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

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

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

revision 450 by jsorg71, Wed Aug 27 22:51:33 2003 UTC revision 1485 by astrand, Tue Nov 25 08:05:25 2008 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- 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-2002     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    #include <strings.h>
30  #include "rdesktop.h"  #include "rdesktop.h"
31  #include "xproto.h"  #include "xproto.h"
32    
33  extern int g_width;  extern int g_width;
34  extern int g_height;  extern int g_height;
35  extern BOOL g_sendmotion;  extern int g_xpos;
36  extern BOOL g_fullscreen;  extern int g_ypos;
37  extern BOOL g_grab_keyboard;  extern int g_pos;
38  extern BOOL g_hide_decorations;  extern RD_BOOL g_sendmotion;
39    extern RD_BOOL g_fullscreen;
40    extern RD_BOOL g_grab_keyboard;
41    extern RD_BOOL g_hide_decorations;
42  extern char g_title[];  extern char g_title[];
43  extern int g_server_bpp;  /* Color depth of the RDP session.
44       As of RDP 5.1, it may be 8, 15, 16 or 24. */
45    extern int g_server_depth;
46  extern int g_win_button_size;  extern int g_win_button_size;
 BOOL g_enable_compose = False;  
 BOOL g_focused;  
 BOOL g_mouse_in_wnd;  
47    
48  Display *g_display;  Display *g_display;
49  Time g_last_gesturetime;  Time g_last_gesturetime;
50  static int g_x_socket;  static int g_x_socket;
51  static Screen *g_screen;  static Screen *g_screen;
52  Window g_wnd;  Window g_wnd;
53  static GC g_gc;  
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;  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;  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;  static int g_bpp;
108  static XIM g_IM;  static XIM g_IM;
109  static XIC g_IC;  static XIC g_IC;
110  static XModifierKeymap *g_mod_map;  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;  static Cursor g_current_cursor;
115    static RD_HCURSOR g_null_cursor = NULL;
116  static Atom g_protocol_atom, g_kill_atom;  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 g_host_be;  static RD_BOOL g_host_be;
142  static BOOL g_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 g_ownbackstore;  extern RD_BOOL g_ownbackstore;
148  static Pixmap g_backstore;  static Pixmap g_backstore = 0;
149    
150  /* Moving in single app mode */  /* Moving in single app mode */
151  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
152  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
153  static int g_move_y_offset = 0;  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 */  /* MWM decorations */
161  #define MWM_HINTS_DECORATIONS   (1L << 1)  #define MWM_HINTS_DECORATIONS   (1L << 1)
162  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
163  typedef struct  typedef struct
164  {  {
165          uint32 flags;          unsigned long flags;
166          uint32 functions;          unsigned long functions;
167          uint32 decorations;          unsigned long decorations;
168          sint32 inputMode;          long inputMode;
169          uint32 status;          unsigned long status;
170  }  }
171  PropMotifWmHints;  PropMotifWmHints;
172    
# Line 87  typedef struct Line 178  typedef struct
178  }  }
179  PixelColour;  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(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
220            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
221          if (g_ownbackstore) \          if (g_ownbackstore) \
222                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
223  }  }
# Line 100  PixelColour; Line 227  PixelColour;
227          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          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  BOOL g_owncolmap = False;  extern RD_BOOL g_owncolmap;
259  static Colormap g_xcolmap;  static Colormap g_xcolmap;
260  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
261    
262  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : translate_colour(g_colmap[col]) )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
263  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
264  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
265    
# Line 131  static int rop2_map[] = { Line 285  static int rop2_map[] = {
285  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_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(g_display, g_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
315    sw_remove_window(seamless_window * win)
316    {
317            seamless_window *sw, **prevnext = &g_seamless_windows;
318            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
341    sw_all_to_desktop(Window wnd, unsigned int desktop)
342    {
343            seamless_window *sw;
344            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    
357    /* Send our position */
358  static void  static void
359  mwm_hide_decorations(void)  sw_update_position(seamless_window * sw)
360    {
361            XWindowAttributes wa;
362            int x, y;
363            Window child_return;
364            unsigned int serial;
365    
366            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                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
393                    {
394                            timerclear(sw->position_timer);
395                            sw_update_position(sw);
396                    }
397            }
398    }
399    
400    
401    static void
402    sw_restack_window(seamless_window * sw, unsigned long behind)
403    {
404            seamless_window *sw_above;
405    
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    
430    static void
431    sw_handle_restack(seamless_window * sw)
432    {
433            Status status;
434            Window root, parent, *children;
435            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            i = 0;
446            while (children[i] != sw->wnd)
447            {
448                    i++;
449                    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;
458            }
459    
460            if (!sw_below && !sw->behind)
461                    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;          PropMotifWmHints motif_hints;
514          Atom hintsatom;          Atom hintsatom;
# Line 149  mwm_hide_decorations(void) Line 525  mwm_hide_decorations(void)
525                  return;                  return;
526          }          }
527    
528          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
529                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
530    
531  }  }
532    
533  static PixelColour  typedef struct _sw_configurenotify_context
 split_colour15(uint32 colour)  
534  {  {
535          PixelColour rv;          Window window;
536          rv.red = (colour & 0x7c00) >> 10;          unsigned long serial;
537          rv.red = (rv.red * 0xff) / 0x1f;  } sw_configurenotify_context;
538          rv.green = (colour & 0x03e0) >> 5;  
539          rv.green = (rv.green * 0xff) / 0x1f;  /* Predicate procedure for sw_wait_configurenotify */
540          rv.blue = (colour & 0x1f);  static Bool
541          rv.blue = (rv.blue * 0xff) / 0x1f;  sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg)
542          return rv;  {
543  }          sw_configurenotify_context *context = (sw_configurenotify_context *) arg;
544            if (xevent->xany.type == ConfigureNotify
545  static PixelColour              && xevent->xconfigure.window == context->window
546  split_colour16(uint32 colour)              && xevent->xany.serial >= context->serial)
547  {                  return True;
548          PixelColour rv;  
549          rv.red = (colour & 0xf800) >> 11;          return False;
550          rv.red = (rv.red * 0xff) / 0x1f;  }
551          rv.green = (colour & 0x07e0) >> 5;  
552          rv.green = (rv.green * 0xff) / 0x3f;  /* Wait for a ConfigureNotify, with a equal or larger serial, on the
553          rv.blue = (colour & 0x001f);     specified window. The event will be removed from the queue. We
554          rv.blue = (rv.blue * 0xff) / 0x1f;     could use XMaskEvent(StructureNotifyMask), but we would then risk
555          return rv;     throwing away crucial events like DestroyNotify.
556  }  
557       After a ConfigureWindow, according to ICCCM section 4.1.5, we
558  static PixelColour     should recieve a ConfigureNotify, either a real or synthetic
559  split_colour24(uint32 colour)     one. This indicates that the configure has been "completed".
560  {     However, some WMs such as several versions of Metacity fails to
561          PixelColour rv;     send synthetic events. See bug
562          rv.blue = (colour & 0xff0000) >> 16;     http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
563          rv.green = (colour & 0xff00) >> 8;     timeout to avoid a hang. Tk uses the same approach. */
564          rv.red = (colour & 0xff);  static void
565          return rv;  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;
585                    }
586                    usleep(100000);
587                    gettimeofday(&now, NULL);
588            }
589            while (timercmp(&now, &nextsecond, <));
590    
591            if (!got)
592            {
593                    warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
594            }
595  }  }
596    
597  static uint32  /* Get the toplevel window, in case of reparenting */
598  make_colour16(PixelColour pc)  static Window
599    sw_get_toplevel(Window wnd)
600  {  {
601          pc.red = (pc.red * 0x1f) / 0xff;          Window root, parent;
602          pc.green = (pc.green * 0x3f) / 0xff;          Window *child_list;
603          pc.blue = (pc.blue * 0x1f) / 0xff;          unsigned int num_children;
604          return (pc.red << 11) | (pc.green << 5) | pc.blue;  
605            while (1)
606            {
607                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
608                    if (root == parent)
609                    {
610                            break;
611                    }
612                    else if (!parent)
613                    {
614                            warning("Internal error: sw_get_toplevel called with root window\n");
615                    }
616    
617                    wnd = parent;
618            }
619    
620            return wnd;
621  }  }
622    
623  static uint32  
624  make_colour24(PixelColour pc)  /* 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          return (pc.red << 16) | (pc.green << 8) | pc.blue;          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;
651                    }
652            }
653    
654            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  static uint32  
672  make_colour32(PixelColour pc)  /* 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          return (pc.red << 16) | (pc.green << 8) | pc.blue;          /* 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 (g_server_bpp)          PixelColour pc;
819            switch (g_server_depth)
820          {          {
821                  case 15:                  case 15:
822                          switch (g_bpp)                          SPLITCOLOUR15(colour, pc);
                         {  
                                 case 16:  
                                         colour = make_colour16(split_colour15(colour));  
                                         break;  
                                 case 24:  
                                         colour = make_colour24(split_colour15(colour));  
                                         break;  
                                 case 32:  
                                         colour = make_colour32(split_colour15(colour));  
                                         break;  
                         }  
823                          break;                          break;
824                  case 16:                  case 16:
825                          switch (g_bpp)                          SPLITCOLOUR16(colour, pc);
                         {  
                                 case 16:  
                                         break;  
                                 case 24:  
                                         colour = make_colour24(split_colour16(colour));  
                                         break;  
                                 case 32:  
                                         colour = make_colour32(split_colour16(colour));  
                                         break;  
                         }  
826                          break;                          break;
827                  case 24:                  case 24:
828                          switch (g_bpp)                  case 32:
829                          {                          SPLITCOLOUR24(colour, pc);
                                 case 16:  
                                         colour = make_colour16(split_colour24(colour));  
                                         break;  
                                 case 24:  
                                         break;  
                                 case 32:  
                                         colour = make_colour32(split_colour24(colour));  
                                         break;  
                         }  
830                          break;                          break;
831          }                  default:
832          switch (g_bpp)                          /* Avoid warning */
833          {                          pc.red = 0;
834                  case 16:                          pc.green = 0;
835                          if (g_host_be != g_xserver_be)                          pc.blue = 0;
                                 BSWAP16(colour);  
836                          break;                          break;
837            }
838            return MAKECOLOUR(pc);
839    }
840    
841                  case 24:  /* indent is confused by UNROLL8 */
842                          if (g_xserver_be)  /* *INDENT-OFF* */
                                 BSWAP24(colour);  
                         break;  
843    
844                  case 32:  /* repeat and unroll, similar to bitmap.c */
845                          if (g_host_be != g_xserver_be)  /* potentialy any of the following translate */
846                                  BSWAP32(colour);  /* functions can use repeat but just doing */
847                          break;  /* the most common ones */
         }  
848    
849          return colour;  #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  static void  static void
877  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
878  {  {
879          while (out < end)          while (out < end)
880                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
881  }  }
882    
883  static void  static void
884  translate8to16(uint8 * data, uint16 * out, uint16 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
885  {  {
886          while (out < end)          uint16 value;
887                  *(out++) = (uint16) g_colmap[*(data++)];  
888            if (g_compatible_arch)
889            {
890                    /* *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            {
900                    while (out < end)
901                    {
902                            value = (uint16) g_colmap[*(data++)];
903                            BOUT16(out, value);
904                    }
905            }
906            else
907            {
908                    while (out < end)
909                    {
910                            value = (uint16) g_colmap[*(data++)];
911                            LOUT16(out, value);
912                    }
913            }
914  }  }
915    
916  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
917  static void  static void
918  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
919  {  {
920          uint32 value;          uint32 value;
921    
922          while (out < end)          if (g_compatible_arch)
923          {          {
924                  value = g_colmap[*(data++)];                  while (out < end)
925                  *(out++) = value;                  {
926                  *(out++) = value >> 8;                          value = g_colmap[*(data++)];
927                  *(out++) = value >> 16;                          BOUT24(out, value);
928                    }
929            }
930            else
931            {
932                    while (out < end)
933                    {
934                            value = g_colmap[*(data++)];
935                            LOUT24(out, value);
936                    }
937          }          }
938  }  }
939    
940  static void  static void
941  translate8to32(uint8 * data, uint32 * out, uint32 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
942  {  {
943          while (out < end)          uint32 value;
                 *(out++) = g_colmap[*(data++)];  
 }  
944    
945  /* todo the remaining translate function might need some big endian check ?? */          if (g_compatible_arch)
946            {
947                    /* *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                    while (out < end)
966                    {
967                            value = g_colmap[*(data++)];
968                            LOUT32(out, value);
969                    }
970            }
971    }
972    
973  static void  static void
974  translate15to16(uint16 * data, uint16 * out, uint16 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
975  {  {
976          while (out < end)          uint16 pixel;
977                  *(out++) = (uint16) make_colour16(split_colour15(*(data++)));          uint16 value;
978            PixelColour pc;
979    
980            if (g_xserver_be)
981            {
982                    while (out < end)
983                    {
984                            pixel = *(data++);
985                            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  static void  static void
1011  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
1012  {  {
1013          uint32 value;          uint32 value;
1014            uint16 pixel;
1015            PixelColour pc;
1016    
1017          while (out < end)          if (g_compatible_arch)
1018          {          {
1019                  value = make_colour24(split_colour15(*(data++)));                  /* *INDENT-OFF* */
1020                  *(out++) = value;                  REPEAT3
1021                  *(out++) = value >> 8;                  (
1022                  *(out++) = value >> 16;                          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  static void  static void
1061  translate15to32(uint16 * data, uint32 * out, uint32 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
1062  {  {
1063          while (out < end)          uint16 pixel;
1064                  *(out++) = make_colour32(split_colour15(*(data++)));          uint32 value;
1065            PixelColour pc;
1066    
1067            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                    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  static void
1112  translate16to16(uint16 * data, uint16 * out, uint16 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
1113  {  {
1114          while (out < end)          uint16 pixel;
1115                  *(out++) = (uint16) (*(data++));          uint16 value;
1116  }          PixelColour pc;
1117    
1118            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                            while (out < end)
1147                            {
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  static void  static void
1169  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
1170  {  {
1171          uint32 value;          uint32 value;
1172            uint16 pixel;
1173            PixelColour pc;
1174    
1175          while (out < end)          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                  value = make_colour24(split_colour16(*(data++)));                  if (g_host_be)
1215                  *(out++) = value;                  {
1216                  *(out++) = value >> 8;                          while (out < end)
1217                  *(out++) = value >> 16;                          {
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  static void  static void
1239  translate16to32(uint16 * data, uint32 * out, uint32 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
1240  {  {
1241          while (out < end)          uint16 pixel;
1242                  *(out++) = make_colour32(split_colour16(*(data++)));          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  static void
1310  translate24to16(uint8 * data, uint16 * out, uint16 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1311  {  {
1312          uint32 pixel = 0;          uint32 pixel = 0;
1313            uint16 value;
1314            PixelColour pc;
1315    
1316          while (out < end)          while (out < end)
1317          {          {
1318                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1319                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1320                  pixel |= *(data++);                  pixel |= *(data++);
1321                  *(out++) = (uint16) make_colour16(split_colour24(pixel));                  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  static void  static void
1335  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1336  {  {
1337          while (out < end)          uint32 pixel;
1338            uint32 value;
1339            PixelColour pc;
1340    
1341            if (g_xserver_be)
1342          {          {
1343                  *(out++) = (*(data++));                  while (out < end)
1344                    {
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            else
1354            {
1355                    while (out < end)
1356                    {
1357                            pixel = *(data++) << 16;
1358                            pixel |= *(data++) << 8;
1359                            pixel |= *(data++);
1360                            SPLITCOLOUR24(pixel, pc);
1361                            value = MAKECOLOUR(pc);
1362                            LOUT24(out, value);
1363                    }
1364          }          }
1365  }  }
1366    
1367  static void  static void
1368  translate24to32(uint8 * data, uint32 * out, uint32 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1369  {  {
1370          uint32 pixel = 0;          uint32 pixel;
1371          while (out < end)          uint32 value;
1372            PixelColour pc;
1373    
1374            if (g_compatible_arch)
1375          {          {
1376                  pixel = *(data++);                  /* *INDENT-OFF* */
1377                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
1378                  pixel |= *(data++) << 16;                  REPEAT4
1379                  *(out++) = pixel;                  (
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 *  static uint8 *
1423  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1424  {  {
1425          int size = width * height * g_bpp / 8;          int size;
1426          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1427          uint8 *end = out + size;          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          switch (g_server_bpp)          /* todo */
1439            if (g_server_depth == 32 && g_depth == 24)
1440            {
1441                    return data;
1442            }
1443    
1444            if (g_no_translate_image)
1445            {
1446                    if ((g_depth == 15 && g_server_depth == 15) ||
1447                        (g_depth == 16 && g_server_depth == 16) ||
1448                        (g_depth == 24 && g_server_depth == 24))
1449                            return data;
1450            }
1451    
1452            size = width * height * (g_bpp / 8);
1453            out = (uint8 *) xmalloc(size);
1454            end = out + size;
1455    
1456            switch (g_server_depth)
1457          {          {
1458                  case 24:                  case 24:
1459                          switch (g_bpp)                          switch (g_bpp)
1460                          {                          {
1461                                  case 32:                                  case 32:
1462                                          translate24to32(data, (uint32 *) out, (uint32 *) end);                                          translate24to32(data, out, end);
1463                                          break;                                          break;
1464                                  case 24:                                  case 24:
1465                                          translate24to24(data, out, end);                                          translate24to24(data, out, end);
1466                                          break;                                          break;
1467                                  case 16:                                  case 16:
1468                                          translate24to16(data, (uint16 *) out, (uint16 *) end);                                          translate24to16(data, out, end);
1469                                          break;                                          break;
1470                          }                          }
1471                          break;                          break;
# Line 439  translate_image(int width, int height, u Line 1473  translate_image(int width, int height, u
1473                          switch (g_bpp)                          switch (g_bpp)
1474                          {                          {
1475                                  case 32:                                  case 32:
1476                                          translate16to32((uint16 *) data, (uint32 *) out,                                          translate16to32((uint16 *) data, out, end);
                                                         (uint32 *) end);  
1477                                          break;                                          break;
1478                                  case 24:                                  case 24:
1479                                          translate16to24((uint16 *) data, out, end);                                          translate16to24((uint16 *) data, out, end);
1480                                          break;                                          break;
1481                                  case 16:                                  case 16:
1482                                          translate16to16((uint16 *) data, (uint16 *) out,                                          translate16to16((uint16 *) data, out, end);
                                                         (uint16 *) end);  
1483                                          break;                                          break;
1484                          }                          }
1485                          break;                          break;
# Line 455  translate_image(int width, int height, u Line 1487  translate_image(int width, int height, u
1487                          switch (g_bpp)                          switch (g_bpp)
1488                          {                          {
1489                                  case 32:                                  case 32:
1490                                          translate15to32((uint16 *) data, (uint32 *) out,                                          translate15to32((uint16 *) data, out, end);
                                                         (uint32 *) end);  
1491                                          break;                                          break;
1492                                  case 24:                                  case 24:
1493                                          translate15to24((uint16 *) data, out, end);                                          translate15to24((uint16 *) data, out, end);
1494                                          break;                                          break;
1495                                  case 16:                                  case 16:
1496                                          translate15to16((uint16 *) data, (uint16 *) out,                                          translate15to16((uint16 *) data, out, end);
                                                         (uint16 *) end);  
1497                                          break;                                          break;
1498                          }                          }
1499                          break;                          break;
# Line 474  translate_image(int width, int height, u Line 1504  translate_image(int width, int height, u
1504                                          translate8to8(data, out, end);                                          translate8to8(data, out, end);
1505                                          break;                                          break;
1506                                  case 16:                                  case 16:
1507                                          translate8to16(data, (uint16 *) out, (uint16 *) end);                                          translate8to16(data, out, end);
1508                                          break;                                          break;
1509                                  case 24:                                  case 24:
1510                                          translate8to24(data, out, end);                                          translate8to24(data, out, end);
1511                                          break;                                          break;
1512                                  case 32:                                  case 32:
1513                                          translate8to32(data, (uint32 *) out, (uint32 *) end);                                          translate8to32(data, out, end);
1514                                          break;                                          break;
1515                          }                          }
1516                          break;                          break;
# Line 488  translate_image(int width, int height, u Line 1518  translate_image(int width, int height, u
1518          return out;          return out;
1519  }  }
1520    
1521  BOOL  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            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1528            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    RD_BOOL
1544  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1545  {  {
1546          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 513  get_key_state(unsigned int state, uint32 Line 1565  get_key_state(unsigned int state, uint32
1565          return (state & keysymMask) ? True : False;          return (state & keysymMask) ? True : False;
1566  }  }
1567    
1568  BOOL  static void
1569  ui_init(void)  calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1570    {
1571            *shift_l = ffs(mask) - 1;
1572            mask >>= *shift_l;
1573            *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    static RD_BOOL
1592    select_visual(int screen_num)
1593  {  {
1594          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1595          uint16 test;          int pixmap_formats_count, visuals_count;
1596            XVisualInfo *vmatches = NULL;
1597            XVisualInfo template;
1598          int i;          int i;
1599            unsigned red_weight, blue_weight, green_weight;
1600    
1601          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1602          if (g_display == NULL)  
1603            if (g_server_depth == -1)
1604          {          {
1605                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1606            }
1607    
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;                  return False;
1614          }          }
1615    
1616          g_x_socket = ConnectionNumber(g_display);          /* Search for best TrueColor visual */
1617          g_screen = DefaultScreenOfDisplay(g_display);          template.class = TrueColor;
1618          g_visual = DefaultVisualOfScreen(g_screen);          template.screen = screen_num;
1619          g_depth = DefaultDepthOfScreen(g_screen);          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                            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                                    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          pfm = XListPixmapFormats(g_display, &i);                          /* Only care for visuals, for whose BPPs (not depths!)
1674          if (pfm != NULL)                             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(vmatches);
1713            }
1714    
1715            if (g_visual != NULL)
1716            {
1717                    g_owncolmap = False;
1718                    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                  /* Use maximum bpp for this depth - this is generally                  template.class = PseudoColor;
1725                     desirable, e.g. 24 bits->32 bits. */                  template.depth = 8;
1726                  while (i--)                  template.colormap_size = 256;
1727                    vmatches =
1728                            XGetVisualInfo(g_display,
1729                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1730                                           &template, &visuals_count);
1731                    if (vmatches == NULL)
1732                  {                  {
1733                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          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                                  g_bpp = pfm[i].bits_per_pixel;                                  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                  }                  }
                 XFree(pfm);  
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          if (g_bpp < 8)          sw = sw_get_window_by_id(id);
1799            if (!sw)
1800                    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                  error("Less than 8 bpp not currently supported.\n");                  XFree(name);
1808                  XCloseDisplay(g_display);          }
1809    
1810            return sts;
1811    }
1812    
1813    static int
1814    error_handler(Display * dpy, XErrorEvent * eev)
1815    {
1816            if (g_error_expected)
1817                    return 0;
1818    
1819            return g_old_error_handler(dpy, eev);
1820    }
1821    
1822    RD_BOOL
1823    ui_init(void)
1824    {
1825            int screen_num;
1826    
1827            g_display = XOpenDisplay(NULL);
1828            if (g_display == NULL)
1829            {
1830                    error("Failed to open display: %s\n", XDisplayName(NULL));
1831                  return False;                  return False;
1832          }          }
1833    
         if (g_owncolmap != True)  
1834          {          {
1835                  g_xcolmap = DefaultColormapOfScreen(g_screen);                  uint16 endianess_test = 1;
1836                  if (g_depth <= 8)                  g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
                         warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");  
1837          }          }
1838    
1839          g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);          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 (DoesBackingStore(g_screen) != Always)          if (!select_visual(screen_num))
1847                  g_ownbackstore = True;                  return False;
1848    
1849          test = 1;          if (g_no_translate_image)
1850          g_host_be = !(BOOL) (*(uint8 *) (&test));          {
1851          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);                  DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1852            }
1853    
1854            if (g_server_depth > g_bpp)
1855            {
1856                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1857                            g_server_depth, g_bpp);
1858            }
1859    
1860            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1861                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1862    
1863          if ((g_width == 0) || (g_height == 0))          if (!g_owncolmap)
1864            {
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 ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1873            {
1874                    warning("External BackingStore not available. Using internal.\n");
1875                    g_ownbackstore = True;
1876            }
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 */                  /* Fetch geometry from _NET_WORKAREA */
1898                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1899                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1900                  {                  {
1901                          g_width = cx;                          g_width = cx;
1902                          g_height = cy;                          g_height = cy;
1903                            g_using_full_workarea = True;
1904                  }                  }
1905                  else                  else
1906                  {                  {
1907                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1908                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1909                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1910                  }                  }
1911          }          }
1912    
         if (g_fullscreen)  
         {  
                 g_width = WidthOfScreen(g_screen);  
                 g_height = HeightOfScreen(g_screen);  
         }  
   
1913          /* make sure width is a multiple of 4 */          /* make sure width is a multiple of 4 */
1914          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1915    
         if (g_ownbackstore)  
         {  
                 g_backstore =  
                         XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,  
                                       g_depth);  
   
                 /* clear to prevent rubbish being exposed at startup */  
                 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));  
                 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);  
         }  
   
1916          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1917            xwin_refresh_pointer_map();
1918    
1919            xkeymap_init();
1920    
1921          if (g_enable_compose)          if (g_enable_compose)
1922                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1923    
         xkeymap_init();  
1924          xclip_init();          xclip_init();
1925            ewmh_init();
1926            if (g_seamless_rdp)
1927            {
1928                    seamless_init();
1929            }
1930    
1931          /* todo take this out when high colour is done */          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
         printf("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth);  
1932    
1933          return True;          return True;
1934  }  }
# Line 625  ui_init(void) Line 1936  ui_init(void)
1936  void  void
1937  ui_deinit(void)  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)          if (g_IM != NULL)
1948                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1949    
1950            if (g_null_cursor != NULL)
1951                    ui_destroy_cursor(g_null_cursor);
1952    
1953          XFreeModifiermap(g_mod_map);          XFreeModifiermap(g_mod_map);
1954    
1955          if (g_ownbackstore)          if (g_ownbackstore)
# Line 638  ui_deinit(void) Line 1960  ui_deinit(void)
1960          g_display = NULL;          g_display = NULL;
1961  }  }
1962    
1963  BOOL  
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)  ui_create_window(void)
1993  {  {
1994            uint8 null_pointer_mask[1] = { 0x80 };
1995            uint8 null_pointer_data[24] = { 0x00 };
1996    
1997          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1998          XClassHint *classhints;          XClassHint *classhints;
1999          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 651  ui_create_window(void) Line 2004  ui_create_window(void)
2004          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
2005          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
2006    
2007          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
2008          attribs.backing_store = g_ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
2009          attribs.override_redirect = g_fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
2010            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2011          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2012                              0, CopyFromParent, InputOutput, CopyFromParent,  
2013                              CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          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);          XStoreName(g_display, g_wnd, g_title);
2039            ewmh_set_wm_name(g_wnd, g_title);
2040    
2041          if (g_hide_decorations)          if (g_hide_decorations)
2042                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2043    
2044          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2045          if (classhints != NULL)          if (classhints != NULL)
# Line 676  ui_create_window(void) Line 2053  ui_create_window(void)
2053          if (sizehints)          if (sizehints)
2054          {          {
2055                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
2056                    if (g_pos)
2057                            sizehints->flags |= PPosition;
2058                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
2059                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
2060                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
2061                  XFree(sizehints);                  XFree(sizehints);
2062          }          }
2063    
2064          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          if (g_embed_wnd)
2065                  VisibilityChangeMask | FocusChangeMask;          {
2066                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2067            }
2068    
2069          if (g_sendmotion)          get_input_mask(&input_mask);
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
2070    
2071          if (g_IM != NULL)          if (g_IM != NULL)
2072          {          {
2073                  g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),                  g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
2074                                 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);                                   XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
2075    
2076                  if ((g_IC != NULL)                  if ((g_IC != NULL)
2077                      && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))                      && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
# Line 713  ui_create_window(void) Line 2087  ui_create_window(void)
2087                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
2088          }          }
2089          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
2090            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
2091    
2092          g_focused = False;          g_focused = False;
2093          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 722  ui_create_window(void) Line 2097  ui_create_window(void)
2097          g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);          g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
2098          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);          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_resize_window()
2114    {
2115            XSizeHints *sizehints;
2116            Pixmap bs;
2117    
2118            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            if (!(g_fullscreen || g_embed_wnd))
2129            {
2130                    XResizeWindow(g_display, g_wnd, g_width, g_height);
2131            }
2132    
2133            /* create new backstore pixmap */
2134            if (g_backstore != 0)
2135            {
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
2146  ui_destroy_window(void)  ui_destroy_window(void)
2147  {  {
2148          if (g_IC != NULL)          if (g_IC != NULL)
# Line 739  xwin_toggle_fullscreen(void) Line 2156  xwin_toggle_fullscreen(void)
2156  {  {
2157          Pixmap contents = 0;          Pixmap contents = 0;
2158    
2159            if (g_seamless_active)
2160                    /* Turn off SeamlessRDP mode */
2161                    ui_seamless_toggle();
2162    
2163          if (!g_ownbackstore)          if (!g_ownbackstore)
2164          {          {
2165                  /* need to save contents of window */                  /* need to save contents of window */
# Line 759  xwin_toggle_fullscreen(void) Line 2180  xwin_toggle_fullscreen(void)
2180          }          }
2181  }  }
2182    
2183  /* Process all events in Xlib queue  static void
2184    handle_button_event(XEvent xevent, RD_BOOL down)
2185    {
2186            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 */     Returns 0 after user quit, 1 otherwise */
2273  static int  static int
2274  xwin_process_events(void)  xwin_process_events(void)
2275  {  {
2276          XEvent xevent;          XEvent xevent;
2277          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
2278          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
2279          char str[256];          char str[256];
2280          Status status;          Status status;
2281          unsigned int state;          int events = 0;
2282          Window wdummy;          seamless_window *sw;
         int dummy;  
2283    
2284          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
2285          {          {
2286                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
2287    
# Line 785  xwin_process_events(void) Line 2291  xwin_process_events(void)
2291                          continue;                          continue;
2292                  }                  }
2293    
                 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:                          case ClientMessage:
2303                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2304                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2305                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2306                                          /* Quit */                                  {
2307                                          return 0;                                          /* 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;                                  break;
2317    
2318                          case KeyPress:                          case KeyPress:
# Line 820  xwin_process_events(void) Line 2338  xwin_process_events(void)
2338                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2339                                  }                                  }
2340    
2341                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2342                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2343    
2344                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2345                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2346                                          break;                                          break;
2347    
2348                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2349                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers();  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers();  
   
2350                                  break;                                  break;
2351    
2352                          case KeyRelease:                          case KeyRelease:
# Line 845  xwin_process_events(void) Line 2354  xwin_process_events(void)
2354                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2355                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2356    
2357                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2358                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2359    
2360                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2361                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  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);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2366                                  break;                                  break;
2367    
2368                          case ButtonPress:                          case ButtonPress:
2369                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2370                                  /* fall through */                                  break;
2371    
2372                          case ButtonRelease:                          case ButtonRelease:
2373                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
2374                                  break;                                  break;
2375    
2376                          case MotionNotify:                          case MotionNotify:
# Line 936  xwin_process_events(void) Line 2385  xwin_process_events(void)
2385                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2386                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2387                                                         CurrentTime);                                                         CurrentTime);
2388                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2389                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  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 FocusIn:                          case FocusIn:
2404                                  if (xevent.xfocus.mode == NotifyGrab)                                  if (xevent.xfocus.mode == NotifyGrab)
2405                                          break;                                          break;
2406                                  g_focused = True;                                  g_focused = True;
2407                                  XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,                                  reset_modifier_keys();
                                               &dummy, &dummy, &state);  
                                 reset_modifier_keys(state);  
2408                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2409                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2410                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2411    
2412                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2413                                    if (!sw)
2414                                            break;
2415    
2416                                    /* Menu windows are real X11 windows,
2417                                       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 FocusOut:                          case FocusOut:
# Line 982  xwin_process_events(void) Line 2465  xwin_process_events(void)
2465                                  break;                                  break;
2466    
2467                          case Expose:                          case Expose:
2468                                  XCopyArea(g_display, g_backstore, g_wnd, g_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 1001  xwin_process_events(void) Line 2501  xwin_process_events(void)
2501                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2502                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2503                                  }                                  }
2504    
2505                                    if (xevent.xmapping.request == MappingPointer)
2506                                    {
2507                                            xwin_refresh_pointer_map();
2508                                    }
2509    
2510                                  break;                                  break;
2511    
2512                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1015  xwin_process_events(void) Line 2521  xwin_process_events(void)
2521                                  break;                                  break;
2522                          case PropertyNotify:                          case PropertyNotify:
2523                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  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;
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;                                  break;
2580                  }                  }
2581          }          }
# Line 1026  xwin_process_events(void) Line 2587  xwin_process_events(void)
2587  int  int
2588  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2589  {  {
2590          int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;          int n;
2591          fd_set rfds;          fd_set rfds, wfds;
2592            struct timeval tv;
2593          FD_ZERO(&rfds);          RD_BOOL s_timeout = False;
2594    
2595          while (True)          while (True)
2596          {          {
2597                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2598                  /* Process any events already waiting */                  /* Process any events already waiting */
2599                  if (!xwin_process_events())                  if (!xwin_process_events())
2600                          /* User quit */                          /* User quit */
2601                          return 0;                          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                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2610    
2611                  switch (select(n, &rfds, NULL, NULL, NULL))                  /* default timeout */
2612                    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                    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    #ifdef WITH_RDPSND
2642                    rdpsnd_check_fds(&rfds, &wfds);
2643    #endif
2644    
2645                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2646    
2647                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2648                          return 1;                          return 1;
2649    
2650          }          }
2651  }  }
2652    
# Line 1062  ui_move_pointer(int x, int y) Line 2656  ui_move_pointer(int x, int y)
2656          XWarpPointer(g_display, g_wnd, g_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                    if (g_bpp == 24)
2676                            bitmap_pad = 32;
2677            }
2678    
2679          tdata = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2680          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2681          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2682                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2683    
2684          XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2685    
2686          XFree(image);          XFree(image);
2687          if (!g_owncolmap)          if (tdata != data)
2688                  xfree(tdata);                  xfree(tdata);
2689          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2690  }  }
2691    
2692  void  void
# Line 1087  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            if (g_server_depth == 8)
2700            {
2701                    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          tdata = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2712          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2713                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2714    
2715          if (g_ownbackstore)          if (g_ownbackstore)
2716          {          {
2717                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2718                  XCopyArea(g_display, g_backstore, g_wnd, g_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(g_display, g_wnd, g_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 (!g_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(g_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(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2752          gc = XCreateGC(g_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(g_display, g_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);
# Line 1131  ui_create_glyph(int width, int height, u Line 2758  ui_create_glyph(int width, int height, u
2758          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2759          XInitImage(image);          XInitImage(image);
2760    
2761          XPutImage(g_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(g_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(g_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 1212  ui_create_cursor(unsigned int x, unsigne Line 2838  ui_create_cursor(unsigned int x, unsigne
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  void
2845  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2846  {  {
2847          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2848          XDefineCursor(g_display, g_wnd, g_current_cursor);          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_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2854  {  {
2855          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2856  }  }
2857    
2858    void
2859    ui_set_null_cursor(void)
2860    {
2861            ui_set_cursor(g_null_cursor);
2862    }
2863    
2864  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
2865                  (xc)->red   = ((c)->red   << 8) | (c)->red; \                  (xc)->red   = ((c)->red   << 8) | (c)->red; \
2866                  (xc)->green = ((c)->green << 8) | (c)->green; \                  (xc)->green = ((c)->green << 8) | (c)->green; \
# Line 1235  ui_destroy_cursor(HCURSOR cursor) Line 2868  ui_destroy_cursor(HCURSOR cursor)
2868                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2869    
2870    
2871  HCOLOURMAP  RD_HCOLOURMAP
2872  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2873  {  {
2874          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1309  ui_create_colourmap(COLOURMAP * colours) Line 2942  ui_create_colourmap(COLOURMAP * colours)
2942    
2943                          }                          }
2944    
2945                            map[i] = colour;
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
2946                  }                  }
2947                  return map;                  return map;
2948          }          }
# Line 1333  ui_create_colourmap(COLOURMAP * colours) Line 2964  ui_create_colourmap(COLOURMAP * colours)
2964                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2965    
2966                  xfree(xcolours);                  xfree(xcolours);
2967                  return (HCOLOURMAP) map;                  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 (!g_owncolmap)          if (!g_owncolmap)
2975                  xfree(map);                  xfree(map);
# Line 1347  ui_destroy_colourmap(HCOLOURMAP map) Line 2978  ui_destroy_colourmap(HCOLOURMAP map)
2978  }  }
2979    
2980  void  void
2981  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2982  {  {
2983          if (!g_owncolmap)          if (!g_owncolmap)
2984          {          {
# Line 1357  ui_set_colourmap(HCOLOURMAP map) Line 2988  ui_set_colourmap(HCOLOURMAP map)
2988                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2989          }          }
2990          else          else
2991            {
2992                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  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(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
3005  }  }
3006    
3007  void  void
3008  ui_reset_clip(void)  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 = g_width;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = g_height;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
3015  }  }
3016    
3017  void  void
# Line 1422  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;                          break;
3057    
3058                  case 2: /* Hatch */                  case 2: /* Hatch */
3059                          fill = (Pixmap) ui_create_glyph(8, 8,                          fill = (Pixmap) ui_create_glyph(8, 8,
3060                                                          hatch_patterns + brush->pattern[0] * 8);                                                          hatch_patterns + brush->pattern[0] * 8);
3061                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(fgcolour);
3062                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(bgcolour);
3063                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3064                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
3065                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3066                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3067                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3068                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3069                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3070                          break;                          break;
3071    
3072                  case 3: /* Pattern */                  case 3: /* Pattern */
3073                          for (i = 0; i != 8; i++)                          if (brush->bd == 0)     /* rdp4 brush */
3074                                  ipattern[7 - i] = brush->pattern[i];                          {
3075                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                                  for (i = 0; i != 8; i++)
3076                                            ipattern[7 - i] = brush->pattern[i];
3077                          SET_FOREGROUND(bgcolour);                                  fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3078                          SET_BACKGROUND(fgcolour);                                  SET_FOREGROUND(bgcolour);
3079                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                                  SET_BACKGROUND(fgcolour);
3080                          XSetStipple(g_display, g_gc, fill);                                  XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3081                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                                  XSetStipple(g_display, g_gc, fill);
3082                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3083                          FILL_RECTANGLE(x, y, cx, cy);                                  FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3084                                    XSetFillStyle(g_display, g_gc, FillSolid);
3085                          XSetFillStyle(g_display, g_gc, FillSolid);                                  XSetTSOrigin(g_display, g_gc, 0, 0);
3086                          XSetTSOrigin(g_display, g_gc, 0, 0);                                  ui_destroy_glyph((RD_HGLYPH) fill);
3087                          ui_destroy_glyph((HGLYPH) fill);                          }
3088                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3089                            {
3090                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3091                                    XSetFillStyle(g_display, g_gc, FillTiled);
3092                                    XSetTile(g_display, g_gc, fill);
3093                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3094                                    FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3095                                    XSetFillStyle(g_display, g_gc, FillSolid);
3096                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3097                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3098                            }
3099                            else
3100                            {
3101                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3102                                    SET_FOREGROUND(bgcolour);
3103                                    SET_BACKGROUND(fgcolour);
3104                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3105                                    XSetStipple(g_display, g_gc, fill);
3106                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3107                                    FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3108                                    XSetFillStyle(g_display, g_gc, FillSolid);
3109                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3110                                    ui_destroy_glyph((RD_HGLYPH) fill);
3111                            }
3112                          break;                          break;
3113    
3114                  default:                  default:
# Line 1462  ui_patblt(uint8 opcode, Line 3116  ui_patblt(uint8 opcode,
3116          }          }
3117    
3118          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3119    
3120            if (g_ownbackstore)
3121                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3122            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3123                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3124                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3125  }  }
3126    
3127  void  void
# Line 1470  ui_screenblt(uint8 opcode, Line 3130  ui_screenblt(uint8 opcode,
3130               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
3131  {  {
3132          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
         XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
3133          if (g_ownbackstore)          if (g_ownbackstore)
3134            {
3135                    XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3136                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3137                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3138            }
3139            else
3140            {
3141                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3142            }
3143    
3144            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3145                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3146                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3147    
3148          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3149  }  }
3150    
3151  void  void
3152  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3153            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3154            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3155  {  {
3156          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3157          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3158            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3159                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3160                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3161          if (g_ownbackstore)          if (g_ownbackstore)
3162                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3163          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1491  ui_memblt(uint8 opcode, Line 3166  ui_memblt(uint8 opcode,
3166  void  void
3167  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3168            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3169            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3170            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3171  {  {
3172          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1529  ui_line(uint8 opcode, Line 3204  ui_line(uint8 opcode,
3204          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3205          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3206          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3207            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3208                                                startx - sw->xoffset, starty - sw->yoffset,
3209                                                endx - sw->xoffset, endy - sw->yoffset));
3210          if (g_ownbackstore)          if (g_ownbackstore)
3211                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3212          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1543  ui_rect( Line 3221  ui_rect(
3221          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
3222  }  }
3223    
3224    void
3225    ui_polygon(uint8 opcode,
3226               /* mode */ uint8 fillmode,
3227               /* dest */ RD_POINT * point, int npoints,
3228               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3229    {
3230            uint8 style, i, ipattern[8];
3231            Pixmap fill;
3232    
3233            SET_FUNCTION(opcode);
3234    
3235            switch (fillmode)
3236            {
3237                    case ALTERNATE:
3238                            XSetFillRule(g_display, g_gc, EvenOddRule);
3239                            break;
3240                    case WINDING:
3241                            XSetFillRule(g_display, g_gc, WindingRule);
3242                            break;
3243                    default:
3244                            unimpl("fill mode %d\n", fillmode);
3245            }
3246    
3247            if (brush)
3248                    style = brush->style;
3249            else
3250                    style = 0;
3251    
3252            switch (style)
3253            {
3254                    case 0: /* Solid */
3255                            SET_FOREGROUND(fgcolour);
3256                            FILL_POLYGON((XPoint *) point, npoints);
3257                            break;
3258    
3259                    case 2: /* Hatch */
3260                            fill = (Pixmap) ui_create_glyph(8, 8,
3261                                                            hatch_patterns + brush->pattern[0] * 8);
3262                            SET_FOREGROUND(fgcolour);
3263                            SET_BACKGROUND(bgcolour);
3264                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3265                            XSetStipple(g_display, g_gc, fill);
3266                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3267                            FILL_POLYGON((XPoint *) point, npoints);
3268                            XSetFillStyle(g_display, g_gc, FillSolid);
3269                            XSetTSOrigin(g_display, g_gc, 0, 0);
3270                            ui_destroy_glyph((RD_HGLYPH) fill);
3271                            break;
3272    
3273                    case 3: /* Pattern */
3274                            if (brush->bd == 0)     /* rdp4 brush */
3275                            {
3276                                    for (i = 0; i != 8; i++)
3277                                            ipattern[7 - i] = brush->pattern[i];
3278                                    fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3279                                    SET_FOREGROUND(bgcolour);
3280                                    SET_BACKGROUND(fgcolour);
3281                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3282                                    XSetStipple(g_display, g_gc, fill);
3283                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3284                                    FILL_POLYGON((XPoint *) point, npoints);
3285                                    XSetFillStyle(g_display, g_gc, FillSolid);
3286                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3287                                    ui_destroy_glyph((RD_HGLYPH) fill);
3288                            }
3289                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3290                            {
3291                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3292                                    XSetFillStyle(g_display, g_gc, FillTiled);
3293                                    XSetTile(g_display, g_gc, fill);
3294                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3295                                    FILL_POLYGON((XPoint *) point, npoints);
3296                                    XSetFillStyle(g_display, g_gc, FillSolid);
3297                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3298                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3299                            }
3300                            else
3301                            {
3302                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3303                                    SET_FOREGROUND(bgcolour);
3304                                    SET_BACKGROUND(fgcolour);
3305                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3306                                    XSetStipple(g_display, g_gc, fill);
3307                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3308                                    FILL_POLYGON((XPoint *) point, npoints);
3309                                    XSetFillStyle(g_display, g_gc, FillSolid);
3310                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3311                                    ui_destroy_glyph((RD_HGLYPH) fill);
3312                            }
3313                            break;
3314    
3315                    default:
3316                            unimpl("brush %d\n", brush->style);
3317            }
3318    
3319            RESET_FUNCTION(opcode);
3320    }
3321    
3322    void
3323    ui_polyline(uint8 opcode,
3324                /* dest */ RD_POINT * points, int npoints,
3325                /* pen */ PEN * pen)
3326    {
3327            /* TODO: set join style */
3328            SET_FUNCTION(opcode);
3329            SET_FOREGROUND(pen->colour);
3330            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
3331            if (g_ownbackstore)
3332                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3333                               CoordModePrevious);
3334    
3335            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3336                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3337    
3338            RESET_FUNCTION(opcode);
3339    }
3340    
3341    void
3342    ui_ellipse(uint8 opcode,
3343               /* mode */ uint8 fillmode,
3344               /* dest */ int x, int y, int cx, int cy,
3345               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3346    {
3347            uint8 style, i, ipattern[8];
3348            Pixmap fill;
3349    
3350            SET_FUNCTION(opcode);
3351    
3352            if (brush)
3353                    style = brush->style;
3354            else
3355                    style = 0;
3356    
3357            switch (style)
3358            {
3359                    case 0: /* Solid */
3360                            SET_FOREGROUND(fgcolour);
3361                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3362                            break;
3363    
3364                    case 2: /* Hatch */
3365                            fill = (Pixmap) ui_create_glyph(8, 8,
3366                                                            hatch_patterns + brush->pattern[0] * 8);
3367                            SET_FOREGROUND(fgcolour);
3368                            SET_BACKGROUND(bgcolour);
3369                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3370                            XSetStipple(g_display, g_gc, fill);
3371                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3372                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3373                            XSetFillStyle(g_display, g_gc, FillSolid);
3374                            XSetTSOrigin(g_display, g_gc, 0, 0);
3375                            ui_destroy_glyph((RD_HGLYPH) fill);
3376                            break;
3377    
3378                    case 3: /* Pattern */
3379                            if (brush->bd == 0)     /* rdp4 brush */
3380                            {
3381                                    for (i = 0; i != 8; i++)
3382                                            ipattern[7 - i] = brush->pattern[i];
3383                                    fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3384                                    SET_FOREGROUND(bgcolour);
3385                                    SET_BACKGROUND(fgcolour);
3386                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3387                                    XSetStipple(g_display, g_gc, fill);
3388                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3389                                    DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3390                                    XSetFillStyle(g_display, g_gc, FillSolid);
3391                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3392                                    ui_destroy_glyph((RD_HGLYPH) fill);
3393                            }
3394                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3395                            {
3396                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3397                                    XSetFillStyle(g_display, g_gc, FillTiled);
3398                                    XSetTile(g_display, g_gc, fill);
3399                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3400                                    DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3401                                    XSetFillStyle(g_display, g_gc, FillSolid);
3402                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3403                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3404                            }
3405                            else
3406                            {
3407                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3408                                    SET_FOREGROUND(bgcolour);
3409                                    SET_BACKGROUND(fgcolour);
3410                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3411                                    XSetStipple(g_display, g_gc, fill);
3412                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3413                                    DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3414                                    XSetFillStyle(g_display, g_gc, FillSolid);
3415                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3416                                    ui_destroy_glyph((RD_HGLYPH) fill);
3417                            }
3418                            break;
3419    
3420                    default:
3421                            unimpl("brush %d\n", brush->style);
3422            }
3423    
3424            RESET_FUNCTION(opcode);
3425    }
3426    
3427  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3428  void  void
3429  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3430                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3431                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3432                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3433  {  {
3434          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1567  ui_draw_glyph(int mixmode, Line 3448  ui_draw_glyph(int mixmode,
3448  {\  {\
3449    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3450    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3451      {\
3452        xyoffset = ttext[++idx];\
3453        if ((xyoffset & 0x80))\
3454      {\      {\
3455        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3456        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;\  
         }\  
3457        else\        else\
3458          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3459            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3460      }\      }\
3461    if (glyph != NULL)\      else\
3462      {\      {\
3463        ui_draw_glyph (mixmode, x + glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3464                       y + glyph->baseline,\          y += xyoffset;\
3465                       glyph->width, glyph->height,\        else\
3466                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3467      }\      }\
3468      }\
3469      if (glyph != NULL)\
3470      {\
3471        x1 = x + glyph->offset;\
3472        y1 = y + glyph->baseline;\
3473        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3474        XSetTSOrigin(g_display, g_gc, x1, y1);\
3475        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3476        if (flags & TEXT2_IMPLICIT_X)\
3477          x += glyph->width;\
3478      }\
3479  }  }
3480    
3481  void  void
3482  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,
3483               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3484               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3485               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3486  {  {
3487            /* TODO: use brush appropriately */
3488    
3489          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3490          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3491          DATABLOB *entry;          DATABLOB *entry;
3492    
3493          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3494    
3495            /* Sometimes, the boxcx value is something really large, like
3496               32691. This makes XCopyArea fail with Xvnc. The code below
3497               is a quick fix. */
3498            if (boxx + boxcx > g_width)
3499                    boxcx = g_width - boxx;
3500    
3501          if (boxcx > 1)          if (boxcx > 1)
3502          {          {
3503                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
# Line 1617  ui_draw_text(uint8 font, uint8 flags, in Line 3507  ui_draw_text(uint8 font, uint8 flags, in
3507                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3508          }          }
3509    
3510            SET_FOREGROUND(fgcolour);
3511            SET_BACKGROUND(bgcolour);
3512            XSetFillStyle(g_display, g_gc, FillStippled);
3513    
3514          /* Paint text, character by character */          /* Paint text, character by character */
3515          for (i = 0; i < length;)          for (i = 0; i < length;)
3516          {          {
3517                  switch (text[i])                  switch (text[i])
3518                  {                  {
3519                          case 0xff:                          case 0xff:
3520                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3521                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3522                                  {                                  {
3523                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3524                                          exit(1);                                          for (j = 0; j < length; j++)
3525                                                    fprintf(stderr, "%02x ", text[j]);
3526                                            fprintf(stderr, "\n");
3527                                            i = length = 0;
3528                                            break;
3529                                  }                                  }
3530                                    cache_put_text(text[i + 1], text, text[i + 2]);
3531                                    i += 3;
3532                                    length -= i;
3533                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3534                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3535                                  i = 0;                                  i = 0;
3536                                  break;                                  break;
3537    
3538                          case 0xfe:                          case 0xfe:
3539                                    /* At least one byte needs to follow */
3540                                    if (i + 2 > length)
3541                                    {
3542                                            warning("Skipping short 0xfe command:");
3543                                            for (j = 0; j < length; j++)
3544                                                    fprintf(stderr, "%02x ", text[j]);
3545                                            fprintf(stderr, "\n");
3546                                            i = length = 0;
3547                                            break;
3548                                    }
3549                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3550                                  if (entry != NULL)                                  if (entry->data != NULL)
3551                                  {                                  {
3552                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3553                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3554                                          {                                          {
3555                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3556                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 1667  ui_draw_text(uint8 font, uint8 flags, in Line 3576  ui_draw_text(uint8 font, uint8 flags, in
3576                                  break;                                  break;
3577                  }                  }
3578          }          }
3579    
3580            XSetFillStyle(g_display, g_gc, FillSolid);
3581    
3582          if (g_ownbackstore)          if (g_ownbackstore)
3583          {          {
3584                  if (boxcx > 1)                  if (boxcx > 1)
3585                    {
3586                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3587                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3588                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3589                                                    (g_display, g_backstore, sw->wnd, g_gc,
3590                                                     boxx, boxy,
3591                                                     boxcx, boxcy,
3592                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3593                    }
3594                  else                  else
3595                    {
3596                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3597                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3598                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3599                                                    (g_display, g_backstore, sw->wnd, g_gc,
3600                                                     clipx, clipy,
3601                                                     clipcx, clipcy, clipx - sw->xoffset,
3602                                                     clipy - sw->yoffset));
3603                    }
3604          }          }
3605  }  }
3606    
# Line 1687  ui_desktop_save(uint32 offset, int x, in Line 3613  ui_desktop_save(uint32 offset, int x, in
3613          if (g_ownbackstore)          if (g_ownbackstore)
3614          {          {
3615                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3616                    exit_if_null(image);
3617          }          }
3618          else          else
3619          {          {
3620                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3621                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3622                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3623                    exit_if_null(image);
3624                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3625          }          }
3626    
# Line 1714  ui_desktop_restore(uint32 offset, int x, Line 3642  ui_desktop_restore(uint32 offset, int x,
3642                  return;                  return;
3643    
3644          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3645                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3646    
3647          if (g_ownbackstore)          if (g_ownbackstore)
3648          {          {
3649                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3650                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3651                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3652                                            (g_display, g_backstore, sw->wnd, g_gc,
3653                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3654          }          }
3655          else          else
3656          {          {
3657                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3658                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3659                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3660                                             x - sw->xoffset, y - sw->yoffset));
3661          }          }
3662    
3663          XFree(image);          XFree(image);
3664  }  }
3665    
3666    /* these do nothing here but are used in uiports */
3667    void
3668    ui_begin_update(void)
3669    {
3670    }
3671    
3672    void
3673    ui_end_update(void)
3674    {
3675    }
3676    
3677    
3678    void
3679    ui_seamless_begin(RD_BOOL hidden)
3680    {
3681            if (!g_seamless_rdp)
3682                    return;
3683    
3684            if (g_seamless_started)
3685                    return;
3686    
3687            g_seamless_started = True;
3688            g_seamless_hidden = hidden;
3689    
3690            if (!hidden)
3691                    ui_seamless_toggle();
3692    }
3693    
3694    
3695    void
3696    ui_seamless_hide_desktop()
3697    {
3698            if (!g_seamless_rdp)
3699                    return;
3700    
3701            if (!g_seamless_started)
3702                    return;
3703    
3704            if (g_seamless_active)
3705                    ui_seamless_toggle();
3706    
3707            g_seamless_hidden = True;
3708    }
3709    
3710    
3711    void
3712    ui_seamless_unhide_desktop()
3713    {
3714            if (!g_seamless_rdp)
3715                    return;
3716    
3717            if (!g_seamless_started)
3718                    return;
3719    
3720            g_seamless_hidden = False;
3721    
3722            ui_seamless_toggle();
3723    }
3724    
3725    
3726    void
3727    ui_seamless_toggle()
3728    {
3729            if (!g_seamless_rdp)
3730                    return;
3731    
3732            if (!g_seamless_started)
3733                    return;
3734    
3735            if (g_seamless_hidden)
3736                    return;
3737    
3738            if (g_seamless_active)
3739            {
3740                    /* Deactivate */
3741                    while (g_seamless_windows)
3742                    {
3743                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3744                            sw_remove_window(g_seamless_windows);
3745                    }
3746                    XMapWindow(g_display, g_wnd);
3747            }
3748            else
3749            {
3750                    /* Activate */
3751                    XUnmapWindow(g_display, g_wnd);
3752                    seamless_send_sync();
3753            }
3754    
3755            g_seamless_active = !g_seamless_active;
3756    }
3757    
3758    
3759    void
3760    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3761                              unsigned long flags)
3762    {
3763            Window wnd;
3764            XSetWindowAttributes attribs;
3765            XClassHint *classhints;
3766            XSizeHints *sizehints;
3767            XWMHints *wmhints;
3768            long input_mask;
3769            seamless_window *sw, *sw_parent;
3770    
3771            if (!g_seamless_active)
3772                    return;
3773    
3774            /* Ignore CREATEs for existing windows */
3775            sw = sw_get_window_by_id(id);
3776            if (sw)
3777                    return;
3778    
3779            get_window_attribs(&attribs);
3780            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3781                                InputOutput, g_visual,
3782                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3783    
3784            XStoreName(g_display, wnd, "SeamlessRDP");
3785            ewmh_set_wm_name(wnd, "SeamlessRDP");
3786    
3787            mwm_hide_decorations(wnd);
3788    
3789            classhints = XAllocClassHint();
3790            if (classhints != NULL)
3791            {
3792                    classhints->res_name = "rdesktop";
3793                    classhints->res_class = "SeamlessRDP";
3794                    XSetClassHint(g_display, wnd, classhints);
3795                    XFree(classhints);
3796            }
3797    
3798            /* WM_NORMAL_HINTS */
3799            sizehints = XAllocSizeHints();
3800            if (sizehints != NULL)
3801            {
3802                    sizehints->flags = USPosition;
3803                    XSetWMNormalHints(g_display, wnd, sizehints);
3804                    XFree(sizehints);
3805            }
3806    
3807            /* Parent-less transient windows */
3808            if (parent == 0xFFFFFFFF)
3809            {
3810                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3811                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3812                       using some other hints. */
3813                    ewmh_set_window_popup(wnd);
3814            }
3815            /* Normal transient windows */
3816            else if (parent != 0x00000000)
3817            {
3818                    sw_parent = sw_get_window_by_id(parent);
3819                    if (sw_parent)
3820                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3821                    else
3822                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3823            }
3824    
3825            if (flags & SEAMLESSRDP_CREATE_MODAL)
3826            {
3827                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3828                       somewhat at least */
3829                    if (parent == 0x00000000)
3830                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3831                    ewmh_set_window_modal(wnd);
3832            }
3833    
3834            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3835            {
3836                    /* Make window always-on-top */
3837                    ewmh_set_window_above(wnd);
3838            }
3839    
3840            /* FIXME: Support for Input Context:s */
3841    
3842            get_input_mask(&input_mask);
3843            input_mask |= PropertyChangeMask;
3844    
3845            XSelectInput(g_display, wnd, input_mask);
3846    
3847            /* handle the WM_DELETE_WINDOW protocol. */
3848            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3849    
3850            sw = xmalloc(sizeof(seamless_window));
3851    
3852            memset(sw, 0, sizeof(seamless_window));
3853    
3854            sw->wnd = wnd;
3855            sw->id = id;
3856            sw->group = sw_find_group(group, False);
3857            sw->group->refcnt++;
3858            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3859            sw->desktop = 0;
3860            sw->position_timer = xmalloc(sizeof(struct timeval));
3861            timerclear(sw->position_timer);
3862    
3863            sw->outstanding_position = False;
3864            sw->outpos_serial = 0;
3865            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3866            sw->outpos_width = sw->outpos_height = 0;
3867    
3868            sw->next = g_seamless_windows;
3869            g_seamless_windows = sw;
3870    
3871            /* WM_HINTS */
3872            wmhints = XAllocWMHints();
3873            if (wmhints)
3874            {
3875                    wmhints->flags = WindowGroupHint;
3876                    wmhints->window_group = sw->group->wnd;
3877                    XSetWMHints(g_display, sw->wnd, wmhints);
3878                    XFree(wmhints);
3879            }
3880    }
3881    
3882    
3883    void
3884    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3885    {
3886            seamless_window *sw;
3887    
3888            if (!g_seamless_active)
3889                    return;
3890    
3891            sw = sw_get_window_by_id(id);
3892            if (!sw)
3893            {
3894                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3895                    return;
3896            }
3897    
3898            XDestroyWindow(g_display, sw->wnd);
3899            sw_remove_window(sw);
3900    }
3901    
3902    
3903    void
3904    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3905    {
3906            seamless_window *sw, *sw_next;
3907    
3908            if (!g_seamless_active)
3909                    return;
3910    
3911            for (sw = g_seamless_windows; sw; sw = sw_next)
3912            {
3913                    sw_next = sw->next;
3914    
3915                    if (sw->group->id == id)
3916                    {
3917                            XDestroyWindow(g_display, sw->wnd);
3918                            sw_remove_window(sw);
3919                    }
3920            }
3921    }
3922    
3923    
3924    void
3925    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3926                        const char *data, int chunk_len)
3927    {
3928            seamless_window *sw;
3929    
3930            if (!g_seamless_active)
3931                    return;
3932    
3933            sw = sw_get_window_by_id(id);
3934            if (!sw)
3935            {
3936                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3937                    return;
3938            }
3939    
3940            if (chunk == 0)
3941            {
3942                    if (sw->icon_size)
3943                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3944    
3945                    if (strcmp(format, "RGBA") != 0)
3946                    {
3947                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3948                            return;
3949                    }
3950    
3951                    sw->icon_size = width * height * 4;
3952                    if (sw->icon_size > 32 * 32 * 4)
3953                    {
3954                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3955                            sw->icon_size = 0;
3956                            return;
3957                    }
3958    
3959                    sw->icon_offset = 0;
3960            }
3961            else
3962            {
3963                    if (!sw->icon_size)
3964                            return;
3965            }
3966    
3967            if (chunk_len > (sw->icon_size - sw->icon_offset))
3968            {
3969                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3970                            chunk_len, sw->icon_size - sw->icon_offset);
3971                    sw->icon_size = 0;
3972                    return;
3973            }
3974    
3975            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3976            sw->icon_offset += chunk_len;
3977    
3978            if (sw->icon_offset == sw->icon_size)
3979            {
3980                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3981                    sw->icon_size = 0;
3982            }
3983    }
3984    
3985    
3986    void
3987    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3988    {
3989            seamless_window *sw;
3990    
3991            if (!g_seamless_active)
3992                    return;
3993    
3994            sw = sw_get_window_by_id(id);
3995            if (!sw)
3996            {
3997                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3998                    return;
3999            }
4000    
4001            if (strcmp(format, "RGBA") != 0)
4002            {
4003                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
4004                    return;
4005            }
4006    
4007            ewmh_del_icon(sw->wnd, width, height);
4008    }
4009    
4010    
4011    void
4012    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
4013    {
4014            seamless_window *sw;
4015    
4016            if (!g_seamless_active)
4017                    return;
4018    
4019            sw = sw_get_window_by_id(id);
4020            if (!sw)
4021            {
4022                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
4023                    return;
4024            }
4025    
4026            /* We ignore server updates until it has handled our request. */
4027            if (sw->outstanding_position)
4028                    return;
4029    
4030            if (!width || !height)
4031                    /* X11 windows must be at least 1x1 */
4032                    return;
4033    
4034            sw->xoffset = x;
4035            sw->yoffset = y;
4036            sw->width = width;
4037            sw->height = height;
4038    
4039            /* If we move the window in a maximized state, then KDE won't
4040               accept restoration */
4041            switch (sw->state)
4042            {
4043                    case SEAMLESSRDP_MINIMIZED:
4044                    case SEAMLESSRDP_MAXIMIZED:
4045                            return;
4046            }
4047    
4048            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
4049            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
4050    }
4051    
4052    
4053    void
4054    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
4055    {
4056            seamless_window *sw;
4057            XWindowChanges values;
4058            unsigned long restack_serial;
4059    
4060            if (!g_seamless_active)
4061                    return;
4062    
4063            sw = sw_get_window_by_id(id);
4064            if (!sw)
4065            {
4066                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
4067                    return;
4068            }
4069    
4070            if (behind)
4071            {
4072                    seamless_window *sw_behind;
4073    
4074                    sw_behind = sw_get_window_by_id(behind);
4075                    if (!sw_behind)
4076                    {
4077                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
4078                            return;
4079                    }
4080    
4081                    if (!g_seamless_broken_restack)
4082                    {
4083                            values.stack_mode = Below;
4084                            values.sibling = sw_behind->wnd;
4085                            restack_serial = XNextRequest(g_display);
4086                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
4087                                                 CWStackMode | CWSibling, &values);
4088                            sw_wait_configurenotify(sw->wnd, restack_serial);
4089                    }
4090            }
4091            else
4092            {
4093                    values.stack_mode = Above;
4094                    restack_serial = XNextRequest(g_display);
4095                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4096                                         &values);
4097                    sw_wait_configurenotify(sw->wnd, restack_serial);
4098            }
4099    
4100            sw_restack_window(sw, behind);
4101    
4102            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4103            {
4104                    /* Make window always-on-top */
4105                    ewmh_set_window_above(sw->wnd);
4106            }
4107    }
4108    
4109    
4110    void
4111    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4112    {
4113            seamless_window *sw;
4114    
4115            if (!g_seamless_active)
4116                    return;
4117    
4118            sw = sw_get_window_by_id(id);
4119            if (!sw)
4120            {
4121                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4122                    return;
4123            }
4124    
4125            /* FIXME: Might want to convert the name for non-EWMH WMs */
4126            XStoreName(g_display, sw->wnd, title);
4127            ewmh_set_wm_name(sw->wnd, title);
4128    }
4129    
4130    
4131    void
4132    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
4133    {
4134            seamless_window *sw;
4135    
4136            if (!g_seamless_active)
4137                    return;
4138    
4139            sw = sw_get_window_by_id(id);
4140            if (!sw)
4141            {
4142                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
4143                    return;
4144            }
4145    
4146            switch (state)
4147            {
4148                    case SEAMLESSRDP_NORMAL:
4149                    case SEAMLESSRDP_MAXIMIZED:
4150                            ewmh_change_state(sw->wnd, state);
4151                            XMapWindow(g_display, sw->wnd);
4152                            break;
4153                    case SEAMLESSRDP_MINIMIZED:
4154                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4155                               the Window Manager should probably just ignore the request, since
4156                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4157                               such as minimization, rather than an independent state." Besides,
4158                               XIconifyWindow is easier. */
4159                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4160                            {
4161                                    XWMHints *hints;
4162                                    hints = XGetWMHints(g_display, sw->wnd);
4163                                    if (hints)
4164                                    {
4165                                            hints->flags |= StateHint;
4166                                            hints->initial_state = IconicState;
4167                                            XSetWMHints(g_display, sw->wnd, hints);
4168                                            XFree(hints);
4169                                    }
4170                                    XMapWindow(g_display, sw->wnd);
4171                            }
4172                            else
4173                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4174                            break;
4175                    default:
4176                            warning("SeamlessRDP: Invalid state %d\n", state);
4177                            break;
4178            }
4179    
4180            sw->state = state;
4181    }
4182    
4183    
4184    void
4185    ui_seamless_syncbegin(unsigned long flags)
4186    {
4187            if (!g_seamless_active)
4188                    return;
4189    
4190            /* Destroy all seamless windows */
4191            while (g_seamless_windows)
4192            {
4193                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4194                    sw_remove_window(g_seamless_windows);
4195            }
4196    }
4197    
4198    
4199    void
4200    ui_seamless_ack(unsigned int serial)
4201    {
4202            seamless_window *sw;
4203            for (sw = g_seamless_windows; sw; sw = sw->next)
4204            {
4205                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4206                    {
4207                            sw->xoffset = sw->outpos_xoffset;
4208                            sw->yoffset = sw->outpos_yoffset;
4209                            sw->width = sw->outpos_width;
4210                            sw->height = sw->outpos_height;
4211                            sw->outstanding_position = False;
4212    
4213                            /* Do a complete redraw of the window as part of the
4214                               completion of the move. This is to remove any
4215                               artifacts caused by our lack of synchronization. */
4216                            XCopyArea(g_display, g_backstore,
4217                                      sw->wnd, g_gc,
4218                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4219    
4220                            break;
4221                    }
4222            }
4223    }

Legend:
Removed from v.450  
changed lines
  Added in v.1485

  ViewVC Help
Powered by ViewVC 1.1.26