/[rdesktop]/jpeg/rdesktop/trunk/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

Diff of /jpeg/rdesktop/trunk/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.76  
changed lines
  Added in v.1370

  ViewVC Help
Powered by ViewVC 1.1.26