/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1199 - (hide annotations)
Mon Mar 27 08:17:34 2006 UTC (18 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 83694 byte(s)
Added SeamlessRDP support: Merged seamlessrdp-branch

1 forsberg 415 /* -*- c-basic-offset: 8 -*-
2 matty 6 rdesktop: A Remote Desktop Protocol client.
3 matthewc 38 User interface services - X Window System
4 stargo 828 Copyright (C) Matthew Chapman 1999-2005
5 n-ki 52
6 matty 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.
10 n-ki 52
11 matty 6 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.
15 n-ki 52
16 matty 6 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.
19     */
20    
21 matty 10 #include <X11/Xlib.h>
22 matty 28 #include <X11/Xutil.h>
23 matthewc 537 #include <unistd.h>
24 stargo 609 #include <sys/time.h>
25 matty 10 #include <time.h>
26 matty 33 #include <errno.h>
27 stargo 603 #include <strings.h>
28 matty 10 #include "rdesktop.h"
29 forsberg 415 #include "xproto.h"
30 matty 6
31 astrand 1199 /* We can't include Xproto.h because of conflicting defines for BOOL */
32     #define X_ConfigureWindow 12
33    
34 jsorg71 447 extern int g_width;
35     extern int g_height;
36 stargo 800 extern int g_xpos;
37     extern int g_ypos;
38 stargo 867 extern int g_pos;
39 jsorg71 447 extern BOOL g_sendmotion;
40     extern BOOL g_fullscreen;
41 jsorg71 450 extern BOOL g_grab_keyboard;
42     extern BOOL g_hide_decorations;
43     extern char g_title[];
44 astrand 1042 /* Color depth of the RDP session.
45     As of RDP 5.1, it may be 8, 15, 16 or 24. */
46     extern int g_server_depth;
47 jsorg71 450 extern int g_win_button_size;
48 matty 10
49 jsorg71 450 Display *g_display;
50     Time g_last_gesturetime;
51     static int g_x_socket;
52     static Screen *g_screen;
53     Window g_wnd;
54 astrand 1199
55     /* SeamlessRDP support */
56     typedef struct _seamless_group
57     {
58     Window wnd;
59     unsigned long id;
60     unsigned int refcnt;
61     } seamless_group;
62     typedef struct _seamless_window
63     {
64     Window wnd;
65     unsigned long id;
66     unsigned long behind;
67     seamless_group *group;
68     int xoffset, yoffset;
69     int width, height;
70     int state; /* normal/minimized/maximized. */
71     unsigned int desktop;
72     struct timeval *position_timer;
73    
74     BOOL outstanding_position;
75     unsigned int outpos_serial;
76     int outpos_xoffset, outpos_yoffset;
77     int outpos_width, outpos_height;
78    
79     struct _seamless_window *next;
80     } seamless_window;
81     static seamless_window *g_seamless_windows = NULL;
82     static unsigned long g_seamless_focused = 0;
83     static BOOL g_seamless_started = False; /* Server end is up and running */
84     static BOOL g_seamless_active = False; /* We are currently in seamless mode */
85     static BOOL g_seamless_hidden = False; /* Desktop is hidden on server */
86     extern BOOL g_seamless_rdp;
87    
88 stargo 648 extern uint32 g_embed_wnd;
89 matthewc 481 BOOL g_enable_compose = False;
90 astrand 691 BOOL g_Unobscured; /* used for screenblt */
91 stargo 576 static GC g_gc = NULL;
92 jsorg71 725 static GC g_create_bitmap_gc = NULL;
93     static GC g_create_glyph_gc = NULL;
94 astrand 1199 static XRectangle g_clip_rectangle;
95 jsorg71 450 static Visual *g_visual;
96 astrand 1042 /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
97     This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
98     as far as we're concerned. */
99 jsorg71 450 static int g_depth;
100 astrand 1042 /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
101     This may be larger than g_depth, in which case some of the bits would
102     be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
103 jsorg71 450 static int g_bpp;
104     static XIM g_IM;
105     static XIC g_IC;
106     static XModifierKeymap *g_mod_map;
107     static Cursor g_current_cursor;
108 stargo 576 static HCURSOR g_null_cursor = NULL;
109 jsorg71 450 static Atom g_protocol_atom, g_kill_atom;
110 astrand 1199 extern Atom g_net_wm_state_atom;
111     extern Atom g_net_wm_desktop_atom;
112 matthewc 481 static BOOL g_focused;
113     static BOOL g_mouse_in_wnd;
114 astrand 1049 /* Indicates that:
115     1) visual has 15, 16 or 24 depth and the same color channel masks
116     as its RDP equivalent (implies X server is LE),
117     2) host is LE
118     This will trigger an optimization whose real value is questionable.
119     */
120     static BOOL g_compatible_arch;
121 astrand 1042 /* Indicates whether RDP's bitmaps and our XImages have the same
122     binary format. If so, we can avoid an expensive translation.
123 astrand 1049 Note that this can be true when g_compatible_arch is false,
124     e.g.:
125    
126     RDP(LE) <-> host(BE) <-> X-Server(LE)
127    
128     ('host' is the machine running rdesktop; the host simply memcpy's
129     so its endianess doesn't matter)
130     */
131 astrand 1042 static BOOL g_no_translate_image = False;
132 matty 29
133 matty 33 /* endianness */
134 jsorg71 450 static BOOL g_host_be;
135     static BOOL g_xserver_be;
136 matthewc 527 static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
137     static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
138 matty 33
139     /* software backing store */
140 stargo 648 extern BOOL g_ownbackstore;
141 stargo 603 static Pixmap g_backstore = 0;
142 matty 31
143 astrand 342 /* Moving in single app mode */
144 jsorg71 450 static BOOL g_moving_wnd;
145     static int g_move_x_offset = 0;
146     static int g_move_y_offset = 0;
147 astrand 991 static BOOL g_using_full_workarea = False;
148 astrand 342
149 matthewc 474 #ifdef WITH_RDPSND
150     extern int g_dsp_fd;
151     extern BOOL g_dsp_busy;
152 stargo 501 extern BOOL g_rdpsnd;
153 matthewc 474 #endif
154    
155 astrand 262 /* MWM decorations */
156     #define MWM_HINTS_DECORATIONS (1L << 1)
157     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
158     typedef struct
159     {
160 astrand 1033 unsigned long flags;
161     unsigned long functions;
162     unsigned long decorations;
163     long inputMode;
164     unsigned long status;
165 astrand 262 }
166     PropMotifWmHints;
167    
168 jsorg71 316 typedef struct
169     {
170     uint32 red;
171     uint32 green;
172     uint32 blue;
173     }
174     PixelColour;
175 astrand 262
176 astrand 1199 #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
177     do { \
178     seamless_window *sw; \
179     XRectangle rect; \
180     if (!g_seamless_windows) break; \
181     for (sw = g_seamless_windows; sw; sw = sw->next) { \
182     rect.x = g_clip_rectangle.x - sw->xoffset; \
183     rect.y = g_clip_rectangle.y - sw->yoffset; \
184     rect.width = g_clip_rectangle.width; \
185     rect.height = g_clip_rectangle.height; \
186     XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
187     func args; \
188     } \
189     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
190     } while (0)
191 forsberg 415
192 astrand 1199 static void
193     seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
194     {
195     points[0].x -= xoffset;
196     points[0].y -= yoffset;
197     XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
198     points[0].x += xoffset;
199     points[0].y += yoffset;
200     }
201    
202     static void
203     seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
204     {
205     points[0].x -= xoffset;
206     points[0].y -= yoffset;
207     XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
208     points[0].x += xoffset;
209     points[0].y += yoffset;
210     }
211    
212 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
213     { \
214 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
215 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
216 jsorg71 450 if (g_ownbackstore) \
217     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
218 matty 31 }
219    
220 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
221 jsorg71 281 { \
222 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
223 jsorg71 281 }
224    
225 jdmeijer 831 #define FILL_POLYGON(p,np)\
226     { \
227     XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
228     if (g_ownbackstore) \
229     XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
230 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
231 jdmeijer 831 }
232    
233     #define DRAW_ELLIPSE(x,y,cx,cy,m)\
234     { \
235     switch (m) \
236     { \
237     case 0: /* Outline */ \
238     XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
239 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
240 jdmeijer 831 if (g_ownbackstore) \
241     XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
242     break; \
243     case 1: /* Filled */ \
244 jsorg71 1022 XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
245 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, \
246     x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
247 jdmeijer 831 if (g_ownbackstore) \
248 jsorg71 1022 XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
249 jdmeijer 831 break; \
250     } \
251     }
252    
253 matty 33 /* colour maps */
254 stargo 648 extern BOOL g_owncolmap;
255 jsorg71 450 static Colormap g_xcolmap;
256     static uint32 *g_colmap = NULL;
257 matty 10
258 astrand 1042 #define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
259 jsorg71 450 #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
260     #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
261 matty 28
262     static int rop2_map[] = {
263     GXclear, /* 0 */
264     GXnor, /* DPon */
265     GXandInverted, /* DPna */
266     GXcopyInverted, /* Pn */
267     GXandReverse, /* PDna */
268     GXinvert, /* Dn */
269     GXxor, /* DPx */
270     GXnand, /* DPan */
271     GXand, /* DPa */
272     GXequiv, /* DPxn */
273     GXnoop, /* D */
274     GXorInverted, /* DPno */
275     GXcopy, /* P */
276     GXorReverse, /* PDno */
277     GXor, /* DPo */
278     GXset /* 1 */
279     };
280    
281 jsorg71 450 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
282     #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
283 matty 29
284 astrand 1199 static seamless_window *
285     sw_get_window_by_id(unsigned long id)
286     {
287     seamless_window *sw;
288     for (sw = g_seamless_windows; sw; sw = sw->next)
289     {
290     if (sw->id == id)
291     return sw;
292     }
293     return NULL;
294     }
295    
296    
297     static seamless_window *
298     sw_get_window_by_wnd(Window wnd)
299     {
300     seamless_window *sw;
301     for (sw = g_seamless_windows; sw; sw = sw->next)
302     {
303     if (sw->wnd == wnd)
304     return sw;
305     }
306     return NULL;
307     }
308    
309    
310 astrand 319 static void
311 astrand 1199 sw_remove_window(seamless_window * win)
312 astrand 262 {
313 astrand 1199 seamless_window *sw, **prevnext = &g_seamless_windows;
314     for (sw = g_seamless_windows; sw; sw = sw->next)
315     {
316     if (sw == win)
317     {
318     *prevnext = sw->next;
319     sw->group->refcnt--;
320     if (sw->group->refcnt == 0)
321     {
322     XDestroyWindow(g_display, sw->group->wnd);
323     xfree(sw->group);
324     }
325     xfree(sw->position_timer);
326     xfree(sw);
327     return;
328     }
329     prevnext = &sw->next;
330     }
331     return;
332     }
333    
334    
335     /* Move all windows except wnd to new desktop */
336     static void
337     sw_all_to_desktop(Window wnd, unsigned int desktop)
338     {
339     seamless_window *sw;
340     for (sw = g_seamless_windows; sw; sw = sw->next)
341     {
342     if (sw->wnd == wnd)
343     continue;
344     if (sw->desktop != desktop)
345     {
346     ewmh_move_to_desktop(sw->wnd, desktop);
347     sw->desktop = desktop;
348     }
349     }
350     }
351    
352    
353     /* Send our position */
354     static void
355     sw_update_position(seamless_window * sw)
356     {
357     XWindowAttributes wa;
358     int x, y;
359     Window child_return;
360     unsigned int serial;
361    
362     XGetWindowAttributes(g_display, sw->wnd, &wa);
363     XTranslateCoordinates(g_display, sw->wnd, wa.root,
364     -wa.border_width, -wa.border_width, &x, &y, &child_return);
365    
366     serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
367    
368     sw->outstanding_position = True;
369     sw->outpos_serial = serial;
370    
371     sw->outpos_xoffset = x;
372     sw->outpos_yoffset = y;
373     sw->outpos_width = wa.width;
374     sw->outpos_height = wa.height;
375     }
376    
377    
378     /* Check if it's time to send our position */
379     static void
380     sw_check_timers()
381     {
382     seamless_window *sw;
383     struct timeval now;
384    
385     gettimeofday(&now, NULL);
386     for (sw = g_seamless_windows; sw; sw = sw->next)
387     {
388     if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
389     {
390     timerclear(sw->position_timer);
391     sw_update_position(sw);
392     }
393     }
394     }
395    
396    
397     static void
398     sw_restack_window(seamless_window * sw, unsigned long behind)
399     {
400     seamless_window *sw_above;
401    
402     /* Remove window from stack */
403     for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
404     {
405     if (sw_above->behind == sw->id)
406     break;
407     }
408    
409     if (sw_above)
410     sw_above->behind = sw->behind;
411    
412     /* And then add it at the new position */
413     for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
414     {
415     if (sw_above->behind == behind)
416     break;
417     }
418    
419     if (sw_above)
420     sw_above->behind = sw->id;
421    
422     sw->behind = behind;
423     }
424    
425    
426     static void
427     sw_handle_restack(seamless_window * sw)
428     {
429     Status status;
430     Window root, parent, *children;
431     unsigned int nchildren, i;
432     seamless_window *sw_below;
433    
434     status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
435     &root, &parent, &children, &nchildren);
436     if (!status || !nchildren)
437     return;
438    
439     sw_below = NULL;
440    
441     i = 0;
442     while (children[i] != sw->wnd)
443     {
444     i++;
445     if (i >= nchildren)
446     goto end;
447     }
448    
449     for (i++; i < nchildren; i++)
450     {
451     sw_below = sw_get_window_by_wnd(children[i]);
452     if (sw_below)
453     break;
454     }
455    
456     if (!sw_below && !sw->behind)
457     goto end;
458     if (sw_below && (sw_below->id == sw->behind))
459     goto end;
460    
461     if (sw_below)
462     {
463     seamless_send_zchange(sw->id, sw_below->id, 0);
464     sw_restack_window(sw, sw_below->id);
465     }
466     else
467     {
468     seamless_send_zchange(sw->id, 0, 0);
469     sw_restack_window(sw, 0);
470     }
471    
472     end:
473     XFree(children);
474     }
475    
476    
477     static seamless_group *
478     sw_find_group(unsigned long id, BOOL dont_create)
479     {
480     seamless_window *sw;
481     seamless_group *sg;
482     XSetWindowAttributes attribs;
483    
484     for (sw = g_seamless_windows; sw; sw = sw->next)
485     {
486     if (sw->group->id == id)
487     return sw->group;
488     }
489    
490     if (dont_create)
491     return NULL;
492    
493     sg = xmalloc(sizeof(seamless_group));
494    
495     sg->wnd =
496     XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
497     CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
498    
499     sg->id = id;
500     sg->refcnt = 0;
501    
502     return sg;
503     }
504    
505    
506     static void
507     mwm_hide_decorations(Window wnd)
508     {
509 astrand 262 PropMotifWmHints motif_hints;
510     Atom hintsatom;
511    
512     /* setup the property */
513     motif_hints.flags = MWM_HINTS_DECORATIONS;
514     motif_hints.decorations = 0;
515    
516     /* get the atom for the property */
517 jsorg71 450 hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
518 astrand 262 if (!hintsatom)
519     {
520 matthewc 297 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
521 astrand 262 return;
522     }
523    
524 astrand 1199 XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
525 astrand 262 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
526 astrand 1199
527 astrand 262 }
528    
529 jdmeijer 821 #define SPLITCOLOUR15(colour, rv) \
530     { \
531     rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
532     rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
533     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
534 jsorg71 311 }
535    
536 jdmeijer 821 #define SPLITCOLOUR16(colour, rv) \
537     { \
538     rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
539     rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
540     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
541     } \
542 jsorg71 311
543 jdmeijer 821 #define SPLITCOLOUR24(colour, rv) \
544     { \
545     rv.blue = (colour & 0xff0000) >> 16; \
546     rv.green = (colour & 0x00ff00) >> 8; \
547     rv.red = (colour & 0x0000ff); \
548 jsorg71 311 }
549    
550 jdmeijer 821 #define MAKECOLOUR(pc) \
551     ((pc.red >> g_red_shift_r) << g_red_shift_l) \
552     | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
553     | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
554 jsorg71 316
555 jsorg71 311 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
556 stargo 534 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
557 jsorg71 311 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
558     x = (x << 16) | (x >> 16); }
559    
560 astrand 1049 /* The following macros output the same octet sequences
561     on both BE and LE hosts: */
562    
563 jdmeijer 821 #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
564     #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
565     #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
566     #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
567     #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
568     #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
569    
570 jsorg71 311 static uint32
571     translate_colour(uint32 colour)
572     {
573 matthewc 527 PixelColour pc;
574 astrand 1042 switch (g_server_depth)
575 jsorg71 311 {
576 jsorg71 316 case 15:
577 jdmeijer 821 SPLITCOLOUR15(colour, pc);
578 jsorg71 316 break;
579 jsorg71 311 case 16:
580 jdmeijer 821 SPLITCOLOUR16(colour, pc);
581 jsorg71 311 break;
582     case 24:
583 jdmeijer 821 SPLITCOLOUR24(colour, pc);
584 jsorg71 311 break;
585 astrand 1042 default:
586     /* Avoid warning */
587     pc.red = 0;
588     pc.green = 0;
589     pc.blue = 0;
590     break;
591 jsorg71 311 }
592 jdmeijer 821 return MAKECOLOUR(pc);
593 jsorg71 311 }
594    
595 jsorg71 709 /* indent is confused by UNROLL8 */
596     /* *INDENT-OFF* */
597    
598     /* repeat and unroll, similar to bitmap.c */
599     /* potentialy any of the following translate */
600     /* functions can use repeat but just doing */
601     /* the most common ones */
602    
603 jsorg71 679 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
604 jsorg71 709 /* 2 byte output repeat */
605     #define REPEAT2(stm) \
606 jsorg71 679 { \
607 jsorg71 709 while (out <= end - 8 * 2) \
608     UNROLL8(stm) \
609     while (out < end) \
610     { stm } \
611     }
612 jdmeijer 821 /* 3 byte output repeat */
613     #define REPEAT3(stm) \
614     { \
615     while (out <= end - 8 * 3) \
616     UNROLL8(stm) \
617     while (out < end) \
618     { stm } \
619     }
620 jsorg71 709 /* 4 byte output repeat */
621     #define REPEAT4(stm) \
622     { \
623 jsorg71 679 while (out <= end - 8 * 4) \
624     UNROLL8(stm) \
625     while (out < end) \
626     { stm } \
627     }
628 jdmeijer 821 /* *INDENT-ON* */
629 jsorg71 679
630 matty 28 static void
631 jdmeijer 821 translate8to8(const uint8 * data, uint8 * out, uint8 * end)
632 matty 28 {
633 matty 29 while (out < end)
634 jsorg71 450 *(out++) = (uint8) g_colmap[*(data++)];
635 matty 29 }
636 matty 28
637 matty 29 static void
638 jdmeijer 821 translate8to16(const uint8 * data, uint8 * out, uint8 * end)
639 matty 29 {
640 stargo 521 uint16 value;
641    
642 astrand 1049 if (g_compatible_arch)
643 stargo 521 {
644 jdmeijer 821 /* *INDENT-OFF* */
645 jsorg71 709 REPEAT2
646     (
647     *((uint16 *) out) = g_colmap[*(data++)];
648     out += 2;
649     )
650 jdmeijer 821 /* *INDENT-ON* */
651 jsorg71 643 }
652 jsorg71 709 else if (g_xserver_be)
653 jsorg71 643 {
654 jsorg71 709 while (out < end)
655     {
656     value = (uint16) g_colmap[*(data++)];
657 jdmeijer 821 BOUT16(out, value);
658 jsorg71 709 }
659 stargo 521 }
660 jsorg71 709 else
661     {
662     while (out < end)
663     {
664     value = (uint16) g_colmap[*(data++)];
665 jdmeijer 821 LOUT16(out, value);
666 jsorg71 709 }
667     }
668 matty 29 }
669    
670 jsorg71 316 /* little endian - conversion happens when colourmap is built */
671 jsorg71 311 static void
672 jdmeijer 821 translate8to24(const uint8 * data, uint8 * out, uint8 * end)
673 jsorg71 311 {
674 jsorg71 316 uint32 value;
675    
676 astrand 1049 if (g_compatible_arch)
677 jsorg71 316 {
678 jsorg71 643 while (out < end)
679 stargo 521 {
680 jsorg71 643 value = g_colmap[*(data++)];
681 jdmeijer 821 BOUT24(out, value);
682 stargo 521 }
683 jsorg71 643 }
684     else
685     {
686     while (out < end)
687 stargo 521 {
688 jsorg71 643 value = g_colmap[*(data++)];
689 jdmeijer 821 LOUT24(out, value);
690 stargo 521 }
691 jsorg71 316 }
692 jsorg71 311 }
693    
694 matty 29 static void
695 jdmeijer 821 translate8to32(const uint8 * data, uint8 * out, uint8 * end)
696 matty 29 {
697 stargo 521 uint32 value;
698    
699 astrand 1049 if (g_compatible_arch)
700 stargo 521 {
701 jdmeijer 821 /* *INDENT-OFF* */
702 jsorg71 709 REPEAT4
703     (
704     *((uint32 *) out) = g_colmap[*(data++)];
705     out += 4;
706     )
707 jdmeijer 821 /* *INDENT-ON* */
708 jsorg71 643 }
709 jsorg71 709 else if (g_xserver_be)
710 jsorg71 643 {
711 jsorg71 709 while (out < end)
712     {
713     value = g_colmap[*(data++)];
714 jdmeijer 821 BOUT32(out, value);
715 jsorg71 709 }
716 stargo 521 }
717 jsorg71 709 else
718     {
719     while (out < end)
720     {
721     value = g_colmap[*(data++)];
722 jdmeijer 821 LOUT32(out, value);
723 jsorg71 709 }
724     }
725 jsorg71 316 }
726    
727     static void
728 jdmeijer 821 translate15to16(const uint16 * data, uint8 * out, uint8 * end)
729 jsorg71 316 {
730 jsorg71 483 uint16 pixel;
731     uint16 value;
732 jdmeijer 821 PixelColour pc;
733 jsorg71 483
734 jdmeijer 821 if (g_xserver_be)
735 jsorg71 483 {
736 jdmeijer 821 while (out < end)
737 jsorg71 483 {
738 jdmeijer 821 pixel = *(data++);
739     if (g_host_be)
740     {
741     BSWAP16(pixel);
742     }
743     SPLITCOLOUR15(pixel, pc);
744     value = MAKECOLOUR(pc);
745     BOUT16(out, value);
746 stargo 521 }
747 jdmeijer 821 }
748     else
749     {
750     while (out < end)
751 jsorg71 483 {
752 jdmeijer 821 pixel = *(data++);
753     if (g_host_be)
754     {
755     BSWAP16(pixel);
756     }
757     SPLITCOLOUR15(pixel, pc);
758     value = MAKECOLOUR(pc);
759     LOUT16(out, value);
760 jsorg71 483 }
761     }
762 jsorg71 316 }
763    
764     static void
765 jdmeijer 821 translate15to24(const uint16 * data, uint8 * out, uint8 * end)
766 jsorg71 316 {
767 matty 29 uint32 value;
768 jsorg71 483 uint16 pixel;
769 jdmeijer 821 PixelColour pc;
770 matty 29
771 astrand 1049 if (g_compatible_arch)
772 matty 28 {
773 jdmeijer 821 /* *INDENT-OFF* */
774     REPEAT3
775     (
776     pixel = *(data++);
777     SPLITCOLOUR15(pixel, pc);
778     *(out++) = pc.blue;
779     *(out++) = pc.green;
780     *(out++) = pc.red;
781     )
782     /* *INDENT-ON* */
783     }
784     else if (g_xserver_be)
785     {
786     while (out < end)
787 jsorg71 483 {
788 jdmeijer 821 pixel = *(data++);
789     if (g_host_be)
790     {
791     BSWAP16(pixel);
792     }
793     SPLITCOLOUR15(pixel, pc);
794     value = MAKECOLOUR(pc);
795     BOUT24(out, value);
796 stargo 521 }
797 jdmeijer 821 }
798     else
799     {
800     while (out < end)
801 jsorg71 483 {
802 jdmeijer 821 pixel = *(data++);
803     if (g_host_be)
804     {
805     BSWAP16(pixel);
806     }
807     SPLITCOLOUR15(pixel, pc);
808     value = MAKECOLOUR(pc);
809     LOUT24(out, value);
810 jsorg71 483 }
811 matty 28 }
812     }
813    
814     static void
815 jdmeijer 821 translate15to32(const uint16 * data, uint8 * out, uint8 * end)
816 jsorg71 316 {
817 jsorg71 472 uint16 pixel;
818 jsorg71 483 uint32 value;
819 jdmeijer 821 PixelColour pc;
820 jsorg71 472
821 astrand 1049 if (g_compatible_arch)
822 jsorg71 472 {
823 jdmeijer 821 /* *INDENT-OFF* */
824     REPEAT4
825     (
826     pixel = *(data++);
827     SPLITCOLOUR15(pixel, pc);
828     *(out++) = pc.blue;
829     *(out++) = pc.green;
830     *(out++) = pc.red;
831     *(out++) = 0;
832     )
833     /* *INDENT-ON* */
834     }
835     else if (g_xserver_be)
836     {
837     while (out < end)
838 jsorg71 472 {
839 jdmeijer 821 pixel = *(data++);
840     if (g_host_be)
841     {
842     BSWAP16(pixel);
843     }
844     SPLITCOLOUR15(pixel, pc);
845     value = MAKECOLOUR(pc);
846     BOUT32(out, value);
847 jsorg71 472 }
848 jdmeijer 821 }
849     else
850     {
851     while (out < end)
852 jsorg71 483 {
853 jdmeijer 821 pixel = *(data++);
854     if (g_host_be)
855     {
856     BSWAP16(pixel);
857     }
858     SPLITCOLOUR15(pixel, pc);
859     value = MAKECOLOUR(pc);
860     LOUT32(out, value);
861 jsorg71 483 }
862 jsorg71 472 }
863 jsorg71 316 }
864    
865     static void
866 jdmeijer 821 translate16to16(const uint16 * data, uint8 * out, uint8 * end)
867 jsorg71 316 {
868 matthewc 528 uint16 pixel;
869 jsorg71 483 uint16 value;
870 jdmeijer 821 PixelColour pc;
871 jsorg71 483
872 jdmeijer 821 if (g_xserver_be)
873 jsorg71 483 {
874 matthewc 528 if (g_host_be)
875 jsorg71 483 {
876 jdmeijer 821 while (out < end)
877     {
878     pixel = *(data++);
879     BSWAP16(pixel);
880     SPLITCOLOUR16(pixel, pc);
881     value = MAKECOLOUR(pc);
882     BOUT16(out, value);
883     }
884 jsorg71 483 }
885 jdmeijer 821 else
886 jsorg71 483 {
887 jdmeijer 821 while (out < end)
888     {
889     pixel = *(data++);
890     SPLITCOLOUR16(pixel, pc);
891     value = MAKECOLOUR(pc);
892     BOUT16(out, value);
893     }
894 jsorg71 483 }
895 jdmeijer 821 }
896     else
897     {
898     if (g_host_be)
899     {
900     while (out < end)
901     {
902     pixel = *(data++);
903     BSWAP16(pixel);
904     SPLITCOLOUR16(pixel, pc);
905     value = MAKECOLOUR(pc);
906     LOUT16(out, value);
907     }
908     }
909 matthewc 528 else
910     {
911 jdmeijer 821 while (out < end)
912     {
913     pixel = *(data++);
914     SPLITCOLOUR16(pixel, pc);
915     value = MAKECOLOUR(pc);
916     LOUT16(out, value);
917     }
918 matthewc 528 }
919 jsorg71 483 }
920 jsorg71 316 }
921    
922     static void
923 jdmeijer 821 translate16to24(const uint16 * data, uint8 * out, uint8 * end)
924 matty 28 {
925 jsorg71 311 uint32 value;
926 jsorg71 483 uint16 pixel;
927 jdmeijer 821 PixelColour pc;
928 jsorg71 311
929 astrand 1049 if (g_compatible_arch)
930 jsorg71 311 {
931 jdmeijer 821 /* *INDENT-OFF* */
932     REPEAT3
933     (
934     pixel = *(data++);
935     SPLITCOLOUR16(pixel, pc);
936     *(out++) = pc.blue;
937     *(out++) = pc.green;
938     *(out++) = pc.red;
939     )
940     /* *INDENT-ON* */
941     }
942     else if (g_xserver_be)
943     {
944 jsorg71 483 if (g_host_be)
945     {
946 jdmeijer 821 while (out < end)
947     {
948     pixel = *(data++);
949     BSWAP16(pixel);
950     SPLITCOLOUR16(pixel, pc);
951     value = MAKECOLOUR(pc);
952     BOUT24(out, value);
953     }
954 stargo 521 }
955 jdmeijer 821 else
956 jsorg71 483 {
957 jdmeijer 821 while (out < end)
958     {
959     pixel = *(data++);
960     SPLITCOLOUR16(pixel, pc);
961     value = MAKECOLOUR(pc);
962     BOUT24(out, value);
963     }
964 jsorg71 483 }
965 jdmeijer 821 }
966     else
967     {
968     if (g_host_be)
969     {
970     while (out < end)
971     {
972     pixel = *(data++);
973     BSWAP16(pixel);
974     SPLITCOLOUR16(pixel, pc);
975     value = MAKECOLOUR(pc);
976     LOUT24(out, value);
977     }
978     }
979 jsorg71 483 else
980     {
981 jdmeijer 821 while (out < end)
982     {
983     pixel = *(data++);
984     SPLITCOLOUR16(pixel, pc);
985     value = MAKECOLOUR(pc);
986     LOUT24(out, value);
987     }
988 jsorg71 483 }
989 jsorg71 311 }
990     }
991    
992     static void
993 jdmeijer 821 translate16to32(const uint16 * data, uint8 * out, uint8 * end)
994 jsorg71 311 {
995 jsorg71 472 uint16 pixel;
996 jsorg71 483 uint32 value;
997 jdmeijer 821 PixelColour pc;
998 jsorg71 472
999 astrand 1049 if (g_compatible_arch)
1000 jsorg71 472 {
1001 jdmeijer 821 /* *INDENT-OFF* */
1002     REPEAT4
1003     (
1004     pixel = *(data++);
1005     SPLITCOLOUR16(pixel, pc);
1006     *(out++) = pc.blue;
1007     *(out++) = pc.green;
1008     *(out++) = pc.red;
1009     *(out++) = 0;
1010     )
1011     /* *INDENT-ON* */
1012     }
1013     else if (g_xserver_be)
1014     {
1015 jsorg71 472 if (g_host_be)
1016     {
1017 jdmeijer 821 while (out < end)
1018     {
1019     pixel = *(data++);
1020     BSWAP16(pixel);
1021     SPLITCOLOUR16(pixel, pc);
1022     value = MAKECOLOUR(pc);
1023     BOUT32(out, value);
1024     }
1025 stargo 534 }
1026 jdmeijer 821 else
1027 jsorg71 472 {
1028 stargo 823 while (out < end)
1029 jdmeijer 821 {
1030     pixel = *(data++);
1031     SPLITCOLOUR16(pixel, pc);
1032     value = MAKECOLOUR(pc);
1033     BOUT32(out, value);
1034     }
1035 astrand 499 }
1036 jdmeijer 821 }
1037     else
1038     {
1039     if (g_host_be)
1040     {
1041     while (out < end)
1042     {
1043     pixel = *(data++);
1044     BSWAP16(pixel);
1045     SPLITCOLOUR16(pixel, pc);
1046     value = MAKECOLOUR(pc);
1047     LOUT32(out, value);
1048     }
1049     }
1050 astrand 499 else
1051     {
1052 jdmeijer 821 while (out < end)
1053     {
1054     pixel = *(data++);
1055     SPLITCOLOUR16(pixel, pc);
1056     value = MAKECOLOUR(pc);
1057     LOUT32(out, value);
1058     }
1059 astrand 499 }
1060     }
1061 matty 28 }
1062    
1063 jsorg71 311 static void
1064 jdmeijer 821 translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1065 jsorg71 311 {
1066 jsorg71 316 uint32 pixel = 0;
1067 jsorg71 483 uint16 value;
1068 jdmeijer 821 PixelColour pc;
1069    
1070 jsorg71 311 while (out < end)
1071 jsorg71 316 {
1072     pixel = *(data++) << 16;
1073     pixel |= *(data++) << 8;
1074     pixel |= *(data++);
1075 jdmeijer 821 SPLITCOLOUR24(pixel, pc);
1076     value = MAKECOLOUR(pc);
1077 jsorg71 483 if (g_xserver_be)
1078     {
1079 jdmeijer 821 BOUT16(out, value);
1080 jsorg71 483 }
1081     else
1082     {
1083 jdmeijer 821 LOUT16(out, value);
1084 jsorg71 483 }
1085 jsorg71 316 }
1086 jsorg71 311 }
1087    
1088 jsorg71 316 static void
1089 jdmeijer 821 translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1090 jsorg71 316 {
1091 stargo 534 uint32 pixel;
1092     uint32 value;
1093 jdmeijer 821 PixelColour pc;
1094 stargo 534
1095 jdmeijer 821 if (g_xserver_be)
1096 jsorg71 316 {
1097 jdmeijer 821 while (out < end)
1098 stargo 534 {
1099 jdmeijer 821 pixel = *(data++) << 16;
1100     pixel |= *(data++) << 8;
1101     pixel |= *(data++);
1102     SPLITCOLOUR24(pixel, pc);
1103     value = MAKECOLOUR(pc);
1104     BOUT24(out, value);
1105 stargo 534 }
1106 jdmeijer 821 }
1107     else
1108     {
1109     while (out < end)
1110 stargo 534 {
1111 jdmeijer 821 pixel = *(data++) << 16;
1112     pixel |= *(data++) << 8;
1113     pixel |= *(data++);
1114     SPLITCOLOUR24(pixel, pc);
1115     value = MAKECOLOUR(pc);
1116     LOUT24(out, value);
1117 stargo 534 }
1118 jsorg71 316 }
1119     }
1120    
1121     static void
1122 jdmeijer 821 translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1123 jsorg71 316 {
1124 stargo 534 uint32 pixel;
1125     uint32 value;
1126 jdmeijer 821 PixelColour pc;
1127 stargo 534
1128 astrand 1049 if (g_compatible_arch)
1129 jsorg71 316 {
1130 jdmeijer 821 /* *INDENT-OFF* */
1131 stargo 822 #ifdef NEED_ALIGN
1132 jdmeijer 821 REPEAT4
1133     (
1134     *(out++) = *(data++);
1135     *(out++) = *(data++);
1136     *(out++) = *(data++);
1137     *(out++) = 0;
1138 stargo 822 )
1139 jdmeijer 821 #else
1140 stargo 822 REPEAT4
1141     (
1142 astrand 1041 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1143 astrand 1040 *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1144     out += 4;
1145     data += 3;
1146 stargo 822 )
1147 jdmeijer 821 #endif
1148     /* *INDENT-ON* */
1149     }
1150     else if (g_xserver_be)
1151     {
1152     while (out < end)
1153 jsorg71 472 {
1154 jdmeijer 821 pixel = *(data++) << 16;
1155     pixel |= *(data++) << 8;
1156     pixel |= *(data++);
1157     SPLITCOLOUR24(pixel, pc);
1158     value = MAKECOLOUR(pc);
1159     BOUT32(out, value);
1160 jsorg71 472 }
1161 jdmeijer 821 }
1162     else
1163     {
1164     while (out < end)
1165 jsorg71 472 {
1166 jdmeijer 821 pixel = *(data++) << 16;
1167     pixel |= *(data++) << 8;
1168     pixel |= *(data++);
1169     SPLITCOLOUR24(pixel, pc);
1170     value = MAKECOLOUR(pc);
1171     LOUT32(out, value);
1172 jsorg71 472 }
1173 jsorg71 316 }
1174     }
1175    
1176 matty 29 static uint8 *
1177 astrand 64 translate_image(int width, int height, uint8 * data)
1178 matty 28 {
1179 jsorg71 644 int size;
1180     uint8 *out;
1181     uint8 *end;
1182 matty 29
1183 astrand 1042 /*
1184     If RDP depth and X Visual depths match,
1185     and arch(endian) matches, no need to translate:
1186     just return data.
1187     Note: select_visual should've already ensured g_no_translate
1188     is only set for compatible depths, but the RDP depth might've
1189     changed during connection negotiations.
1190     */
1191     if (g_no_translate_image)
1192 jsorg71 645 {
1193 astrand 1042 if ((g_depth == 15 && g_server_depth == 15) ||
1194     (g_depth == 16 && g_server_depth == 16) ||
1195     (g_depth == 24 && g_server_depth == 24))
1196 jsorg71 645 return data;
1197     }
1198 jsorg71 644
1199     size = width * height * (g_bpp / 8);
1200     out = (uint8 *) xmalloc(size);
1201     end = out + size;
1202    
1203 astrand 1042 switch (g_server_depth)
1204 jsorg71 311 {
1205 jsorg71 316 case 24:
1206 jsorg71 450 switch (g_bpp)
1207 jsorg71 316 {
1208     case 32:
1209 jsorg71 483 translate24to32(data, out, end);
1210 jsorg71 316 break;
1211     case 24:
1212     translate24to24(data, out, end);
1213     break;
1214     case 16:
1215 jsorg71 483 translate24to16(data, out, end);
1216 jsorg71 316 break;
1217     }
1218 matty 29 break;
1219     case 16:
1220 jsorg71 450 switch (g_bpp)
1221 jsorg71 316 {
1222     case 32:
1223 jsorg71 483 translate16to32((uint16 *) data, out, end);
1224 jsorg71 316 break;
1225     case 24:
1226     translate16to24((uint16 *) data, out, end);
1227     break;
1228     case 16:
1229 matthewc 528 translate16to16((uint16 *) data, out, end);
1230 jsorg71 316 break;
1231     }
1232 matty 29 break;
1233 jsorg71 316 case 15:
1234 jsorg71 450 switch (g_bpp)
1235 jsorg71 316 {
1236     case 32:
1237 jsorg71 483 translate15to32((uint16 *) data, out, end);
1238 jsorg71 316 break;
1239     case 24:
1240     translate15to24((uint16 *) data, out, end);
1241     break;
1242     case 16:
1243 jsorg71 483 translate15to16((uint16 *) data, out, end);
1244 jsorg71 316 break;
1245     }
1246 matty 29 break;
1247 jsorg71 316 case 8:
1248 jsorg71 450 switch (g_bpp)
1249 jsorg71 316 {
1250     case 8:
1251     translate8to8(data, out, end);
1252     break;
1253     case 16:
1254 stargo 521 translate8to16(data, out, end);
1255 jsorg71 316 break;
1256     case 24:
1257     translate8to24(data, out, end);
1258     break;
1259     case 32:
1260 stargo 521 translate8to32(data, out, end);
1261 jsorg71 316 break;
1262     }
1263 matty 29 break;
1264     }
1265     return out;
1266 matty 28 }
1267    
1268 astrand 118 BOOL
1269 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
1270 astrand 102 {
1271 matthewc 203 int modifierpos, key, keysymMask = 0;
1272 astrand 102 int offset;
1273    
1274 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1275 astrand 102
1276     if (keycode == NoSymbol)
1277     return False;
1278    
1279     for (modifierpos = 0; modifierpos < 8; modifierpos++)
1280     {
1281 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
1282 astrand 102
1283 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
1284 astrand 102 {
1285 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
1286 matthewc 203 keysymMask |= 1 << modifierpos;
1287 astrand 102 }
1288     }
1289    
1290 matthewc 203 return (state & keysymMask) ? True : False;
1291 astrand 102 }
1292    
1293 matthewc 527 static void
1294     calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1295     {
1296     *shift_l = ffs(mask) - 1;
1297     mask >>= *shift_l;
1298     *shift_r = 8 - ffs(mask & ~(mask >> 1));
1299     }
1300    
1301 astrand 1042 /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1302     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1303     */
1304     static unsigned
1305     calculate_mask_weight(uint32 mask)
1306 jsorg71 81 {
1307 astrand 1042 unsigned weight = 0;
1308     do
1309     {
1310     weight += (mask & 1);
1311     }
1312     while (mask >>= 1);
1313     return weight;
1314     }
1315    
1316     static BOOL
1317     select_visual()
1318     {
1319 matthewc 121 XPixmapFormatValues *pfm;
1320 astrand 1042 int pixmap_formats_count, visuals_count;
1321 stargo 565 XVisualInfo *vmatches = NULL;
1322     XVisualInfo template;
1323 astrand 1042 int i;
1324     unsigned red_weight, blue_weight, green_weight;
1325 matthewc 121
1326 astrand 1042 red_weight = blue_weight = green_weight = 0;
1327    
1328     pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1329     if (pfm == NULL)
1330 jsorg71 81 {
1331 astrand 1042 error("Unable to get list of pixmap formats from display.\n");
1332     XCloseDisplay(g_display);
1333 jsorg71 81 return False;
1334     }
1335 matthewc 121
1336 astrand 1042 /* Search for best TrueColor visual */
1337 stargo 565 template.class = TrueColor;
1338 astrand 1042 vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1339     g_visual = NULL;
1340     g_no_translate_image = False;
1341 astrand 1049 g_compatible_arch = False;
1342 astrand 1042 if (vmatches != NULL)
1343 matthewc 527 {
1344 astrand 1042 for (i = 0; i < visuals_count; ++i)
1345 stargo 565 {
1346 astrand 1042 XVisualInfo *visual_info = &vmatches[i];
1347 stargo 565
1348 astrand 1042 /* Try to find a no-translation visual that'll
1349     allow us to use RDP bitmaps directly as ZPixmaps. */
1350     if (!g_xserver_be && (((visual_info->depth == 15) &&
1351     /* R5G5B5 */
1352     (visual_info->red_mask == 0x7c00) &&
1353     (visual_info->green_mask == 0x3e0) &&
1354     (visual_info->blue_mask == 0x1f)) ||
1355     ((visual_info->depth == 16) &&
1356     /* R5G6B5 */
1357     (visual_info->red_mask == 0xf800) &&
1358     (visual_info->green_mask == 0x7e0) &&
1359     (visual_info->blue_mask == 0x1f)) ||
1360     ((visual_info->depth == 24) &&
1361     /* R8G8B8 */
1362     (visual_info->red_mask == 0xff0000) &&
1363     (visual_info->green_mask == 0xff00) &&
1364     (visual_info->blue_mask == 0xff))))
1365     {
1366     g_visual = visual_info->visual;
1367     g_depth = visual_info->depth;
1368 astrand 1049 g_compatible_arch = !g_host_be;
1369 astrand 1042 g_no_translate_image = (visual_info->depth == g_server_depth);
1370     if (g_no_translate_image)
1371     /* We found the best visual */
1372     break;
1373     }
1374     else
1375     {
1376 astrand 1049 g_compatible_arch = False;
1377 astrand 1042 }
1378 jsorg71 644
1379 astrand 1042 if (visual_info->depth > 24)
1380     {
1381     /* Avoid 32-bit visuals and likes like the plague.
1382     They're either untested or proven to work bad
1383     (e.g. nvidia's Composite 32-bit visual).
1384     Most implementation offer a 24-bit visual anyway. */
1385     continue;
1386     }
1387 stargo 565
1388 astrand 1042 /* Only care for visuals, for whose BPPs (not depths!)
1389     we have a translateXtoY function. */
1390     BOOL can_translate_to_bpp = False;
1391     int j;
1392     for (j = 0; j < pixmap_formats_count; ++j)
1393     {
1394     if (pfm[j].depth == visual_info->depth)
1395     {
1396     if ((pfm[j].bits_per_pixel == 16) ||
1397     (pfm[j].bits_per_pixel == 24) ||
1398     (pfm[j].bits_per_pixel == 32))
1399     {
1400     can_translate_to_bpp = True;
1401     }
1402     break;
1403     }
1404     }
1405    
1406     /* Prefer formats which have the most colour depth.
1407     We're being truly aristocratic here, minding each
1408     weight on its own. */
1409     if (can_translate_to_bpp)
1410     {
1411     unsigned vis_red_weight =
1412     calculate_mask_weight(visual_info->red_mask);
1413     unsigned vis_green_weight =
1414     calculate_mask_weight(visual_info->green_mask);
1415     unsigned vis_blue_weight =
1416     calculate_mask_weight(visual_info->blue_mask);
1417     if ((vis_red_weight >= red_weight)
1418     && (vis_green_weight >= green_weight)
1419     && (vis_blue_weight >= blue_weight))
1420     {
1421     red_weight = vis_red_weight;
1422     green_weight = vis_green_weight;
1423     blue_weight = vis_blue_weight;
1424     g_visual = visual_info->visual;
1425     g_depth = visual_info->depth;
1426     }
1427     }
1428 stargo 565 }
1429 astrand 1042 XFree(vmatches);
1430 matthewc 527 }
1431 astrand 1042
1432     if (g_visual != NULL)
1433     {
1434     g_owncolmap = False;
1435     calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1436     calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1437     calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1438     }
1439 matthewc 527 else
1440     {
1441 astrand 1042 template.class = PseudoColor;
1442     template.depth = 8;
1443     template.colormap_size = 256;
1444     vmatches =
1445     XGetVisualInfo(g_display,
1446     VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1447     &template, &visuals_count);
1448     if (vmatches == NULL)
1449 matthewc 527 {
1450 astrand 1042 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1451     XCloseDisplay(g_display);
1452     XFree(pfm);
1453 matthewc 527 return False;
1454     }
1455    
1456 astrand 1042 /* we use a colourmap, so the default visual should do */
1457     g_owncolmap = True;
1458     g_visual = vmatches[0].visual;
1459     g_depth = vmatches[0].depth;
1460     }
1461 jsorg71 644
1462 astrand 1042 g_bpp = 0;
1463     for (i = 0; i < pixmap_formats_count; ++i)
1464     {
1465     XPixmapFormatValues *pf = &pfm[i];
1466     if (pf->depth == g_depth)
1467 jdmeijer 821 {
1468 astrand 1042 g_bpp = pf->bits_per_pixel;
1469    
1470     if (g_no_translate_image)
1471 jdmeijer 821 {
1472 astrand 1042 switch (g_server_depth)
1473     {
1474     case 15:
1475     case 16:
1476     if (g_bpp != 16)
1477     g_no_translate_image = False;
1478     break;
1479     case 24:
1480     /* Yes, this will force image translation
1481     on most modern servers which use 32 bits
1482     for R8G8B8. */
1483     if (g_bpp != 24)
1484     g_no_translate_image = False;
1485     break;
1486     default:
1487     g_no_translate_image = False;
1488     break;
1489     }
1490 jdmeijer 821 }
1491    
1492 astrand 1042 /* Pixmap formats list is a depth-to-bpp mapping --
1493     there's just a single entry for every depth,
1494     so we can safely break here */
1495     break;
1496 jdmeijer 821 }
1497 matthewc 527 }
1498 astrand 1042 XFree(pfm);
1499     pfm = NULL;
1500     return True;
1501     }
1502 matthewc 527
1503 astrand 1199 static XErrorHandler g_old_error_handler;
1504    
1505     static int
1506     error_handler(Display * dpy, XErrorEvent * eev)
1507     {
1508     if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1509     {
1510     fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1511     fprintf(stderr,
1512     "This is most likely caused by a broken window manager (commonly KWin).\n");
1513     return 0;
1514     }
1515    
1516     return g_old_error_handler(dpy, eev);
1517     }
1518    
1519 astrand 1042 BOOL
1520     ui_init(void)
1521     {
1522     int screen_num;
1523    
1524     g_display = XOpenDisplay(NULL);
1525     if (g_display == NULL)
1526 matthewc 121 {
1527 astrand 1042 error("Failed to open display: %s\n", XDisplayName(NULL));
1528     return False;
1529 matthewc 121 }
1530    
1531     {
1532 astrand 1042 uint16 endianess_test = 1;
1533     g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1534     }
1535    
1536 astrand 1199 g_old_error_handler = XSetErrorHandler(error_handler);
1537 astrand 1042 g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1538     screen_num = DefaultScreen(g_display);
1539     g_x_socket = ConnectionNumber(g_display);
1540     g_screen = ScreenOfDisplay(g_display, screen_num);
1541     g_depth = DefaultDepthOfScreen(g_screen);
1542    
1543     if (!select_visual())
1544 matthewc 121 return False;
1545 astrand 1042
1546     if (g_no_translate_image)
1547     {
1548     DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1549 matthewc 121 }
1550    
1551 astrand 1042 if (g_server_depth > g_bpp)
1552     {
1553     warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1554     g_server_depth, g_bpp);
1555     }
1556    
1557     DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1558     g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1559    
1560 matthewc 517 if (!g_owncolmap)
1561 n-ki 279 {
1562 astrand 580 g_xcolmap =
1563     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1564     AllocNone);
1565 jsorg71 450 if (g_depth <= 8)
1566 astrand 1042 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1567 n-ki 279 }
1568    
1569 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1570     {
1571 astrand 1042 warning("External BackingStore not available. Using internal.\n");
1572 jsorg71 450 g_ownbackstore = True;
1573 stargo 609 }
1574 matthewc 121
1575 astrand 500 /*
1576     * Determine desktop size
1577     */
1578 astrand 547 if (g_fullscreen)
1579 astrand 263 {
1580 astrand 547 g_width = WidthOfScreen(g_screen);
1581     g_height = HeightOfScreen(g_screen);
1582 astrand 1057 g_using_full_workarea = True;
1583 astrand 547 }
1584     else if (g_width < 0)
1585     {
1586 astrand 500 /* Percent of screen */
1587 astrand 991 if (-g_width >= 100)
1588     g_using_full_workarea = True;
1589 astrand 500 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1590     g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1591     }
1592     else if (g_width == 0)
1593     {
1594 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1595 matthewc 300 uint32 x, y, cx, cy;
1596     if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1597 astrand 263 {
1598 jsorg71 447 g_width = cx;
1599     g_height = cy;
1600 astrand 1057 g_using_full_workarea = True;
1601 matthewc 300 }
1602     else
1603     {
1604 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1605 astrand 1057 g_width = WidthOfScreen(g_screen);
1606     g_height = HeightOfScreen(g_screen);
1607 astrand 263 }
1608     }
1609 matthewc 121
1610 matthewc 160 /* make sure width is a multiple of 4 */
1611 jsorg71 447 g_width = (g_width + 3) & ~3;
1612 matthewc 160
1613 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1614 matthewc 203
1615 astrand 498 xkeymap_init();
1616    
1617 jsorg71 447 if (g_enable_compose)
1618 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1619 matthewc 188
1620 matthewc 432 xclip_init();
1621 astrand 1199 ewmh_init();
1622     if (g_seamless_rdp)
1623     seamless_init();
1624 jsorg71 316
1625 astrand 1042 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1626 jsorg71 316
1627 jsorg71 81 return True;
1628     }
1629 astrand 66
1630 matthewc 188 void
1631 matthewc 192 ui_deinit(void)
1632 matthewc 188 {
1633 astrand 1199 while (g_seamless_windows)
1634     {
1635     XDestroyWindow(g_display, g_seamless_windows->wnd);
1636     sw_remove_window(g_seamless_windows);
1637     }
1638    
1639 jsorg71 450 if (g_IM != NULL)
1640     XCloseIM(g_IM);
1641 astrand 580
1642 stargo 576 if (g_null_cursor != NULL)
1643     ui_destroy_cursor(g_null_cursor);
1644 matthewc 188
1645 jsorg71 450 XFreeModifiermap(g_mod_map);
1646 matthewc 203
1647 jsorg71 450 if (g_ownbackstore)
1648     XFreePixmap(g_display, g_backstore);
1649 matthewc 188
1650 jsorg71 450 XFreeGC(g_display, g_gc);
1651     XCloseDisplay(g_display);
1652     g_display = NULL;
1653 matthewc 188 }
1654    
1655 astrand 1199
1656     static void
1657     get_window_attribs(XSetWindowAttributes * attribs)
1658     {
1659     attribs->background_pixel = BlackPixelOfScreen(g_screen);
1660     attribs->background_pixel = WhitePixelOfScreen(g_screen);
1661     attribs->border_pixel = WhitePixelOfScreen(g_screen);
1662     attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1663     attribs->override_redirect = g_fullscreen;
1664     attribs->colormap = g_xcolmap;
1665     }
1666    
1667     static void
1668     get_input_mask(long *input_mask)
1669     {
1670     *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1671     VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1672    
1673     if (g_sendmotion)
1674     *input_mask |= PointerMotionMask;
1675     if (g_ownbackstore)
1676     *input_mask |= ExposureMask;
1677     if (g_fullscreen || g_grab_keyboard)
1678     *input_mask |= EnterWindowMask;
1679     if (g_grab_keyboard)
1680     *input_mask |= LeaveWindowMask;
1681     }
1682    
1683 matthewc 121 BOOL
1684 matthewc 192 ui_create_window(void)
1685 matty 6 {
1686 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1687 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1688    
1689 matthewc 121 XSetWindowAttributes attribs;
1690 matty 28 XClassHint *classhints;
1691     XSizeHints *sizehints;
1692 matthewc 188 int wndwidth, wndheight;
1693 matthewc 432 long input_mask, ic_input_mask;
1694 jsorg71 100 XEvent xevent;
1695    
1696 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1697     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1698 matthewc 188
1699 stargo 867 /* Handle -x-y portion of geometry string */
1700     if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1701     g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1702     if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1703     g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1704    
1705 astrand 1199 get_window_attribs(&attribs);
1706 matthewc 188
1707 astrand 801 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1708     wndheight, 0, g_depth, InputOutput, g_visual,
1709     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1710     CWBorderPixel, &attribs);
1711 jsorg71 100
1712 stargo 576 if (g_gc == NULL)
1713 astrand 1199 {
1714 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1715 astrand 1199 ui_reset_clip();
1716     }
1717 stargo 565
1718 jsorg71 725 if (g_create_bitmap_gc == NULL)
1719     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1720    
1721 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
1722 stargo 565 {
1723 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1724 stargo 565
1725     /* clear to prevent rubbish being exposed at startup */
1726     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1727     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1728     }
1729    
1730 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
1731 jsorg71 100
1732 jsorg71 450 if (g_hide_decorations)
1733 astrand 1199 mwm_hide_decorations(g_wnd);
1734 astrand 262
1735 jsorg71 100 classhints = XAllocClassHint();
1736     if (classhints != NULL)
1737     {
1738     classhints->res_name = classhints->res_class = "rdesktop";
1739 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
1740 jsorg71 100 XFree(classhints);
1741     }
1742    
1743     sizehints = XAllocSizeHints();
1744     if (sizehints)
1745     {
1746     sizehints->flags = PMinSize | PMaxSize;
1747 stargo 867 if (g_pos)
1748     sizehints->flags |= PPosition;
1749 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
1750     sizehints->min_height = sizehints->max_height = g_height;
1751 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
1752 jsorg71 100 XFree(sizehints);
1753     }
1754    
1755 astrand 651 if (g_embed_wnd)
1756     {
1757     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1758     }
1759 stargo 636
1760 astrand 1199 get_input_mask(&input_mask);
1761 matthewc 121
1762 jsorg71 450 if (g_IM != NULL)
1763 matthewc 188 {
1764 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1765 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1766 matthewc 188
1767 jsorg71 450 if ((g_IC != NULL)
1768     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1769 matthewc 188 input_mask |= ic_input_mask;
1770     }
1771    
1772 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
1773     XMapWindow(g_display, g_wnd);
1774 jsorg71 100
1775 matthewc 208 /* wait for VisibilityNotify */
1776 astrand 196 do
1777     {
1778 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1779 astrand 196 }
1780 matthewc 208 while (xevent.type != VisibilityNotify);
1781 jsorg71 688 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1782 matthewc 123
1783 jsorg71 447 g_focused = False;
1784     g_mouse_in_wnd = False;
1785 jsorg71 257
1786 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
1787 jsorg71 450 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1788     g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1789     XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1790 astrand 275
1791 astrand 508 /* create invisible 1x1 cursor to be used as null cursor */
1792 stargo 576 if (g_null_cursor == NULL)
1793     g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1794 astrand 508
1795 matty 10 return True;
1796 matty 6 }
1797    
1798 matty 25 void
1799 n-ki 677 ui_resize_window()
1800     {
1801     XSizeHints *sizehints;
1802 jsorg71 708 Pixmap bs;
1803 n-ki 677
1804     sizehints = XAllocSizeHints();
1805     if (sizehints)
1806     {
1807     sizehints->flags = PMinSize | PMaxSize;
1808     sizehints->min_width = sizehints->max_width = g_width;
1809     sizehints->min_height = sizehints->max_height = g_height;
1810     XSetWMNormalHints(g_display, g_wnd, sizehints);
1811     XFree(sizehints);
1812     }
1813    
1814     if (!(g_fullscreen || g_embed_wnd))
1815     {
1816     XResizeWindow(g_display, g_wnd, g_width, g_height);
1817     }
1818 jsorg71 708
1819     /* create new backstore pixmap */
1820     if (g_backstore != 0)
1821     {
1822     bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1823     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1824     XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1825     XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1826     XFreePixmap(g_display, g_backstore);
1827     g_backstore = bs;
1828     }
1829 n-ki 677 }
1830    
1831     void
1832 matthewc 192 ui_destroy_window(void)
1833 matty 6 {
1834 jsorg71 450 if (g_IC != NULL)
1835     XDestroyIC(g_IC);
1836 matty 31
1837 jsorg71 450 XDestroyWindow(g_display, g_wnd);
1838 matty 6 }
1839    
1840 jsorg71 100 void
1841 matthewc 192 xwin_toggle_fullscreen(void)
1842 jsorg71 100 {
1843 matthewc 188 Pixmap contents = 0;
1844 matthewc 123
1845 astrand 1199 if (g_seamless_active)
1846     /* Turn off SeamlessRDP mode */
1847     ui_seamless_toggle();
1848    
1849 jsorg71 450 if (!g_ownbackstore)
1850 matthewc 188 {
1851     /* need to save contents of window */
1852 jsorg71 450 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1853     XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1854 matthewc 188 }
1855    
1856     ui_destroy_window();
1857 jsorg71 447 g_fullscreen = !g_fullscreen;
1858 matthewc 188 ui_create_window();
1859 matthewc 123
1860 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
1861 matthewc 188
1862 jsorg71 450 if (!g_ownbackstore)
1863 matthewc 188 {
1864 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1865     XFreePixmap(g_display, contents);
1866 matthewc 188 }
1867 jsorg71 100 }
1868    
1869 astrand 988 static void
1870     handle_button_event(XEvent xevent, BOOL down)
1871     {
1872     uint16 button, flags = 0;
1873     g_last_gesturetime = xevent.xbutton.time;
1874     button = xkeymap_translate_button(xevent.xbutton.button);
1875     if (button == 0)
1876     return;
1877    
1878     if (down)
1879     flags = MOUSE_FLAG_DOWN;
1880    
1881     /* Stop moving window when button is released, regardless of cursor position */
1882     if (g_moving_wnd && (xevent.type == ButtonRelease))
1883     g_moving_wnd = False;
1884    
1885     /* If win_button_size is nonzero, enable single app mode */
1886     if (xevent.xbutton.y < g_win_button_size)
1887     {
1888     /* Check from right to left: */
1889     if (xevent.xbutton.x >= g_width - g_win_button_size)
1890     {
1891     /* The close button, continue */
1892     ;
1893     }
1894     else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1895     {
1896     /* The maximize/restore button. Do not send to
1897     server. It might be a good idea to change the
1898     cursor or give some other visible indication
1899     that rdesktop inhibited this click */
1900     if (xevent.type == ButtonPress)
1901     return;
1902     }
1903     else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1904     {
1905     /* The minimize button. Iconify window. */
1906     if (xevent.type == ButtonRelease)
1907     {
1908     /* Release the mouse button outside the minimize button, to prevent the
1909     actual minimazation to happen */
1910     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1911     XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1912     return;
1913     }
1914     }
1915     else if (xevent.xbutton.x <= g_win_button_size)
1916     {
1917     /* The system menu. Ignore. */
1918     if (xevent.type == ButtonPress)
1919     return;
1920     }
1921     else
1922     {
1923     /* The title bar. */
1924     if (xevent.type == ButtonPress)
1925     {
1926 astrand 991 if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1927 astrand 988 {
1928     g_moving_wnd = True;
1929     g_move_x_offset = xevent.xbutton.x;
1930     g_move_y_offset = xevent.xbutton.y;
1931     }
1932     return;
1933     }
1934     }
1935     }
1936    
1937 astrand 1199 if (xevent.xmotion.window == g_wnd)
1938     {
1939     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1940     flags | button, xevent.xbutton.x, xevent.xbutton.y);
1941     }
1942     else
1943     {
1944     /* SeamlessRDP */
1945     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1946     flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1947     }
1948 astrand 988 }
1949    
1950 astrand 1199
1951 stargo 887 /* Process events in Xlib queue
1952 astrand 275 Returns 0 after user quit, 1 otherwise */
1953     static int
1954 matthewc 192 xwin_process_events(void)
1955 matty 9 {
1956 n-ki 54 XEvent xevent;
1957 matthewc 38 KeySym keysym;
1958 matty 10 uint32 ev_time;
1959 astrand 66 char str[256];
1960     Status status;
1961 stargo 887 int events = 0;
1962 astrand 1199 seamless_window *sw;
1963 matty 9
1964 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
1965 matty 9 {
1966 jsorg71 450 XNextEvent(g_display, &xevent);
1967 matthewc 123
1968 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1969 astrand 66 {
1970 astrand 84 DEBUG_KBD(("Filtering event\n"));
1971 astrand 66 continue;
1972     }
1973    
1974 n-ki 54 switch (xevent.type)
1975 matty 9 {
1976 jsorg71 688 case VisibilityNotify:
1977 astrand 1199 if (xevent.xvisibility.window == g_wnd)
1978     g_Unobscured =
1979     xevent.xvisibility.state == VisibilityUnobscured;
1980    
1981 jsorg71 688 break;
1982 astrand 275 case ClientMessage:
1983     /* the window manager told us to quit */
1984 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
1985     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1986 astrand 275 /* Quit */
1987     return 0;
1988     break;
1989    
1990 matty 9 case KeyPress:
1991 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1992     if (g_IC != NULL)
1993 astrand 66 /* Multi_key compatible version */
1994     {
1995 jsorg71 450 XmbLookupString(g_IC,
1996 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
1997     &status);
1998 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1999 astrand 66 {
2000 astrand 82 error("XmbLookupString failed with status 0x%x\n",
2001     status);
2002 astrand 66 break;
2003     }
2004     }
2005     else
2006     {
2007     /* Plain old XLookupString */
2008 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
2009 astrand 66 XLookupString((XKeyEvent *) & xevent,
2010 astrand 82 str, sizeof(str), &keysym, NULL);
2011 astrand 66 }
2012    
2013 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2014 astrand 261 get_ksname(keysym)));
2015 astrand 66
2016 matthewc 203 ev_time = time(NULL);
2017     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2018 astrand 118 break;
2019    
2020 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2021 astrand 976 ev_time, True, 0);
2022 astrand 66 break;
2023 matthewc 203
2024 astrand 66 case KeyRelease:
2025 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
2026 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
2027     sizeof(str), &keysym, NULL);
2028 n-ki 52
2029 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2030 matthewc 203 get_ksname(keysym)));
2031 n-ki 52
2032 matthewc 203 ev_time = time(NULL);
2033     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2034 astrand 118 break;
2035    
2036 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2037 astrand 976 ev_time, False, 0);
2038 matty 9 break;
2039    
2040     case ButtonPress:
2041 astrand 988 handle_button_event(xevent, True);
2042     break;
2043 matty 9
2044     case ButtonRelease:
2045 astrand 988 handle_button_event(xevent, False);
2046 matty 10 break;
2047    
2048     case MotionNotify:
2049 jsorg71 450 if (g_moving_wnd)
2050 astrand 342 {
2051 jsorg71 450 XMoveWindow(g_display, g_wnd,
2052     xevent.xmotion.x_root - g_move_x_offset,
2053     xevent.xmotion.y_root - g_move_y_offset);
2054 astrand 342 break;
2055     }
2056    
2057 jsorg71 447 if (g_fullscreen && !g_focused)
2058 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2059 jsorg71 288 CurrentTime);
2060 astrand 1199
2061     if (xevent.xmotion.window == g_wnd)
2062     {
2063     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2064     xevent.xmotion.x, xevent.xmotion.y);
2065     }
2066     else
2067     {
2068     /* SeamlessRDP */
2069     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2070     xevent.xmotion.x_root,
2071     xevent.xmotion.y_root);
2072     }
2073 matty 28 break;
2074    
2075 matthewc 194 case FocusIn:
2076 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
2077     break;
2078 jsorg71 447 g_focused = True;
2079 astrand 543 reset_modifier_keys();
2080 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
2081     XGrabKeyboard(g_display, g_wnd, True,
2082 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
2083 astrand 1199
2084     sw = sw_get_window_by_wnd(xevent.xfocus.window);
2085     if (!sw)
2086     break;
2087    
2088     if (sw->id != g_seamless_focused)
2089     {
2090     seamless_send_focus(sw->id, 0);
2091     g_seamless_focused = sw->id;
2092     }
2093 matty 28 break;
2094    
2095 matthewc 194 case FocusOut:
2096 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
2097     break;
2098 jsorg71 447 g_focused = False;
2099 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
2100 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2101 matty 28 break;
2102 matty 31
2103 matthewc 250 case EnterNotify:
2104     /* we only register for this event when in fullscreen mode */
2105 jsorg71 257 /* or grab_keyboard */
2106 jsorg71 447 g_mouse_in_wnd = True;
2107     if (g_fullscreen)
2108 jsorg71 257 {
2109 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2110 astrand 261 CurrentTime);
2111 jsorg71 257 break;
2112     }
2113 jsorg71 447 if (g_focused)
2114 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
2115 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
2116 matthewc 250 break;
2117    
2118 matthewc 253 case LeaveNotify:
2119 jsorg71 257 /* we only register for this event when grab_keyboard */
2120 jsorg71 447 g_mouse_in_wnd = False;
2121 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2122 matthewc 253 break;
2123    
2124 matty 31 case Expose:
2125 astrand 1199 if (xevent.xexpose.window == g_wnd)
2126     {
2127     XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2128     g_gc,
2129     xevent.xexpose.x, xevent.xexpose.y,
2130     xevent.xexpose.width, xevent.xexpose.height,
2131     xevent.xexpose.x, xevent.xexpose.y);
2132     }
2133     else
2134     {
2135     sw = sw_get_window_by_wnd(xevent.xexpose.window);
2136     if (!sw)
2137     break;
2138     XCopyArea(g_display, g_backstore,
2139     xevent.xexpose.window, g_gc,
2140     xevent.xexpose.x + sw->xoffset,
2141     xevent.xexpose.y + sw->yoffset,
2142     xevent.xexpose.width,
2143     xevent.xexpose.height, xevent.xexpose.x,
2144     xevent.xexpose.y);
2145     }
2146    
2147 matty 31 break;
2148 astrand 119
2149     case MappingNotify:
2150     /* Refresh keyboard mapping if it has changed. This is important for
2151     Xvnc, since it allocates keycodes dynamically */
2152     if (xevent.xmapping.request == MappingKeyboard
2153     || xevent.xmapping.request == MappingModifier)
2154     XRefreshKeyboardMapping(&xevent.xmapping);
2155 matthewc 203
2156     if (xevent.xmapping.request == MappingModifier)
2157     {
2158 jsorg71 450 XFreeModifiermap(g_mod_map);
2159     g_mod_map = XGetModifierMapping(g_display);
2160 matthewc 203 }
2161 astrand 119 break;
2162 matthewc 432
2163 astrand 435 /* clipboard stuff */
2164 forsberg 415 case SelectionNotify:
2165 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
2166 forsberg 415 break;
2167     case SelectionRequest:
2168 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2169 forsberg 415 break;
2170 matthewc 432 case SelectionClear:
2171     xclip_handle_SelectionClear();
2172     break;
2173 forsberg 415 case PropertyNotify:
2174 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
2175 astrand 1199 if (xevent.xproperty.window == g_wnd)
2176     break;
2177     if (xevent.xproperty.window == DefaultRootWindow(g_display))
2178     break;
2179    
2180     /* seamless */
2181     sw = sw_get_window_by_wnd(xevent.xproperty.window);
2182     if (!sw)
2183     break;
2184    
2185     if ((xevent.xproperty.atom == g_net_wm_state_atom)
2186     && (xevent.xproperty.state == PropertyNewValue))
2187     {
2188     sw->state = ewmh_get_window_state(sw->wnd);
2189     seamless_send_state(sw->id, sw->state, 0);
2190     }
2191    
2192     if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2193     && (xevent.xproperty.state == PropertyNewValue))
2194     {
2195     sw->desktop = ewmh_get_window_desktop(sw->wnd);
2196     sw_all_to_desktop(sw->wnd, sw->desktop);
2197     }
2198    
2199 forsberg 415 break;
2200 jdmeijer 905 case MapNotify:
2201 astrand 1199 if (!g_seamless_active)
2202     rdp_send_client_window_status(1);
2203 jdmeijer 905 break;
2204     case UnmapNotify:
2205 astrand 1199 if (!g_seamless_active)
2206     rdp_send_client_window_status(0);
2207 jdmeijer 905 break;
2208 astrand 1199 case ConfigureNotify:
2209     if (!g_seamless_active)
2210     break;
2211    
2212     sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2213     if (!sw)
2214     break;
2215    
2216     gettimeofday(sw->position_timer, NULL);
2217     if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2218     1000000)
2219     {
2220     sw->position_timer->tv_usec +=
2221     SEAMLESSRDP_POSITION_TIMER - 1000000;
2222     sw->position_timer->tv_sec += 1;
2223     }
2224     else
2225     {
2226     sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2227     }
2228    
2229     sw_handle_restack(sw);
2230     break;
2231 matty 9 }
2232     }
2233 astrand 275 /* Keep going */
2234     return 1;
2235 matty 9 }
2236    
2237 astrand 275 /* Returns 0 after user quit, 1 otherwise */
2238     int
2239 matty 33 ui_select(int rdp_socket)
2240     {
2241 stargo 606 int n;
2242 matthewc 474 fd_set rfds, wfds;
2243 n-ki 592 struct timeval tv;
2244     BOOL s_timeout = False;
2245 matty 33
2246     while (True)
2247     {
2248 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2249 matthewc 121 /* Process any events already waiting */
2250 astrand 275 if (!xwin_process_events())
2251     /* User quit */
2252     return 0;
2253 astrand 119
2254 astrand 1199 if (g_seamless_active)
2255     sw_check_timers();
2256    
2257 matty 33 FD_ZERO(&rfds);
2258 matthewc 474 FD_ZERO(&wfds);
2259 matty 33 FD_SET(rdp_socket, &rfds);
2260 jsorg71 450 FD_SET(g_x_socket, &rfds);
2261 matty 33
2262 matthewc 474 #ifdef WITH_RDPSND
2263     /* FIXME: there should be an API for registering fds */
2264 stargo 504 if (g_dsp_busy)
2265 matty 33 {
2266 matthewc 474 FD_SET(g_dsp_fd, &wfds);
2267 n-ki 592 n = (g_dsp_fd > n) ? g_dsp_fd : n;
2268 astrand 499 }
2269 matthewc 474 #endif
2270 n-ki 592 /* default timeout */
2271     tv.tv_sec = 60;
2272     tv.tv_usec = 0;
2273 matthewc 474
2274 n-ki 592 /* add redirection handles */
2275     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2276 astrand 1199 seamless_select_timeout(&tv);
2277 n-ki 592
2278     n++;
2279    
2280     switch (select(n, &rfds, &wfds, NULL, &tv))
2281 matthewc 474 {
2282 matty 33 case -1:
2283     error("select: %s\n", strerror(errno));
2284    
2285     case 0:
2286 stargo 795 /* Abort serial read calls */
2287     if (s_timeout)
2288     rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2289 matty 33 continue;
2290     }
2291    
2292 n-ki 592 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2293    
2294 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2295     return 1;
2296    
2297 matthewc 474 #ifdef WITH_RDPSND
2298 stargo 504 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2299 matthewc 474 wave_out_play();
2300     #endif
2301 matty 33 }
2302     }
2303    
2304     void
2305 matty 25 ui_move_pointer(int x, int y)
2306 matty 9 {
2307 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2308 matty 9 }
2309    
2310 matty 25 HBITMAP
2311 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2312 matty 6 {
2313     XImage *image;
2314 matty 9 Pixmap bitmap;
2315 matty 28 uint8 *tdata;
2316 stargo 521 int bitmap_pad;
2317 matty 29
2318 astrand 1042 if (g_server_depth == 8)
2319 stargo 521 {
2320     bitmap_pad = 8;
2321     }
2322     else
2323     {
2324     bitmap_pad = g_bpp;
2325    
2326     if (g_bpp == 24)
2327     bitmap_pad = 32;
2328     }
2329    
2330 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2331     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2332     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2333 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2334 matty 6
2335 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2336 matty 9
2337     XFree(image);
2338 jsorg71 644 if (tdata != data)
2339 n-ki 279 xfree(tdata);
2340 matty 24 return (HBITMAP) bitmap;
2341 matty 6 }
2342    
2343 matty 25 void
2344 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2345 matty 6 {
2346 matty 10 XImage *image;
2347 matty 29 uint8 *tdata;
2348 stargo 521 int bitmap_pad;
2349    
2350 astrand 1042 if (g_server_depth == 8)
2351 stargo 521 {
2352     bitmap_pad = 8;
2353     }
2354     else
2355     {
2356     bitmap_pad = g_bpp;
2357    
2358     if (g_bpp == 24)
2359     bitmap_pad = 32;
2360     }
2361    
2362 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2363     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2364 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2365 matty 28
2366 jsorg71 450 if (g_ownbackstore)
2367 matty 31 {
2368 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2369     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2370 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2371     (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2372     x - sw->xoffset, y - sw->yoffset));
2373 matty 31 }
2374     else
2375     {
2376 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2377 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2378     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2379     x - sw->xoffset, y - sw->yoffset));
2380 matty 31 }
2381 matty 29
2382 matty 24 XFree(image);
2383 jsorg71 644 if (tdata != data)
2384 n-ki 279 xfree(tdata);
2385 matty 6 }
2386    
2387 matty 25 void
2388     ui_destroy_bitmap(HBITMAP bmp)
2389 matty 6 {
2390 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2391 matty 10 }
2392    
2393 matty 25 HGLYPH
2394 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2395 matty 10 {
2396 matty 9 XImage *image;
2397     Pixmap bitmap;
2398     int scanline;
2399 matty 6
2400 matty 9 scanline = (width + 7) / 8;
2401 matty 6
2402 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2403 jsorg71 725 if (g_create_glyph_gc == 0)
2404     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2405 matty 9
2406 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2407 astrand 73 width, height, 8, scanline);
2408 matty 23 image->byte_order = MSBFirst;
2409     image->bitmap_bit_order = MSBFirst;
2410     XInitImage(image);
2411    
2412 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2413 matty 29
2414 matty 9 XFree(image);
2415 astrand 64 return (HGLYPH) bitmap;
2416 matty 6 }
2417 matty 7
2418 matty 25 void
2419     ui_destroy_glyph(HGLYPH glyph)
2420 matty 7 {
2421 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2422 matty 9 }
2423    
2424 matty 29 HCURSOR
2425 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2426     uint8 * andmask, uint8 * xormask)
2427 matty 9 {
2428 matty 29 HGLYPH maskglyph, cursorglyph;
2429     XColor bg, fg;
2430     Cursor xcursor;
2431     uint8 *cursor, *pcursor;
2432     uint8 *mask, *pmask;
2433     uint8 nextbit;
2434     int scanline, offset;
2435     int i, j;
2436    
2437     scanline = (width + 7) / 8;
2438     offset = scanline * height;
2439    
2440 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2441 matty 29 memset(cursor, 0, offset);
2442    
2443 forsberg 415 mask = (uint8 *) xmalloc(offset);
2444 matty 29 memset(mask, 0, offset);
2445    
2446     /* approximate AND and XOR masks with a monochrome X pointer */
2447     for (i = 0; i < height; i++)
2448 matty 7 {
2449 matty 29 offset -= scanline;
2450     pcursor = &cursor[offset];
2451     pmask = &mask[offset];
2452    
2453     for (j = 0; j < scanline; j++)
2454 matty 28 {
2455 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2456     {
2457     if (xormask[0] || xormask[1] || xormask[2])
2458     {
2459     *pcursor |= (~(*andmask) & nextbit);
2460     *pmask |= nextbit;
2461     }
2462     else
2463     {
2464     *pcursor |= ((*andmask) & nextbit);
2465     *pmask |= (~(*andmask) & nextbit);
2466     }
2467    
2468     xormask += 3;
2469     }
2470    
2471     andmask++;
2472     pcursor++;
2473     pmask++;
2474 matty 28 }
2475 matty 7 }
2476 matty 29
2477     fg.red = fg.blue = fg.green = 0xffff;
2478     bg.red = bg.blue = bg.green = 0x0000;
2479     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2480    
2481     cursorglyph = ui_create_glyph(width, height, cursor);
2482     maskglyph = ui_create_glyph(width, height, mask);
2483    
2484 astrand 66 xcursor =
2485 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2486 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2487 astrand 64
2488 matty 29 ui_destroy_glyph(maskglyph);
2489     ui_destroy_glyph(cursorglyph);
2490     xfree(mask);
2491     xfree(cursor);
2492 astrand 64 return (HCURSOR) xcursor;
2493 matty 29 }
2494    
2495     void
2496     ui_set_cursor(HCURSOR cursor)
2497     {
2498 jsorg71 450 g_current_cursor = (Cursor) cursor;
2499     XDefineCursor(g_display, g_wnd, g_current_cursor);
2500 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2501 matty 29 }
2502    
2503     void
2504     ui_destroy_cursor(HCURSOR cursor)
2505     {
2506 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2507 matty 29 }
2508    
2509 astrand 508 void
2510     ui_set_null_cursor(void)
2511     {
2512     ui_set_cursor(g_null_cursor);
2513     }
2514    
2515 matty 29 #define MAKE_XCOLOR(xc,c) \
2516     (xc)->red = ((c)->red << 8) | (c)->red; \
2517     (xc)->green = ((c)->green << 8) | (c)->green; \
2518     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2519     (xc)->flags = DoRed | DoGreen | DoBlue;
2520    
2521 n-ki 279
2522 matty 29 HCOLOURMAP
2523 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2524 matty 29 {
2525     COLOURENTRY *entry;
2526     int i, ncolours = colours->ncolours;
2527 jsorg71 450 if (!g_owncolmap)
2528 matty 28 {
2529 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2530 n-ki 279 XColor xentry;
2531     XColor xc_cache[256];
2532     uint32 colour;
2533     int colLookup = 256;
2534     for (i = 0; i < ncolours; i++)
2535 matty 28 {
2536 n-ki 279 entry = &colours->colours[i];
2537     MAKE_XCOLOR(&xentry, entry);
2538 matty 7
2539 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2540 astrand 196 {
2541 n-ki 279 /* Allocation failed, find closest match. */
2542     int j = 256;
2543     int nMinDist = 3 * 256 * 256;
2544     long nDist = nMinDist;
2545 matty 28
2546 n-ki 279 /* only get the colors once */
2547     while (colLookup--)
2548 astrand 196 {
2549 n-ki 279 xc_cache[colLookup].pixel = colLookup;
2550     xc_cache[colLookup].red = xc_cache[colLookup].green =
2551     xc_cache[colLookup].blue = 0;
2552     xc_cache[colLookup].flags = 0;
2553 jsorg71 450 XQueryColor(g_display,
2554     DefaultColormap(g_display,
2555     DefaultScreen(g_display)),
2556 n-ki 279 &xc_cache[colLookup]);
2557 n-ki 185 }
2558 n-ki 279 colLookup = 0;
2559    
2560     /* approximate the pixel */
2561     while (j--)
2562 astrand 196 {
2563 n-ki 279 if (xc_cache[j].flags)
2564     {
2565     nDist = ((long) (xc_cache[j].red >> 8) -
2566     (long) (xentry.red >> 8)) *
2567     ((long) (xc_cache[j].red >> 8) -
2568     (long) (xentry.red >> 8)) +
2569     ((long) (xc_cache[j].green >> 8) -
2570     (long) (xentry.green >> 8)) *
2571     ((long) (xc_cache[j].green >> 8) -
2572     (long) (xentry.green >> 8)) +
2573     ((long) (xc_cache[j].blue >> 8) -
2574     (long) (xentry.blue >> 8)) *
2575     ((long) (xc_cache[j].blue >> 8) -
2576     (long) (xentry.blue >> 8));
2577     }
2578     if (nDist < nMinDist)
2579     {
2580     nMinDist = nDist;
2581     xentry.pixel = j;
2582     }
2583 n-ki 185 }
2584     }
2585 n-ki 279 colour = xentry.pixel;
2586    
2587     /* update our cache */
2588     if (xentry.pixel < 256)
2589     {
2590     xc_cache[xentry.pixel].red = xentry.red;
2591     xc_cache[xentry.pixel].green = xentry.green;
2592     xc_cache[xentry.pixel].blue = xentry.blue;
2593    
2594     }
2595    
2596 matthewc 527 map[i] = colour;
2597 n-ki 185 }
2598 n-ki 279 return map;
2599     }
2600     else
2601     {
2602     XColor *xcolours, *xentry;
2603     Colormap map;
2604 matty 29
2605 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2606 n-ki 279 for (i = 0; i < ncolours; i++)
2607 astrand 196 {
2608 n-ki 279 entry = &colours->colours[i];
2609     xentry = &xcolours[i];
2610     xentry->pixel = i;
2611     MAKE_XCOLOR(xentry, entry);
2612 matty 29 }
2613    
2614 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2615     XStoreColors(g_display, map, xcolours, ncolours);
2616 n-ki 185
2617 n-ki 279 xfree(xcolours);
2618     return (HCOLOURMAP) map;
2619 matty 29 }
2620 matty 7 }
2621    
2622 matty 25 void
2623     ui_destroy_colourmap(HCOLOURMAP map)
2624 matty 7 {
2625 jsorg71 450 if (!g_owncolmap)
2626 n-ki 279 xfree(map);
2627     else
2628 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2629 matty 7 }
2630    
2631 matty 25 void
2632     ui_set_colourmap(HCOLOURMAP map)
2633 matty 7 {
2634 jsorg71 450 if (!g_owncolmap)
2635 astrand 448 {
2636 jsorg71 450 if (g_colmap)
2637     xfree(g_colmap);
2638 astrand 448
2639 jsorg71 450 g_colmap = (uint32 *) map;
2640 astrand 448 }
2641 n-ki 279 else
2642 astrand 1199 {
2643 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2644 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2645     }
2646 matty 7 }
2647    
2648 matty 25 void
2649     ui_set_clip(int x, int y, int cx, int cy)
2650 matty 7 {
2651 astrand 1199 g_clip_rectangle.x = x;
2652     g_clip_rectangle.y = y;
2653     g_clip_rectangle.width = cx;
2654     g_clip_rectangle.height = cy;
2655     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2656 matty 9 }
2657 matty 7
2658 matty 25 void
2659 matthewc 192 ui_reset_clip(void)
2660 matty 9 {
2661 astrand 1199 g_clip_rectangle.x = 0;
2662     g_clip_rectangle.y = 0;
2663     g_clip_rectangle.width = g_width;
2664     g_clip_rectangle.height = g_height;
2665     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2666 matty 7 }
2667    
2668 matty 25 void
2669 matthewc 192 ui_bell(void)
2670 matty 10 {
2671 jsorg71 450 XBell(g_display, 0);
2672 matty 10 }
2673    
2674 matty 25 void
2675     ui_destblt(uint8 opcode,
2676     /* dest */ int x, int y, int cx, int cy)
2677 matty 9 {
2678 matty 29 SET_FUNCTION(opcode);
2679 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2680 matty 29 RESET_FUNCTION(opcode);
2681 matty 9 }
2682    
2683 jsorg71 373 static uint8 hatch_patterns[] = {
2684 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2685     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2686     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2687     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2688     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2689     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2690 jsorg71 373 };
2691    
2692 matty 25 void
2693     ui_patblt(uint8 opcode,
2694     /* dest */ int x, int y, int cx, int cy,
2695 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2696 matty 9 {
2697     Pixmap fill;
2698 jsorg71 59 uint8 i, ipattern[8];
2699 matty 9
2700 matty 29 SET_FUNCTION(opcode);
2701 matty 9
2702     switch (brush->style)
2703     {
2704 matty 24 case 0: /* Solid */
2705 matty 29 SET_FOREGROUND(fgcolour);
2706 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2707 matty 9 break;
2708    
2709 jsorg71 373 case 2: /* Hatch */
2710 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2711     hatch_patterns + brush->pattern[0] * 8);
2712 astrand 487 SET_FOREGROUND(fgcolour);
2713     SET_BACKGROUND(bgcolour);
2714 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2715     XSetStipple(g_display, g_gc, fill);
2716     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2717 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2718 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2719     XSetTSOrigin(g_display, g_gc, 0, 0);
2720 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
2721     break;
2722    
2723 matty 24 case 3: /* Pattern */
2724 jsorg71 59 for (i = 0; i != 8; i++)
2725     ipattern[7 - i] = brush->pattern[i];
2726     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2727 matty 29 SET_FOREGROUND(bgcolour);
2728     SET_BACKGROUND(fgcolour);
2729 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2730     XSetStipple(g_display, g_gc, fill);
2731     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2732 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2733 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2734     XSetTSOrigin(g_display, g_gc, 0, 0);
2735 astrand 64 ui_destroy_glyph((HGLYPH) fill);
2736 matty 9 break;
2737    
2738     default:
2739 matty 30 unimpl("brush %d\n", brush->style);
2740 matty 9 }
2741 matty 29
2742     RESET_FUNCTION(opcode);
2743 jsorg71 680
2744     if (g_ownbackstore)
2745     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2746 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2747     (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2748     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2749 matty 9 }
2750    
2751 matty 25 void
2752     ui_screenblt(uint8 opcode,
2753     /* dest */ int x, int y, int cx, int cy,
2754     /* src */ int srcx, int srcy)
2755 matty 9 {
2756 matty 29 SET_FUNCTION(opcode);
2757 jsorg71 450 if (g_ownbackstore)
2758 stargo 609 {
2759 astrand 1199 XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2760     g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2761     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2762 stargo 609 }
2763     else
2764     {
2765     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2766     }
2767 astrand 1199
2768     ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2769     (g_display, g_ownbackstore ? g_backstore : g_wnd,
2770     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2771    
2772 matty 29 RESET_FUNCTION(opcode);
2773 matty 9 }
2774    
2775 matty 25 void
2776     ui_memblt(uint8 opcode,
2777     /* dest */ int x, int y, int cx, int cy,
2778     /* src */ HBITMAP src, int srcx, int srcy)
2779 matty 9 {
2780 matty 29 SET_FUNCTION(opcode);
2781 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2782 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2783     (g_display, (Pixmap) src, sw->wnd, g_gc,
2784     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2785 jsorg71 450 if (g_ownbackstore)
2786     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2787 matty 29 RESET_FUNCTION(opcode);
2788 matty 9 }
2789    
2790 matty 25 void
2791     ui_triblt(uint8 opcode,
2792     /* dest */ int x, int y, int cx, int cy,
2793     /* src */ HBITMAP src, int srcx, int srcy,
2794 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2795 matty 9 {
2796     /* This is potentially difficult to do in general. Until someone
2797 matty 10 comes up with a more efficient way of doing it I am using cases. */
2798 matty 9
2799     switch (opcode)
2800     {
2801 matty 24 case 0x69: /* PDSxxn */
2802 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2803 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2804 matty 16 break;
2805    
2806 matty 24 case 0xb8: /* PSDPxax */
2807 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2808 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2809 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2810 matty 9 break;
2811    
2812 matty 29 case 0xc0: /* PSa */
2813 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2814 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2815 matty 28 break;
2816    
2817 matty 9 default:
2818 matty 30 unimpl("triblt 0x%x\n", opcode);
2819 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2820 matty 9 }
2821     }
2822    
2823 matty 25 void
2824     ui_line(uint8 opcode,
2825     /* dest */ int startx, int starty, int endx, int endy,
2826 astrand 64 /* pen */ PEN * pen)
2827 matty 9 {
2828 matty 29 SET_FUNCTION(opcode);
2829     SET_FOREGROUND(pen->colour);
2830 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2831 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2832     startx - sw->xoffset, starty - sw->yoffset,
2833     endx - sw->xoffset, endy - sw->yoffset));
2834 jsorg71 450 if (g_ownbackstore)
2835     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2836 matty 29 RESET_FUNCTION(opcode);
2837 matty 9 }
2838    
2839 matty 25 void
2840     ui_rect(
2841     /* dest */ int x, int y, int cx, int cy,
2842     /* brush */ int colour)
2843 matty 9 {
2844 matty 29 SET_FOREGROUND(colour);
2845 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2846 matty 9 }
2847    
2848 jdmeijer 831 void
2849     ui_polygon(uint8 opcode,
2850     /* mode */ uint8 fillmode,
2851     /* dest */ POINT * point, int npoints,
2852     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2853     {
2854     uint8 style, i, ipattern[8];
2855     Pixmap fill;
2856    
2857     SET_FUNCTION(opcode);
2858    
2859     switch (fillmode)
2860     {
2861     case ALTERNATE:
2862     XSetFillRule(g_display, g_gc, EvenOddRule);
2863     break;
2864     case WINDING:
2865     XSetFillRule(g_display, g_gc, WindingRule);
2866     break;
2867     default:
2868     unimpl("fill mode %d\n", fillmode);
2869     }
2870    
2871     if (brush)
2872     style = brush->style;
2873     else
2874     style = 0;
2875    
2876     switch (style)
2877     {
2878     case 0: /* Solid */
2879     SET_FOREGROUND(fgcolour);
2880     FILL_POLYGON((XPoint *) point, npoints);
2881     break;
2882    
2883     case 2: /* Hatch */
2884     fill = (Pixmap) ui_create_glyph(8, 8,
2885     hatch_patterns + brush->pattern[0] * 8);
2886     SET_FOREGROUND(fgcolour);
2887     SET_BACKGROUND(bgcolour);
2888     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2889     XSetStipple(g_display, g_gc, fill);
2890     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2891     FILL_POLYGON((XPoint *) point, npoints);
2892     XSetFillStyle(g_display, g_gc, FillSolid);
2893     XSetTSOrigin(g_display, g_gc, 0, 0);
2894     ui_destroy_glyph((HGLYPH) fill);
2895     break;
2896    
2897     case 3: /* Pattern */
2898     for (i = 0; i != 8; i++)
2899     ipattern[7 - i] = brush->pattern[i];
2900     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2901     SET_FOREGROUND(bgcolour);
2902     SET_BACKGROUND(fgcolour);
2903     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2904     XSetStipple(g_display, g_gc, fill);
2905     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2906     FILL_POLYGON((XPoint *) point, npoints);
2907     XSetFillStyle(g_display, g_gc, FillSolid);
2908     XSetTSOrigin(g_display, g_gc, 0, 0);
2909     ui_destroy_glyph((HGLYPH) fill);
2910     break;
2911    
2912     default:
2913     unimpl("brush %d\n", brush->style);
2914     }
2915    
2916     RESET_FUNCTION(opcode);
2917     }
2918    
2919     void
2920 jdmeijer 844 ui_polyline(uint8 opcode,
2921     /* dest */ POINT * points, int npoints,
2922     /* pen */ PEN * pen)
2923     {
2924     /* TODO: set join style */
2925     SET_FUNCTION(opcode);
2926     SET_FOREGROUND(pen->colour);
2927     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2928     if (g_ownbackstore)
2929     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2930     CoordModePrevious);
2931 astrand 1199
2932     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2933     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2934    
2935 jdmeijer 844 RESET_FUNCTION(opcode);
2936     }
2937    
2938     void
2939 jdmeijer 831 ui_ellipse(uint8 opcode,
2940     /* mode */ uint8 fillmode,
2941     /* dest */ int x, int y, int cx, int cy,
2942     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2943     {
2944     uint8 style, i, ipattern[8];
2945     Pixmap fill;
2946    
2947     SET_FUNCTION(opcode);
2948    
2949     if (brush)
2950     style = brush->style;
2951     else
2952     style = 0;
2953    
2954     switch (style)
2955     {
2956     case 0: /* Solid */
2957     SET_FOREGROUND(fgcolour);
2958     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2959     break;
2960    
2961     case 2: /* Hatch */
2962     fill = (Pixmap) ui_create_glyph(8, 8,
2963     hatch_patterns + brush->pattern[0] * 8);
2964     SET_FOREGROUND(fgcolour);
2965     SET_BACKGROUND(bgcolour);
2966     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2967     XSetStipple(g_display, g_gc, fill);
2968     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2969     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2970     XSetFillStyle(g_display, g_gc, FillSolid);
2971     XSetTSOrigin(g_display, g_gc, 0, 0);
2972     ui_destroy_glyph((HGLYPH) fill);
2973     break;
2974    
2975     case 3: /* Pattern */
2976     for (i = 0; i != 8; i++)
2977     ipattern[7 - i] = brush->pattern[i];
2978     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2979     SET_FOREGROUND(bgcolour);
2980     SET_BACKGROUND(fgcolour);
2981     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2982     XSetStipple(g_display, g_gc, fill);
2983     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2984     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2985     XSetFillStyle(g_display, g_gc, FillSolid);
2986     XSetTSOrigin(g_display, g_gc, 0, 0);
2987     ui_destroy_glyph((HGLYPH) fill);
2988     break;
2989    
2990     default:
2991     unimpl("brush %d\n", brush->style);
2992     }
2993    
2994     RESET_FUNCTION(opcode);
2995     }
2996    
2997 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
2998 matty 25 void
2999     ui_draw_glyph(int mixmode,
3000     /* dest */ int x, int y, int cx, int cy,
3001 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
3002     int bgcolour, int fgcolour)
3003 matty 9 {
3004 matty 29 SET_FOREGROUND(fgcolour);
3005     SET_BACKGROUND(bgcolour);
3006 matty 9
3007 jsorg71 450 XSetFillStyle(g_display, g_gc,
3008 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3009 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
3010     XSetTSOrigin(g_display, g_gc, x, y);
3011 matty 9
3012 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3013 matty 9
3014 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3015 matty 9 }
3016    
3017 mmihalik 49 #define DO_GLYPH(ttext,idx) \
3018     {\
3019     glyph = cache_get_font (font, ttext[idx]);\
3020     if (!(flags & TEXT2_IMPLICIT_X))\
3021 jsorg71 564 {\
3022     xyoffset = ttext[++idx];\
3023     if ((xyoffset & 0x80))\
3024 mmihalik 49 {\
3025 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3026     y += ttext[idx+1] | (ttext[idx+2] << 8);\
3027 mmihalik 49 else\
3028 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
3029     idx += 2;\
3030 mmihalik 49 }\
3031 jsorg71 564 else\
3032 mmihalik 49 {\
3033 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3034     y += xyoffset;\
3035     else\
3036     x += xyoffset;\
3037 mmihalik 49 }\
3038 jsorg71 564 }\
3039     if (glyph != NULL)\
3040     {\
3041     x1 = x + glyph->offset;\
3042     y1 = y + glyph->baseline;\
3043     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3044     XSetTSOrigin(g_display, g_gc, x1, y1);\
3045     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3046     if (flags & TEXT2_IMPLICIT_X)\
3047     x += glyph->width;\
3048     }\
3049 mmihalik 49 }
3050    
3051 matty 25 void
3052 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
3053 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
3054 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3055     int bgcolour, int fgcolour, uint8 * text, uint8 length)
3056 matty 9 {
3057 jdmeijer 843 /* TODO: use brush appropriately */
3058    
3059 matty 10 FONTGLYPH *glyph;
3060 jsorg71 564 int i, j, xyoffset, x1, y1;
3061 mmihalik 49 DATABLOB *entry;
3062 matty 9
3063 matty 29 SET_FOREGROUND(bgcolour);
3064 matty 28
3065 astrand 620 /* Sometimes, the boxcx value is something really large, like
3066     32691. This makes XCopyArea fail with Xvnc. The code below
3067     is a quick fix. */
3068     if (boxx + boxcx > g_width)
3069     boxcx = g_width - boxx;
3070    
3071 matty 9 if (boxcx > 1)
3072 matty 31 {
3073 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3074 matty 31 }
3075 matty 17 else if (mixmode == MIX_OPAQUE)
3076 matty 31 {
3077 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3078 matty 31 }
3079 matty 9
3080 jsorg71 564 SET_FOREGROUND(fgcolour);
3081     SET_BACKGROUND(bgcolour);
3082     XSetFillStyle(g_display, g_gc, FillStippled);
3083    
3084 matty 9 /* Paint text, character by character */
3085 astrand 64 for (i = 0; i < length;)
3086     {
3087     switch (text[i])
3088     {
3089     case 0xff:
3090 astrand 1031 /* At least two bytes needs to follow */
3091 astrand 1029 if (i + 3 > length)
3092 astrand 64 {
3093 astrand 1031 warning("Skipping short 0xff command:");
3094     for (j = 0; j < length; j++)
3095     fprintf(stderr, "%02x ", text[j]);
3096     fprintf(stderr, "\n");
3097 astrand 1029 i = length = 0;
3098     break;
3099 astrand 64 }
3100 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
3101     i += 3;
3102     length -= i;
3103 astrand 64 /* this will move pointer from start to first character after FF command */
3104 astrand 1029 text = &(text[i]);
3105 astrand 64 i = 0;
3106 mmihalik 49 break;
3107 matty 9
3108 astrand 64 case 0xfe:
3109 astrand 1031 /* At least one byte needs to follow */
3110     if (i + 2 > length)
3111 astrand 1029 {
3112 astrand 1031 warning("Skipping short 0xfe command:");
3113     for (j = 0; j < length; j++)
3114     fprintf(stderr, "%02x ", text[j]);
3115     fprintf(stderr, "\n");
3116 astrand 1029 i = length = 0;
3117     break;
3118     }
3119 astrand 64 entry = cache_get_text(text[i + 1]);
3120 astrand 1030 if (entry->data != NULL)
3121 astrand 64 {
3122 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
3123     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3124 astrand 64 {
3125     if (flags & TEXT2_VERTICAL)
3126     y += text[i + 2];
3127     else
3128     x += text[i + 2];
3129     }
3130     for (j = 0; j < entry->size; j++)
3131 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
3132 matthewc 44 }
3133 astrand 1031 if (i + 2 < length)
3134     i += 3;
3135     else
3136     i += 2;
3137 jsorg71 286 length -= i;
3138     /* this will move pointer from start to first character after FE command */
3139     text = &(text[i]);
3140     i = 0;
3141 astrand 64 break;
3142 matty 17
3143 astrand 64 default:
3144     DO_GLYPH(text, i);
3145     i++;
3146     break;
3147 matty 29 }
3148 mmihalik 49 }
3149 jsorg71 564
3150     XSetFillStyle(g_display, g_gc, FillSolid);
3151    
3152 jsorg71 450 if (g_ownbackstore)
3153 jsorg71 278 {
3154     if (boxcx > 1)
3155 astrand 1199 {
3156 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3157 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
3158 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3159     (g_display, g_backstore, sw->wnd, g_gc,
3160     boxx, boxy,
3161     boxcx, boxcy,
3162     boxx - sw->xoffset, boxy - sw->yoffset));
3163     }
3164 jsorg71 278 else
3165 astrand 1199 {
3166 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3167 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
3168 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3169     (g_display, g_backstore, sw->wnd, g_gc,
3170     clipx, clipy,
3171     clipcx, clipcy, clipx - sw->xoffset,
3172     clipy - sw->yoffset));
3173     }
3174 jsorg71 278 }
3175 matty 9 }
3176    
3177 matty 25 void
3178     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
3179 matty 9 {
3180 matty 28 Pixmap pix;
3181 matty 9 XImage *image;
3182    
3183 jsorg71 450 if (g_ownbackstore)
3184 matty 31 {
3185 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3186 matty 31 }
3187     else
3188     {
3189 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3190     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3191     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3192     XFreePixmap(g_display, pix);
3193 matty 31 }
3194 matty 28
3195 jsorg71 450 offset *= g_bpp / 8;
3196     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
3197 matty 28
3198     XDestroyImage(image);
3199 matty 9 }
3200    
3201 matty 25 void
3202     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
3203 matty 9 {
3204     XImage *image;
3205 matty 10 uint8 *data;
3206 matty 9
3207 jsorg71 450 offset *= g_bpp / 8;
3208     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3209 matty 10 if (data == NULL)
3210     return;
3211 matty 29
3212 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3213     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
3214 matty 29
3215 jsorg71 450 if (g_ownbackstore)
3216 matty 31 {
3217 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3218     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3219 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3220     (g_display, g_backstore, sw->wnd, g_gc,
3221     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3222 matty 31 }
3223     else
3224     {
3225 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3226 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3227     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3228     x - sw->xoffset, y - sw->yoffset));
3229 matty 31 }
3230    
3231 matty 9 XFree(image);
3232     }
3233 jsorg71 713
3234     /* these do nothing here but are used in uiports */
3235     void
3236     ui_begin_update(void)
3237     {
3238     }
3239    
3240     void
3241     ui_end_update(void)
3242     {
3243     }
3244 astrand 1199
3245    
3246     void
3247     ui_seamless_begin(BOOL hidden)
3248     {
3249     if (!g_seamless_rdp)
3250     return;
3251    
3252     if (g_seamless_started)
3253     return;
3254    
3255     g_seamless_started = True;
3256     g_seamless_hidden = hidden;
3257    
3258     if (!hidden)
3259     ui_seamless_toggle();
3260     }
3261    
3262    
3263     void
3264     ui_seamless_hide_desktop()
3265     {
3266     if (!g_seamless_rdp)
3267     return;
3268    
3269     if (!g_seamless_started)
3270     return;
3271    
3272     if (g_seamless_active)
3273     ui_seamless_toggle();
3274    
3275     g_seamless_hidden = True;
3276     }
3277    
3278    
3279     void
3280     ui_seamless_unhide_desktop()
3281     {
3282     if (!g_seamless_rdp)
3283     return;
3284    
3285     if (!g_seamless_started)
3286     return;
3287    
3288     g_seamless_hidden = False;
3289    
3290     ui_seamless_toggle();
3291     }
3292    
3293    
3294     void
3295     ui_seamless_toggle()
3296     {
3297     if (!g_seamless_rdp)
3298     return;
3299    
3300     if (!g_seamless_started)
3301     return;
3302    
3303     if (g_seamless_hidden)
3304     return;
3305    
3306     if (g_seamless_active)
3307     {
3308     /* Deactivate */
3309     while (g_seamless_windows)
3310     {
3311     XDestroyWindow(g_display, g_seamless_windows->wnd);
3312     sw_remove_window(g_seamless_windows);
3313     }
3314     XMapWindow(g_display, g_wnd);
3315     }
3316     else
3317     {
3318     /* Activate */
3319     XUnmapWindow(g_display, g_wnd);
3320     seamless_send_sync();
3321     }
3322    
3323     g_seamless_active = !g_seamless_active;
3324     }
3325    
3326    
3327     void
3328     ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3329     unsigned long flags)
3330     {
3331     Window wnd;
3332     XSetWindowAttributes attribs;
3333     XClassHint *classhints;
3334     XSizeHints *sizehints;
3335     XWMHints *wmhints;
3336     long input_mask;
3337     seamless_window *sw, *sw_parent;
3338    
3339     if (!g_seamless_active)
3340     return;
3341    
3342     /* Ignore CREATEs for existing windows */
3343     sw = sw_get_window_by_id(id);
3344     if (sw)
3345     return;
3346    
3347     get_window_attribs(&attribs);
3348     wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3349     InputOutput, g_visual,
3350     CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3351    
3352     XStoreName(g_display, wnd, "SeamlessRDP");
3353     ewmh_set_wm_name(wnd, "SeamlessRDP");
3354    
3355     mwm_hide_decorations(wnd);
3356    
3357     classhints = XAllocClassHint();
3358     if (classhints != NULL)
3359     {
3360     classhints->res_name = "rdesktop";
3361     classhints->res_class = "SeamlessRDP";
3362     XSetClassHint(g_display, wnd, classhints);
3363     XFree(classhints);
3364     }
3365    
3366     /* WM_NORMAL_HINTS */
3367     sizehints = XAllocSizeHints();
3368     if (sizehints != NULL)
3369     {
3370     sizehints->flags = USPosition;
3371     XSetWMNormalHints(g_display, wnd, sizehints);
3372     XFree(sizehints);
3373     }
3374    
3375     /* Parent-less transient windows */
3376     if (parent == 0xFFFFFFFF)
3377     {
3378     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3379     /* Some buggy wm:s (kwin) do not handle the above, so fake it
3380     using some other hints. */
3381     ewmh_set_window_popup(wnd);
3382     }
3383     /* Normal transient windows */
3384     else if (parent != 0x00000000)
3385     {
3386     sw_parent = sw_get_window_by_id(parent);
3387     if (sw_parent)
3388     XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3389     else
3390     warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3391     }
3392    
3393     if (flags & SEAMLESSRDP_CREATE_MODAL)
3394     {
3395     /* We do this to support buggy wm:s (*cough* metacity *cough*)
3396     somewhat at least */
3397     if (parent == 0x00000000)
3398     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3399     ewmh_set_window_modal(wnd);
3400     }
3401    
3402     /* FIXME: Support for Input Context:s */
3403    
3404     get_input_mask(&input_mask);
3405     input_mask |= PropertyChangeMask;
3406    
3407     XSelectInput(g_display, wnd, input_mask);
3408    
3409     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3410     seamless window, we could try to close the window on the
3411     serverside, instead of terminating rdesktop */
3412     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3413    
3414     sw = xmalloc(sizeof(seamless_window));
3415     sw->wnd = wnd;
3416     sw->id = id;
3417     sw->behind = 0;
3418     sw->group = sw_find_group(group, False);
3419     sw->group->refcnt++;
3420     sw->xoffset = 0;
3421     sw->yoffset = 0;
3422     sw->width = 0;
3423     sw->height = 0;
3424     sw->state = SEAMLESSRDP_NOTYETMAPPED;
3425     sw->desktop = 0;
3426     sw->position_timer = xmalloc(sizeof(struct timeval));
3427     timerclear(sw->position_timer);
3428    
3429     sw->outstanding_position = False;
3430     sw->outpos_serial = 0;
3431     sw->outpos_xoffset = sw->outpos_yoffset = 0;
3432     sw->outpos_width = sw->outpos_height = 0;
3433    
3434     sw->next = g_seamless_windows;
3435     g_seamless_windows = sw;
3436    
3437     /* WM_HINTS */
3438     wmhints = XAllocWMHints();
3439     if (wmhints)
3440     {
3441     wmhints->flags = WindowGroupHint;
3442     wmhints->window_group = sw->group->wnd;
3443     XSetWMHints(g_display, sw->wnd, wmhints);
3444     XFree(wmhints);
3445     }
3446     }
3447    
3448    
3449     void
3450     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3451     {
3452     seamless_window *sw;
3453    
3454     if (!g_seamless_active)
3455     return;
3456    
3457     sw = sw_get_window_by_id(id);
3458     if (!sw)
3459     {
3460     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3461     return;
3462     }
3463    
3464     XDestroyWindow(g_display, sw->wnd);
3465     sw_remove_window(sw);
3466     }
3467    
3468    
3469     void
3470     ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3471     {
3472     seamless_window *sw;
3473    
3474     if (!g_seamless_active)
3475     return;
3476    
3477     sw = sw_get_window_by_id(id);
3478     if (!sw)
3479     {
3480     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3481     return;
3482     }
3483    
3484     /* We ignore server updates until it has handled our request. */
3485     if (sw->outstanding_position)
3486     return;
3487    
3488     if (!width || !height)
3489     /* X11 windows must be at least 1x1 */
3490     return;
3491    
3492     sw->xoffset = x;
3493     sw->yoffset = y;
3494     sw->width = width;
3495     sw->height = height;
3496    
3497     /* If we move the window in a maximized state, then KDE won't
3498     accept restoration */
3499     switch (sw->state)
3500     {
3501     case SEAMLESSRDP_MINIMIZED:
3502     case SEAMLESSRDP_MAXIMIZED:
3503     return;
3504     }
3505    
3506     /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3507     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3508     }
3509    
3510    
3511     void
3512     ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3513     {
3514     seamless_window *sw;
3515    
3516     if (!g_seamless_active)
3517     return;
3518    
3519     sw = sw_get_window_by_id(id);
3520     if (!sw)
3521     {
3522     warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3523     return;
3524     }
3525    
3526     if (behind)
3527     {
3528     seamless_window *sw_behind;
3529     Window wnds[2];
3530    
3531     sw_behind = sw_get_window_by_id(behind);
3532     if (!sw_behind)
3533     {
3534     warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3535     behind);
3536     return;
3537     }
3538    
3539     wnds[1] = sw_behind->wnd;
3540     wnds[0] = sw->wnd;
3541    
3542     XRestackWindows(g_display, wnds, 2);
3543     }
3544     else
3545     {
3546     XRaiseWindow(g_display, sw->wnd);
3547     }
3548    
3549     sw_restack_window(sw, behind);
3550     }
3551    
3552    
3553     void
3554     ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3555     {
3556     seamless_window *sw;
3557    
3558     if (!g_seamless_active)
3559     return;
3560    
3561     sw = sw_get_window_by_id(id);
3562     if (!sw)
3563     {
3564     warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3565     return;
3566     }
3567    
3568     /* FIXME: Might want to convert the name for non-EWMH WMs */
3569     XStoreName(g_display, sw->wnd, title);
3570     ewmh_set_wm_name(sw->wnd, title);
3571     }
3572    
3573    
3574     void
3575     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3576     {
3577     seamless_window *sw;
3578    
3579     if (!g_seamless_active)
3580     return;
3581    
3582     sw = sw_get_window_by_id(id);
3583     if (!sw)
3584     {
3585     warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3586     return;
3587     }
3588    
3589     switch (state)
3590     {
3591     case SEAMLESSRDP_NORMAL:
3592     case SEAMLESSRDP_MAXIMIZED:
3593     ewmh_change_state(sw->wnd, state);
3594     XMapWindow(g_display, sw->wnd);
3595     break;
3596     case SEAMLESSRDP_MINIMIZED:
3597     /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3598     the Window Manager should probably just ignore the request, since
3599     _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3600     such as minimization, rather than an independent state." Besides,
3601     XIconifyWindow is easier. */
3602     if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3603     {
3604     XWMHints *hints;
3605     hints = XGetWMHints(g_display, sw->wnd);
3606     if (hints)
3607     {
3608     hints->flags |= StateHint;
3609     hints->initial_state = IconicState;
3610     XSetWMHints(g_display, sw->wnd, hints);
3611     XFree(hints);
3612     }
3613     XMapWindow(g_display, sw->wnd);
3614     }
3615     else
3616     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3617     break;
3618     default:
3619     warning("SeamlessRDP: Invalid state %d\n", state);
3620     break;
3621     }
3622    
3623     sw->state = state;
3624     }
3625    
3626    
3627     void
3628     ui_seamless_syncbegin(unsigned long flags)
3629     {
3630     if (!g_seamless_active)
3631     return;
3632    
3633     /* Destroy all seamless windows */
3634     while (g_seamless_windows)
3635     {
3636     XDestroyWindow(g_display, g_seamless_windows->wnd);
3637     sw_remove_window(g_seamless_windows);
3638     }
3639     }
3640    
3641    
3642     void
3643     ui_seamless_ack(unsigned int serial)
3644     {
3645     seamless_window *sw;
3646     for (sw = g_seamless_windows; sw; sw = sw->next)
3647     {
3648     if (sw->outstanding_position && (sw->outpos_serial == serial))
3649     {
3650     sw->xoffset = sw->outpos_xoffset;
3651     sw->yoffset = sw->outpos_yoffset;
3652     sw->width = sw->outpos_width;
3653     sw->height = sw->outpos_height;
3654     sw->outstanding_position = False;
3655    
3656     /* Do a complete redraw of the window as part of the
3657     completion of the move. This is to remove any
3658     artifacts caused by our lack of synchronization. */
3659     XCopyArea(g_display, g_backstore,
3660     sw->wnd, g_gc,
3661     sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3662    
3663     break;
3664     }
3665     }
3666     }

  ViewVC Help
Powered by ViewVC 1.1.26