1
/* -*- c-basic-offset: 8 -*-
2
rdesktop: A Remote Desktop Protocol client.
3
User interface services - X Window System
4
Copyright (C) Matthew Chapman 1999-2002
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
#include <X11/Xutil.h>
31
extern BOOL g_sendmotion;
32
extern BOOL g_fullscreen;
33
extern BOOL g_grab_keyboard;
34
extern BOOL g_hide_decorations;
35
extern char g_title[];
36
extern int g_server_bpp;
37
extern int g_win_button_size;
40
Time g_last_gesturetime;
41
static int g_x_socket;
42
static Screen *g_screen;
44
BOOL g_enable_compose = False;
46
static BOOL g_gc_initialized = False;
47
static Visual *g_visual;
52
static XModifierKeymap *g_mod_map;
53
static Cursor g_current_cursor;
54
static HCURSOR g_null_cursor;
55
static Atom g_protocol_atom, g_kill_atom;
56
static BOOL g_focused;
57
static BOOL g_mouse_in_wnd;
60
static BOOL g_host_be;
61
static BOOL g_xserver_be;
62
static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
63
static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
65
/* software backing store */
66
static BOOL g_ownbackstore;
67
static Pixmap g_backstore;
68
static BOOL g_backstore_initialized = False;
70
/* Moving in single app mode */
71
static BOOL g_moving_wnd;
72
static int g_move_x_offset = 0;
73
static int g_move_y_offset = 0;
77
extern BOOL g_dsp_busy;
82
#define MWM_HINTS_DECORATIONS (1L << 1)
83
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
103
#define FILL_RECTANGLE(x,y,cx,cy)\
105
XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
106
if (g_ownbackstore) \
107
XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
110
#define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
112
XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
116
BOOL g_owncolmap = False;
117
static Colormap g_xcolmap;
118
static uint32 *g_colmap = NULL;
120
#define TRANSLATE(col) ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
121
#define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
122
#define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
124
static int rop2_map[] = {
127
GXandInverted, /* DPna */
128
GXcopyInverted, /* Pn */
129
GXandReverse, /* PDna */
136
GXorInverted, /* DPno */
138
GXorReverse, /* PDno */
143
#define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
144
#define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
147
mwm_hide_decorations(void)
149
PropMotifWmHints motif_hints;
152
/* setup the property */
153
motif_hints.flags = MWM_HINTS_DECORATIONS;
154
motif_hints.decorations = 0;
156
/* get the atom for the property */
157
hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
160
warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
164
XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,
165
(unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
169
split_colour15(uint32 colour)
172
rv.red = (colour & 0x7c00) >> 10;
173
rv.red = (rv.red * 0xff) / 0x1f;
174
rv.green = (colour & 0x03e0) >> 5;
175
rv.green = (rv.green * 0xff) / 0x1f;
176
rv.blue = (colour & 0x1f);
177
rv.blue = (rv.blue * 0xff) / 0x1f;
182
split_colour16(uint32 colour)
185
rv.red = (colour & 0xf800) >> 11;
186
rv.red = (rv.red * 0xff) / 0x1f;
187
rv.green = (colour & 0x07e0) >> 5;
188
rv.green = (rv.green * 0xff) / 0x3f;
189
rv.blue = (colour & 0x001f);
190
rv.blue = (rv.blue * 0xff) / 0x1f;
195
split_colour24(uint32 colour)
198
rv.blue = (colour & 0xff0000) >> 16;
199
rv.green = (colour & 0xff00) >> 8;
200
rv.red = (colour & 0xff);
205
make_colour(PixelColour pc)
207
return (((pc.red >> g_red_shift_r) << g_red_shift_l)
208
| ((pc.green >> g_green_shift_r) << g_green_shift_l)
209
| ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));
212
#define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
213
#define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
214
#define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
215
x = (x << 16) | (x >> 16); }
218
translate_colour(uint32 colour)
221
switch (g_server_bpp)
224
pc = split_colour15(colour);
227
pc = split_colour16(colour);
230
pc = split_colour24(colour);
233
return make_colour(pc);
237
translate8to8(uint8 * data, uint8 * out, uint8 * end)
240
*(out++) = (uint8) g_colmap[*(data++)];
244
translate8to16(uint8 * data, uint8 * out, uint8 * end)
250
value = (uint16) g_colmap[*(data++)];
254
*(out++) = value >> 8;
260
*(out++) = value >> 8;
265
/* little endian - conversion happens when colourmap is built */
267
translate8to24(uint8 * data, uint8 * out, uint8 * end)
273
value = g_colmap[*(data++)];
277
*(out++) = value >> 16;
278
*(out++) = value >> 8;
284
*(out++) = value >> 8;
285
*(out++) = value >> 16;
291
translate8to32(uint8 * data, uint8 * out, uint8 * end)
297
value = g_colmap[*(data++)];
301
*(out++) = value >> 24;
302
*(out++) = value >> 16;
303
*(out++) = value >> 8;
309
*(out++) = value >> 8;
310
*(out++) = value >> 16;
311
*(out++) = value >> 24;
317
translate15to16(uint16 * data, uint8 * out, uint8 * end)
331
value = make_colour(split_colour15(pixel));
335
*(out++) = value >> 8;
341
*(out++) = value >> 8;
347
translate15to24(uint16 * data, uint8 * out, uint8 * end)
361
value = make_colour(split_colour15(pixel));
364
*(out++) = value >> 16;
365
*(out++) = value >> 8;
371
*(out++) = value >> 8;
372
*(out++) = value >> 16;
378
translate15to32(uint16 * data, uint8 * out, uint8 * end)
392
value = make_colour(split_colour15(pixel));
396
*(out++) = value >> 24;
397
*(out++) = value >> 16;
398
*(out++) = value >> 8;
404
*(out++) = value >> 8;
405
*(out++) = value >> 16;
406
*(out++) = value >> 24;
412
translate16to16(uint16 * data, uint8 * out, uint8 * end)
426
value = make_colour(split_colour16(pixel));
430
*(out++) = value >> 8;
436
*(out++) = value >> 8;
442
translate16to24(uint16 * data, uint8 * out, uint8 * end)
456
value = make_colour(split_colour16(pixel));
460
*(out++) = value >> 16;
461
*(out++) = value >> 8;
467
*(out++) = value >> 8;
468
*(out++) = value >> 16;
474
translate16to32(uint16 * data, uint8 * out, uint8 * end)
488
value = make_colour(split_colour16(pixel));
492
*(out++) = value >> 24;
493
*(out++) = value >> 16;
494
*(out++) = value >> 8;
500
*(out++) = value >> 8;
501
*(out++) = value >> 16;
502
*(out++) = value >> 24;
508
translate24to16(uint8 * data, uint8 * out, uint8 * end)
514
pixel = *(data++) << 16;
515
pixel |= *(data++) << 8;
518
value = (uint16) make_colour(split_colour24(pixel));
522
*(out++) = value >> 8;
528
*(out++) = value >> 8;
534
translate24to24(uint8 * data, uint8 * out, uint8 * end)
541
pixel = *(data++) << 16;
542
pixel |= *(data++) << 8;
545
value = make_colour(split_colour24(pixel));
549
*(out++) = value >> 16;
550
*(out++) = value >> 8;
556
*(out++) = value >> 8;
557
*(out++) = value >> 16;
563
translate24to32(uint8 * data, uint8 * out, uint8 * end)
570
pixel = *(data++) << 16;
571
pixel |= *(data++) << 8;
574
value = make_colour(split_colour24(pixel));
578
*(out++) = value >> 24;
579
*(out++) = value >> 16;
580
*(out++) = value >> 8;
586
*(out++) = value >> 8;
587
*(out++) = value >> 16;
588
*(out++) = value >> 24;
594
translate_image(int width, int height, uint8 * data)
596
int size = width * height * g_bpp / 8;
597
uint8 *out = (uint8 *) xmalloc(size);
598
uint8 *end = out + size;
600
switch (g_server_bpp)
606
translate24to32(data, out, end);
609
translate24to24(data, out, end);
612
translate24to16(data, out, end);
620
translate16to32((uint16 *) data, out, end);
623
translate16to24((uint16 *) data, out, end);
626
translate16to16((uint16 *) data, out, end);
634
translate15to32((uint16 *) data, out, end);
637
translate15to24((uint16 *) data, out, end);
640
translate15to16((uint16 *) data, out, end);
648
translate8to8(data, out, end);
651
translate8to16(data, out, end);
654
translate8to24(data, out, end);
657
translate8to32(data, out, end);
666
get_key_state(unsigned int state, uint32 keysym)
668
int modifierpos, key, keysymMask = 0;
671
KeyCode keycode = XKeysymToKeycode(g_display, keysym);
673
if (keycode == NoSymbol)
676
for (modifierpos = 0; modifierpos < 8; modifierpos++)
678
offset = g_mod_map->max_keypermod * modifierpos;
680
for (key = 0; key < g_mod_map->max_keypermod; key++)
682
if (g_mod_map->modifiermap[offset + key] == keycode)
683
keysymMask |= 1 << modifierpos;
687
return (state & keysymMask) ? True : False;
691
calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
693
*shift_l = ffs(mask) - 1;
695
*shift_r = 8 - ffs(mask & ~(mask >> 1));
702
XPixmapFormatValues *pfm;
704
int i, screen_num, nvisuals;
705
XVisualInfo *vmatches = NULL;
706
XVisualInfo template;
707
Bool TrueColorVisual = False;
709
g_display = XOpenDisplay(NULL);
710
if (g_display == NULL)
712
error("Failed to open display: %s\n", XDisplayName(NULL));
716
screen_num = DefaultScreen(g_display);
717
g_x_socket = ConnectionNumber(g_display);
718
g_screen = ScreenOfDisplay(g_display, screen_num);
719
g_depth = DefaultDepthOfScreen(g_screen);
721
/* Search for best TrueColor depth */
722
template.class = TrueColor;
723
vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);
726
while (nvisuals >= 0)
728
if ((vmatches + nvisuals)->depth > g_depth)
730
g_depth = (vmatches + nvisuals)->depth;
733
TrueColorVisual = True;
736
if ((g_server_bpp == 8) && ((! TrueColorVisual) || (g_depth <= 8)))
738
/* we use a colourmap, so the default visual should do */
739
g_visual = DefaultVisualOfScreen(g_screen);
740
g_depth = DefaultDepthOfScreen(g_screen);
742
/* Do not allocate colours on a TrueColor visual */
743
if (g_visual->class == TrueColor)
750
/* need a truecolour visual */
751
if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))
753
error("The display does not support true colour - high colour support unavailable.\n");
757
g_visual = vi.visual;
759
calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);
760
calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);
761
calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);
764
pfm = XListPixmapFormats(g_display, &i);
767
/* Use maximum bpp for this depth - this is generally
768
desirable, e.g. 24 bits->32 bits. */
771
if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
773
g_bpp = pfm[i].bits_per_pixel;
781
error("Less than 8 bpp not currently supported.\n");
782
XCloseDisplay(g_display);
788
g_xcolmap = XCreateColormap(g_display,RootWindowOfScreen(g_screen),g_visual,AllocNone);
790
warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
793
if (DoesBackingStore(g_screen) != Always)
794
g_ownbackstore = True;
797
g_host_be = !(BOOL) (*(uint8 *) (&test));
798
g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
801
* Determine desktop size
805
g_width = WidthOfScreen(g_screen);
806
g_height = HeightOfScreen(g_screen);
808
else if (g_width < 0)
810
/* Percent of screen */
811
g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
812
g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
814
else if (g_width == 0)
816
/* Fetch geometry from _NET_WORKAREA */
819
if (get_current_workarea(&x, &y, &cx, &cy) == 0)
826
warning("Failed to get workarea: probably your window manager does not support extended hints\n");
832
/* make sure width is a multiple of 4 */
833
g_width = (g_width + 3) & ~3;
835
g_mod_map = XGetModifierMapping(g_display);
839
if (g_enable_compose)
840
g_IM = XOpenIM(g_display, NULL, NULL, NULL);
844
DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));
855
XFreeModifiermap(g_mod_map);
858
XFreePixmap(g_display, g_backstore);
860
XFreeGC(g_display, g_gc);
861
XCloseDisplay(g_display);
866
ui_create_window(void)
868
uint8 null_pointer_mask[1] = { 0x80 };
869
uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };
870
XSetWindowAttributes attribs;
871
XClassHint *classhints;
872
XSizeHints *sizehints;
873
int wndwidth, wndheight;
874
long input_mask, ic_input_mask;
877
wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
878
wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
880
attribs.background_pixel = BlackPixelOfScreen(g_screen);
881
attribs.border_pixel = WhitePixelOfScreen(g_screen);
882
attribs.backing_store = g_ownbackstore ? NotUseful : Always;
883
attribs.override_redirect = g_fullscreen;
884
attribs.colormap = g_xcolmap;
886
g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,
887
0, g_depth, InputOutput, g_visual,
888
CWBackPixel | CWBackingStore | CWOverrideRedirect |
889
CWColormap | CWBorderPixel, &attribs);
891
if ( ! g_gc_initialized )
893
g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
894
g_gc_initialized = True;
897
if ((g_ownbackstore) && (! g_backstore_initialized))
900
XCreatePixmap(g_display, g_wnd, g_width, g_height,
903
/* clear to prevent rubbish being exposed at startup */
904
XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
905
XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
906
g_backstore_initialized = True;
909
XStoreName(g_display, g_wnd, g_title);
911
if (g_hide_decorations)
912
mwm_hide_decorations();
914
classhints = XAllocClassHint();
915
if (classhints != NULL)
917
classhints->res_name = classhints->res_class = "rdesktop";
918
XSetClassHint(g_display, g_wnd, classhints);
922
sizehints = XAllocSizeHints();
925
sizehints->flags = PMinSize | PMaxSize;
926
sizehints->min_width = sizehints->max_width = g_width;
927
sizehints->min_height = sizehints->max_height = g_height;
928
XSetWMNormalHints(g_display, g_wnd, sizehints);
932
input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
933
VisibilityChangeMask | FocusChangeMask;
936
input_mask |= PointerMotionMask;
938
input_mask |= ExposureMask;
939
if (g_fullscreen || g_grab_keyboard)
940
input_mask |= EnterWindowMask;
942
input_mask |= LeaveWindowMask;
946
g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
947
XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
950
&& (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
951
input_mask |= ic_input_mask;
954
XSelectInput(g_display, g_wnd, input_mask);
955
XMapWindow(g_display, g_wnd);
957
/* wait for VisibilityNotify */
960
XMaskEvent(g_display, VisibilityChangeMask, &xevent);
962
while (xevent.type != VisibilityNotify);
965
g_mouse_in_wnd = False;
967
/* handle the WM_DELETE_WINDOW protocol */
968
g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
969
g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
970
XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
972
/* create invisible 1x1 cursor to be used as null cursor */
973
g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
979
ui_destroy_window(void)
984
XDestroyWindow(g_display, g_wnd);
988
xwin_toggle_fullscreen(void)
994
/* need to save contents of window */
995
contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
996
XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1000
g_fullscreen = !g_fullscreen;
1003
XDefineCursor(g_display, g_wnd, g_current_cursor);
1005
if (!g_ownbackstore)
1007
XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1008
XFreePixmap(g_display, contents);
1012
/* Process all events in Xlib queue
1013
Returns 0 after user quit, 1 otherwise */
1015
xwin_process_events(void)
1019
uint16 button, flags;
1025
while (XPending(g_display) > 0)
1027
XNextEvent(g_display, &xevent);
1029
if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1031
DEBUG_KBD(("Filtering event\n"));
1037
switch (xevent.type)
1040
/* the window manager told us to quit */
1041
if ((xevent.xclient.message_type == g_protocol_atom)
1042
&& ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1048
g_last_gesturetime = xevent.xkey.time;
1050
/* Multi_key compatible version */
1052
XmbLookupString(g_IC,
1053
&xevent.xkey, str, sizeof(str), &keysym,
1055
if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1057
error("XmbLookupString failed with status 0x%x\n",
1064
/* Plain old XLookupString */
1065
DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1066
XLookupString((XKeyEvent *) & xevent,
1067
str, sizeof(str), &keysym, NULL);
1070
DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1071
get_ksname(keysym)));
1073
ev_time = time(NULL);
1074
if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1077
tr = xkeymap_translate_key(keysym,
1078
xevent.xkey.keycode, xevent.xkey.state);
1080
if (tr.scancode == 0)
1083
save_remote_modifiers(tr.scancode);
1084
ensure_remote_modifiers(ev_time, tr);
1085
rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1086
restore_remote_modifiers(ev_time, tr.scancode);
1091
g_last_gesturetime = xevent.xkey.time;
1092
XLookupString((XKeyEvent *) & xevent, str,
1093
sizeof(str), &keysym, NULL);
1095
DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1096
get_ksname(keysym)));
1098
ev_time = time(NULL);
1099
if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1102
tr = xkeymap_translate_key(keysym,
1103
xevent.xkey.keycode, xevent.xkey.state);
1105
if (tr.scancode == 0)
1108
rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1112
flags = MOUSE_FLAG_DOWN;
1116
g_last_gesturetime = xevent.xbutton.time;
1117
button = xkeymap_translate_button(xevent.xbutton.button);
1121
/* If win_button_size is nonzero, enable single app mode */
1122
if (xevent.xbutton.y < g_win_button_size)
1124
/* Stop moving window when button is released, regardless of cursor position */
1125
if (g_moving_wnd && (xevent.type == ButtonRelease))
1126
g_moving_wnd = False;
1128
/* Check from right to left: */
1130
if (xevent.xbutton.x >= g_width - g_win_button_size)
1132
/* The close button, continue */
1135
else if (xevent.xbutton.x >=
1136
g_width - g_win_button_size * 2)
1138
/* The maximize/restore button. Do not send to
1139
server. It might be a good idea to change the
1140
cursor or give some other visible indication
1141
that rdesktop inhibited this click */
1144
else if (xevent.xbutton.x >=
1145
g_width - g_win_button_size * 3)
1147
/* The minimize button. Iconify window. */
1148
XIconifyWindow(g_display, g_wnd,
1149
DefaultScreen(g_display));
1152
else if (xevent.xbutton.x <= g_win_button_size)
1154
/* The system menu. Ignore. */
1159
/* The title bar. */
1160
if ((xevent.type == ButtonPress) && !g_fullscreen
1161
&& g_hide_decorations)
1163
g_moving_wnd = True;
1164
g_move_x_offset = xevent.xbutton.x;
1165
g_move_y_offset = xevent.xbutton.y;
1172
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1173
flags | button, xevent.xbutton.x, xevent.xbutton.y);
1179
XMoveWindow(g_display, g_wnd,
1180
xevent.xmotion.x_root - g_move_x_offset,
1181
xevent.xmotion.y_root - g_move_y_offset);
1185
if (g_fullscreen && !g_focused)
1186
XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1188
rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1189
MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1193
if (xevent.xfocus.mode == NotifyGrab)
1196
reset_modifier_keys();
1197
if (g_grab_keyboard && g_mouse_in_wnd)
1198
XGrabKeyboard(g_display, g_wnd, True,
1199
GrabModeAsync, GrabModeAsync, CurrentTime);
1203
if (xevent.xfocus.mode == NotifyUngrab)
1206
if (xevent.xfocus.mode == NotifyWhileGrabbed)
1207
XUngrabKeyboard(g_display, CurrentTime);
1211
/* we only register for this event when in fullscreen mode */
1212
/* or grab_keyboard */
1213
g_mouse_in_wnd = True;
1216
XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1221
XGrabKeyboard(g_display, g_wnd, True,
1222
GrabModeAsync, GrabModeAsync, CurrentTime);
1226
/* we only register for this event when grab_keyboard */
1227
g_mouse_in_wnd = False;
1228
XUngrabKeyboard(g_display, CurrentTime);
1232
XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1233
xevent.xexpose.x, xevent.xexpose.y,
1234
xevent.xexpose.width,
1235
xevent.xexpose.height,
1236
xevent.xexpose.x, xevent.xexpose.y);
1240
/* Refresh keyboard mapping if it has changed. This is important for
1241
Xvnc, since it allocates keycodes dynamically */
1242
if (xevent.xmapping.request == MappingKeyboard
1243
|| xevent.xmapping.request == MappingModifier)
1244
XRefreshKeyboardMapping(&xevent.xmapping);
1246
if (xevent.xmapping.request == MappingModifier)
1248
XFreeModifiermap(g_mod_map);
1249
g_mod_map = XGetModifierMapping(g_display);
1253
/* clipboard stuff */
1254
case SelectionNotify:
1255
xclip_handle_SelectionNotify(&xevent.xselection);
1257
case SelectionRequest:
1258
xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1260
case SelectionClear:
1261
xclip_handle_SelectionClear();
1263
case PropertyNotify:
1264
xclip_handle_PropertyNotify(&xevent.xproperty);
1272
/* Returns 0 after user quit, 1 otherwise */
1274
ui_select(int rdp_socket)
1276
int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1281
/* Process any events already waiting */
1282
if (!xwin_process_events())
1288
FD_SET(rdp_socket, &rfds);
1289
FD_SET(g_x_socket, &rfds);
1292
/* FIXME: there should be an API for registering fds */
1295
FD_SET(g_dsp_fd, &wfds);
1296
n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;
1300
switch (select(n, &rfds, &wfds, NULL, NULL))
1303
error("select: %s\n", strerror(errno));
1309
if (FD_ISSET(rdp_socket, &rfds))
1313
if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1320
ui_move_pointer(int x, int y)
1322
XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1326
ui_create_bitmap(int width, int height, uint8 * data)
1333
if (g_server_bpp == 8)
1345
tdata = (g_owncolmap ? data : translate_image(width, height, data));
1346
bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1347
image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1348
(char *) tdata, width, height, bitmap_pad, 0);
1350
XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1355
return (HBITMAP) bitmap;
1359
ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1365
if (g_server_bpp == 8)
1377
tdata = (g_owncolmap ? data : translate_image(width, height, data));
1378
image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1379
(char *) tdata, width, height, bitmap_pad, 0);
1383
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1384
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1388
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1397
ui_destroy_bitmap(HBITMAP bmp)
1399
XFreePixmap(g_display, (Pixmap) bmp);
1403
ui_create_glyph(int width, int height, uint8 * data)
1410
scanline = (width + 7) / 8;
1412
bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1413
gc = XCreateGC(g_display, bitmap, 0, NULL);
1415
image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1416
width, height, 8, scanline);
1417
image->byte_order = MSBFirst;
1418
image->bitmap_bit_order = MSBFirst;
1421
XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1424
XFreeGC(g_display, gc);
1425
return (HGLYPH) bitmap;
1429
ui_destroy_glyph(HGLYPH glyph)
1431
XFreePixmap(g_display, (Pixmap) glyph);
1435
ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1436
uint8 * andmask, uint8 * xormask)
1438
HGLYPH maskglyph, cursorglyph;
1441
uint8 *cursor, *pcursor;
1442
uint8 *mask, *pmask;
1444
int scanline, offset;
1447
scanline = (width + 7) / 8;
1448
offset = scanline * height;
1450
cursor = (uint8 *) xmalloc(offset);
1451
memset(cursor, 0, offset);
1453
mask = (uint8 *) xmalloc(offset);
1454
memset(mask, 0, offset);
1456
/* approximate AND and XOR masks with a monochrome X pointer */
1457
for (i = 0; i < height; i++)
1460
pcursor = &cursor[offset];
1461
pmask = &mask[offset];
1463
for (j = 0; j < scanline; j++)
1465
for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1467
if (xormask[0] || xormask[1] || xormask[2])
1469
*pcursor |= (~(*andmask) & nextbit);
1474
*pcursor |= ((*andmask) & nextbit);
1475
*pmask |= (~(*andmask) & nextbit);
1487
fg.red = fg.blue = fg.green = 0xffff;
1488
bg.red = bg.blue = bg.green = 0x0000;
1489
fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1491
cursorglyph = ui_create_glyph(width, height, cursor);
1492
maskglyph = ui_create_glyph(width, height, mask);
1495
XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1496
(Pixmap) maskglyph, &fg, &bg, x, y);
1498
ui_destroy_glyph(maskglyph);
1499
ui_destroy_glyph(cursorglyph);
1502
return (HCURSOR) xcursor;
1506
ui_set_cursor(HCURSOR cursor)
1508
g_current_cursor = (Cursor) cursor;
1509
XDefineCursor(g_display, g_wnd, g_current_cursor);
1513
ui_destroy_cursor(HCURSOR cursor)
1515
XFreeCursor(g_display, (Cursor) cursor);
1519
ui_set_null_cursor(void)
1521
ui_set_cursor(g_null_cursor);
1524
#define MAKE_XCOLOR(xc,c) \
1525
(xc)->red = ((c)->red << 8) | (c)->red; \
1526
(xc)->green = ((c)->green << 8) | (c)->green; \
1527
(xc)->blue = ((c)->blue << 8) | (c)->blue; \
1528
(xc)->flags = DoRed | DoGreen | DoBlue;
1532
ui_create_colourmap(COLOURMAP * colours)
1535
int i, ncolours = colours->ncolours;
1538
uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1540
XColor xc_cache[256];
1542
int colLookup = 256;
1543
for (i = 0; i < ncolours; i++)
1545
entry = &colours->colours[i];
1546
MAKE_XCOLOR(&xentry, entry);
1548
if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1550
/* Allocation failed, find closest match. */
1552
int nMinDist = 3 * 256 * 256;
1553
long nDist = nMinDist;
1555
/* only get the colors once */
1558
xc_cache[colLookup].pixel = colLookup;
1559
xc_cache[colLookup].red = xc_cache[colLookup].green =
1560
xc_cache[colLookup].blue = 0;
1561
xc_cache[colLookup].flags = 0;
1562
XQueryColor(g_display,
1563
DefaultColormap(g_display,
1564
DefaultScreen(g_display)),
1565
&xc_cache[colLookup]);
1569
/* approximate the pixel */
1572
if (xc_cache[j].flags)
1574
nDist = ((long) (xc_cache[j].red >> 8) -
1575
(long) (xentry.red >> 8)) *
1576
((long) (xc_cache[j].red >> 8) -
1577
(long) (xentry.red >> 8)) +
1578
((long) (xc_cache[j].green >> 8) -
1579
(long) (xentry.green >> 8)) *
1580
((long) (xc_cache[j].green >> 8) -
1581
(long) (xentry.green >> 8)) +
1582
((long) (xc_cache[j].blue >> 8) -
1583
(long) (xentry.blue >> 8)) *
1584
((long) (xc_cache[j].blue >> 8) -
1585
(long) (xentry.blue >> 8));
1587
if (nDist < nMinDist)
1594
colour = xentry.pixel;
1596
/* update our cache */
1597
if (xentry.pixel < 256)
1599
xc_cache[xentry.pixel].red = xentry.red;
1600
xc_cache[xentry.pixel].green = xentry.green;
1601
xc_cache[xentry.pixel].blue = xentry.blue;
1611
XColor *xcolours, *xentry;
1614
xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1615
for (i = 0; i < ncolours; i++)
1617
entry = &colours->colours[i];
1618
xentry = &xcolours[i];
1620
MAKE_XCOLOR(xentry, entry);
1623
map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1624
XStoreColors(g_display, map, xcolours, ncolours);
1627
return (HCOLOURMAP) map;
1632
ui_destroy_colourmap(HCOLOURMAP map)
1637
XFreeColormap(g_display, (Colormap) map);
1641
ui_set_colourmap(HCOLOURMAP map)
1648
g_colmap = (uint32 *) map;
1651
XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1655
ui_set_clip(int x, int y, int cx, int cy)
1663
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1673
rect.width = g_width;
1674
rect.height = g_height;
1675
XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1681
XBell(g_display, 0);
1685
ui_destblt(uint8 opcode,
1686
/* dest */ int x, int y, int cx, int cy)
1688
SET_FUNCTION(opcode);
1689
FILL_RECTANGLE(x, y, cx, cy);
1690
RESET_FUNCTION(opcode);
1693
static uint8 hatch_patterns[] = {
1694
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1695
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1696
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1697
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1698
0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1699
0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1703
ui_patblt(uint8 opcode,
1704
/* dest */ int x, int y, int cx, int cy,
1705
/* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1708
uint8 i, ipattern[8];
1710
SET_FUNCTION(opcode);
1712
switch (brush->style)
1715
SET_FOREGROUND(fgcolour);
1716
FILL_RECTANGLE(x, y, cx, cy);
1720
fill = (Pixmap) ui_create_glyph(8, 8,
1721
hatch_patterns + brush->pattern[0] * 8);
1722
SET_FOREGROUND(fgcolour);
1723
SET_BACKGROUND(bgcolour);
1724
XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1725
XSetStipple(g_display, g_gc, fill);
1726
XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1727
FILL_RECTANGLE(x, y, cx, cy);
1728
XSetFillStyle(g_display, g_gc, FillSolid);
1729
XSetTSOrigin(g_display, g_gc, 0, 0);
1730
ui_destroy_glyph((HGLYPH) fill);
1733
case 3: /* Pattern */
1734
for (i = 0; i != 8; i++)
1735
ipattern[7 - i] = brush->pattern[i];
1736
fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1738
SET_FOREGROUND(bgcolour);
1739
SET_BACKGROUND(fgcolour);
1740
XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1741
XSetStipple(g_display, g_gc, fill);
1742
XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1744
FILL_RECTANGLE(x, y, cx, cy);
1746
XSetFillStyle(g_display, g_gc, FillSolid);
1747
XSetTSOrigin(g_display, g_gc, 0, 0);
1748
ui_destroy_glyph((HGLYPH) fill);
1752
unimpl("brush %d\n", brush->style);
1755
RESET_FUNCTION(opcode);
1759
ui_screenblt(uint8 opcode,
1760
/* dest */ int x, int y, int cx, int cy,
1761
/* src */ int srcx, int srcy)
1763
SET_FUNCTION(opcode);
1764
XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1766
XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1767
RESET_FUNCTION(opcode);
1771
ui_memblt(uint8 opcode,
1772
/* dest */ int x, int y, int cx, int cy,
1773
/* src */ HBITMAP src, int srcx, int srcy)
1775
SET_FUNCTION(opcode);
1776
XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1778
XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1779
RESET_FUNCTION(opcode);
1783
ui_triblt(uint8 opcode,
1784
/* dest */ int x, int y, int cx, int cy,
1785
/* src */ HBITMAP src, int srcx, int srcy,
1786
/* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1788
/* This is potentially difficult to do in general. Until someone
1789
comes up with a more efficient way of doing it I am using cases. */
1793
case 0x69: /* PDSxxn */
1794
ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1795
ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1798
case 0xb8: /* PSDPxax */
1799
ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1800
ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1801
ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1804
case 0xc0: /* PSa */
1805
ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1806
ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1810
unimpl("triblt 0x%x\n", opcode);
1811
ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1816
ui_line(uint8 opcode,
1817
/* dest */ int startx, int starty, int endx, int endy,
1818
/* pen */ PEN * pen)
1820
SET_FUNCTION(opcode);
1821
SET_FOREGROUND(pen->colour);
1822
XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1824
XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1825
RESET_FUNCTION(opcode);
1830
/* dest */ int x, int y, int cx, int cy,
1831
/* brush */ int colour)
1833
SET_FOREGROUND(colour);
1834
FILL_RECTANGLE(x, y, cx, cy);
1837
/* warning, this function only draws on wnd or backstore, not both */
1839
ui_draw_glyph(int mixmode,
1840
/* dest */ int x, int y, int cx, int cy,
1841
/* src */ HGLYPH glyph, int srcx, int srcy,
1842
int bgcolour, int fgcolour)
1844
SET_FOREGROUND(fgcolour);
1845
SET_BACKGROUND(bgcolour);
1847
XSetFillStyle(g_display, g_gc,
1848
(mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1849
XSetStipple(g_display, g_gc, (Pixmap) glyph);
1850
XSetTSOrigin(g_display, g_gc, x, y);
1852
FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1854
XSetFillStyle(g_display, g_gc, FillSolid);
1857
#define DO_GLYPH(ttext,idx) \
1859
glyph = cache_get_font (font, ttext[idx]);\
1860
if (!(flags & TEXT2_IMPLICIT_X))\
1862
xyoffset = ttext[++idx];\
1863
if ((xyoffset & 0x80))\
1865
if (flags & TEXT2_VERTICAL)\
1866
y += ttext[idx+1] | (ttext[idx+2] << 8);\
1868
x += ttext[idx+1] | (ttext[idx+2] << 8);\
1873
if (flags & TEXT2_VERTICAL)\
1881
x1 = x + glyph->offset;\
1882
y1 = y + glyph->baseline;\
1883
XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
1884
XSetTSOrigin(g_display, g_gc, x1, y1);\
1885
FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
1886
if (flags & TEXT2_IMPLICIT_X)\
1892
ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1893
int clipx, int clipy, int clipcx, int clipcy,
1894
int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1895
int fgcolour, uint8 * text, uint8 length)
1898
int i, j, xyoffset, x1, y1;
1901
SET_FOREGROUND(bgcolour);
1905
FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1907
else if (mixmode == MIX_OPAQUE)
1909
FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1912
SET_FOREGROUND(fgcolour);
1913
SET_BACKGROUND(bgcolour);
1914
XSetFillStyle(g_display, g_gc, FillStippled);
1916
/* Paint text, character by character */
1917
for (i = 0; i < length;)
1923
cache_put_text(text[i + 1], text, text[i + 2]);
1926
error("this shouldn't be happening\n");
1929
/* this will move pointer from start to first character after FF command */
1931
text = &(text[i + 3]);
1936
entry = cache_get_text(text[i + 1]);
1939
if ((((uint8 *) (entry->data))[1] ==
1940
0) && (!(flags & TEXT2_IMPLICIT_X)))
1942
if (flags & TEXT2_VERTICAL)
1947
for (j = 0; j < entry->size; j++)
1948
DO_GLYPH(((uint8 *) (entry->data)), j);
1955
/* this will move pointer from start to first character after FE command */
1967
XSetFillStyle(g_display, g_gc, FillSolid);
1972
XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1973
boxy, boxcx, boxcy, boxx, boxy);
1975
XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1976
clipy, clipcx, clipcy, clipx, clipy);
1981
ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1988
image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1992
pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1993
XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1994
image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1995
XFreePixmap(g_display, pix);
1998
offset *= g_bpp / 8;
1999
cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2001
XDestroyImage(image);
2005
ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2010
offset *= g_bpp / 8;
2011
data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2015
image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2016
(char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2020
XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2021
XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2025
XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);