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

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

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

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

Legend:
Removed from v.119  
changed lines
  Added in v.1475

  ViewVC Help
Powered by ViewVC 1.1.26