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

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

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

revision 691 by astrand, Thu May 6 08:17:47 2004 UTC revision 1461 by astrand, Wed Mar 26 17:16:32 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-2007
5       Copyright 2007 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>  #include <unistd.h>
26  #include <sys/time.h>  #include <sys/time.h>
27  #include <time.h>  #include <time.h>
# Line 30  Line 32 
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;
47    
48  Display *g_display;  Display *g_display;
# Line 43  Time g_last_gesturetime; Line 50  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    
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;  extern uint32 g_embed_wnd;
93  BOOL g_enable_compose = False;  RD_BOOL g_enable_compose = False;
94  BOOL g_Unobscured;              /* used for screenblt */  RD_BOOL g_Unobscured;           /* used for screenblt */
95  static GC g_gc = NULL;  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[16];
114  static Cursor g_current_cursor;  static Cursor g_current_cursor;
115  static HCURSOR g_null_cursor = NULL;  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  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
118  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
119  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  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;  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;  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
145    
146  /* software backing store */  /* software backing store */
147  extern BOOL g_ownbackstore;  extern RD_BOOL g_ownbackstore;
148  static Pixmap g_backstore = 0;  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  #ifdef WITH_RDPSND
157  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
158  #endif  #endif
159    
160  /* MWM decorations */  /* MWM decorations */
# Line 86  extern BOOL g_rdpsnd; Line 162  extern BOOL g_rdpsnd;
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 102  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 115  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  extern BOOL g_owncolmap;  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 : 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 146  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
359    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  static void
431  mwm_hide_decorations(void)  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 164  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
534  split_colour15(uint32 colour)  {
535            Window window;
536            unsigned long serial;
537    } sw_configurenotify_context;
538    
539    /* Predicate procedure for sw_wait_configurenotify */
540    static Bool
541    sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg)
542    {
543            sw_configurenotify_context *context = (sw_configurenotify_context *) arg;
544            if (xevent->xany.type == ConfigureNotify
545                && xevent->xconfigure.window == context->window
546                && xevent->xany.serial >= context->serial)
547                    return True;
548    
549            return False;
550    }
551    
552    /* Wait for a ConfigureNotify, with a equal or larger serial, on the
553       specified window. The event will be removed from the queue. We
554       could use XMaskEvent(StructureNotifyMask), but we would then risk
555       throwing away crucial events like DestroyNotify.
556    
557       After a ConfigureWindow, according to ICCCM section 4.1.5, we
558       should recieve a ConfigureNotify, either a real or synthetic
559       one. This indicates that the configure has been "completed".
560       However, some WMs such as several versions of Metacity fails to
561       send synthetic events. See bug
562       http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
563       timeout to avoid a hang. Tk uses the same approach. */
564    static void
565    sw_wait_configurenotify(Window wnd, unsigned long serial)
566  {  {
567          PixelColour rv;          XEvent xevent;
568          rv.red = (colour & 0x7c00) >> 7;          sw_configurenotify_context context;
569          rv.green = (colour & 0x03e0) >> 2;          struct timeval now;
570          rv.blue = (colour & 0x001f) << 3;          struct timeval nextsecond;
571          return rv;          RD_BOOL got = False;
572  }  
573            context.window = wnd;
574  static PixelColour          context.serial = serial;
575  split_colour16(uint32 colour)  
576  {          gettimeofday(&nextsecond, NULL);
577          PixelColour rv;          nextsecond.tv_sec += 1;
578          rv.red = (colour & 0xf800) >> 8;  
579          rv.green = (colour & 0x07e0) >> 3;          do
580          rv.blue = (colour & 0x001f) << 3;          {
581          return rv;                  if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context))
582  }                  {
583                            got = True;
584  static PixelColour                          break;
585  split_colour24(uint32 colour)                  }
586  {                  usleep(100000);
587          PixelColour rv;                  gettimeofday(&now, NULL);
588          rv.blue = (colour & 0xff0000) >> 16;          }
589          rv.green = (colour & 0x00ff00) >> 8;          while (timercmp(&now, &nextsecond, <));
590          rv.red = (colour & 0x0000ff);  
591          return rv;          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_colour(PixelColour pc)  static Window
599    sw_get_toplevel(Window wnd)
600  {  {
601          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          Window root, parent;
602                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          Window *child_list;
603                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));          unsigned int num_children;
604    
605            while (1)
606            {
607                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
608                    if (root == parent)
609                    {
610                            break;
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    
624    /* Check if wnd is already behind a window wrt stacking order */
625    static RD_BOOL
626    sw_window_is_behind(Window wnd, Window behind)
627    {
628            Window dummy1, dummy2;
629            Window *child_list;
630            unsigned int num_children;
631            unsigned int i;
632            RD_BOOL found_behind = False;
633            RD_BOOL found_wnd = False;
634    
635            wnd = sw_get_toplevel(wnd);
636            behind = sw_get_toplevel(behind);
637    
638            XQueryTree(g_display, RootWindowOfScreen(g_screen), &dummy1, &dummy2, &child_list,
639                       &num_children);
640    
641            for (i = num_children - 1; i >= 0; i--)
642            {
643                    if (child_list[i] == behind)
644                    {
645                            found_behind = True;
646                    }
647                    else if (child_list[i] == wnd)
648                    {
649                            found_wnd = True;
650                            break;
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    
672    /* Test if the window manager correctly handles window restacking. In
673       particular, we are testing if it's possible to place a window
674       between two other windows. Many WMs such as Metacity can only stack
675       windows on the top or bottom. The window creation should mostly
676       match ui_seamless_create_window. */
677    static void
678    seamless_restack_test()
679    {
680            /* The goal is to have the middle window between top and
681               bottom.  The middle window is initially at the top,
682               though. */
683            Window wnds[3];         /* top, middle and bottom */
684            int i;
685            XEvent xevent;
686            XWindowChanges values;
687            unsigned long restack_serial;
688    
689            for (i = 0; i < 3; i++)
690            {
691                    char name[64];
692                    wnds[i] =
693                            XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 20, 20,
694                                                0, 0, 0);
695                    snprintf(name, sizeof(name), "SeamlessRDP restack test - window %d", i);
696                    XStoreName(g_display, wnds[i], name);
697                    ewmh_set_wm_name(wnds[i], name);
698    
699                    /* Hide decorations. Often this means that no
700                       reparenting will be done, which makes the restack
701                       easier. Besides, we want to mimic our other
702                       seamless windows as much as possible. We must still
703                       handle the case with reparenting, though. */
704                    mwm_hide_decorations(wnds[i]);
705    
706                    /* Prevent windows from appearing in task bar */
707                    XSetTransientForHint(g_display, wnds[i], RootWindowOfScreen(g_screen));
708                    ewmh_set_window_popup(wnds[i]);
709    
710                    /* We need to catch MapNotify/ConfigureNotify */
711                    XSelectInput(g_display, wnds[i], StructureNotifyMask);
712            }
713    
714            /* Map Windows. Currently, we assume that XMapRaised places
715               the window on the top of the stack. Should be fairly safe;
716               the window is configured before it's mapped. */
717            XMapRaised(g_display, wnds[2]); /* bottom */
718            do
719            {
720                    XWindowEvent(g_display, wnds[2], StructureNotifyMask, &xevent);
721            }
722            while (xevent.type != MapNotify);
723            XMapRaised(g_display, wnds[0]); /* top */
724            do
725            {
726                    XWindowEvent(g_display, wnds[0], StructureNotifyMask, &xevent);
727            }
728            while (xevent.type != MapNotify);
729            XMapRaised(g_display, wnds[1]); /* middle */
730            do
731            {
732                    XWindowEvent(g_display, wnds[1], StructureNotifyMask, &xevent);
733            }
734            while (xevent.type != MapNotify);
735    
736            /* The stacking order should now be 1 - 0 - 2 */
737            if (!sw_window_is_behind(wnds[0], wnds[1]) || !sw_window_is_behind(wnds[2], wnds[1]))
738            {
739                    /* Ok, technically a WM is allowed to stack windows arbitrarily, but... */
740                    warning("Broken Window Manager: Unable to test window restacking\n");
741                    g_seamless_broken_restack = True;
742                    for (i = 0; i < 3; i++)
743                            XDestroyWindow(g_display, wnds[i]);
744                    return;
745            }
746    
747            /* Restack, using XReconfigureWMWindow, which should correctly
748               handle reparented windows as well as nonreparenting WMs. */
749            values.stack_mode = Below;
750            values.sibling = wnds[0];
751            restack_serial = XNextRequest(g_display);
752            XReconfigureWMWindow(g_display, wnds[1], DefaultScreen(g_display), CWStackMode | CWSibling,
753                                 &values);
754            sw_wait_configurenotify(wnds[1], restack_serial);
755    
756            /* Now verify that middle is behind top but not behind
757               bottom */
758            if (!sw_window_is_behind(wnds[1], wnds[0]))
759            {
760                    warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n");
761                    g_seamless_broken_restack = True;
762            }
763            else if (sw_window_is_behind(wnds[1], wnds[2]))
764            {
765                    warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n");
766                    g_seamless_broken_restack = True;
767            }
768    
769            /* Destroy windows */
770            for (i = 0; i < 3; i++)
771                    XDestroyWindow(g_display, wnds[i]);
772    }
773    
774    #define SPLITCOLOUR15(colour, rv) \
775    { \
776            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
777            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
778            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
779    }
780    
781    #define SPLITCOLOUR16(colour, rv) \
782    { \
783            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
784            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
785            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
786    } \
787    
788    #define SPLITCOLOUR24(colour, rv) \
789    { \
790            rv.blue = (colour & 0xff0000) >> 16; \
791            rv.green = (colour & 0x00ff00) >> 8; \
792            rv.red = (colour & 0x0000ff); \
793    }
794    
795    #define MAKECOLOUR(pc) \
796            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
797                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
798                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
799    
800  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
801  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 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          PixelColour pc;          PixelColour pc;
819          switch (g_server_bpp)          switch (g_server_depth)
820          {          {
821                  case 15:                  case 15:
822                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
823                          break;                          break;
824                  case 16:                  case 16:
825                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
826                          break;                          break;
827                  case 24:                  case 24:
828                          pc = split_colour24(colour);                  case 32:
829                            SPLITCOLOUR24(colour, pc);
830                            break;
831                    default:
832                            /* Avoid warning */
833                            pc.red = 0;
834                            pc.green = 0;
835                            pc.blue = 0;
836                          break;                          break;
837          }          }
838          return make_colour(pc);          return MAKECOLOUR(pc);
839  }  }
840    
841    /* indent is confused by UNROLL8 */
842    /* *INDENT-OFF* */
843    
844    /* repeat and unroll, similar to bitmap.c */
845    /* potentialy any of the following translate */
846    /* functions can use repeat but just doing */
847    /* the most common ones */
848    
849  #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }  #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
850  #define REPEAT(stm) \  /* 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) \          while (out <= end - 8 * 4) \
870                  UNROLL8(stm) \                  UNROLL8(stm) \
871          while (out < end) \          while (out < end) \
872                  { stm } \                  { 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, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
885  {  {
886          uint16 value;          uint16 value;
887    
888          if (g_arch_match)          if (g_compatible_arch)
889                  REPEAT(*(((uint16 *) out)++) = g_colmap[*(data++)];          {
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)          else if (g_xserver_be)
899          {          {
900                  while (out < end)                  while (out < end)
901                  {                  {
902                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
903                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
904                  }                  }
905          }          }
906          else          else
# Line 268  translate8to16(uint8 * data, uint8 * out Line 908  translate8to16(uint8 * data, uint8 * out
908                  while (out < end)                  while (out < end)
909                  {                  {
910                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
911                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
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          if (g_xserver_be)          if (g_compatible_arch)
923          {          {
924                  while (out < end)                  while (out < end)
925                  {                  {
926                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
927                          *(out++) = value >> 16;                          BOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
928                  }                  }
929          }          }
930          else          else
# Line 295  translate8to24(uint8 * data, uint8 * out Line 932  translate8to24(uint8 * data, uint8 * out
932                  while (out < end)                  while (out < end)
933                  {                  {
934                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
935                          *(out++) = value;                          LOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
936                  }                  }
937          }          }
938  }  }
939    
940  static void  static void
941  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
942  {  {
943          uint32 value;          uint32 value;
944    
945          if (g_arch_match)          if (g_compatible_arch)
946                  REPEAT(*(((uint32 *) out)++) = g_colmap[*(data++)];          {
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)          else if (g_xserver_be)
956          {          {
957                  while (out < end)                  while (out < end)
958                  {                  {
959                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
960                          *(out++) = value >> 24;                          BOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 8;  
                         *(out++) = value;  
961                  }                  }
962          }          }
963          else          else
# Line 326  translate8to32(uint8 * data, uint8 * out Line 965  translate8to32(uint8 * data, uint8 * out
965                  while (out < end)                  while (out < end)
966                  {                  {
967                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
968                          *(out++) = value;                          LOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
969                  }                  }
970          }          }
971  }  }
972    
973  static void  static void
974  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
975  {  {
976          uint16 pixel;          uint16 pixel;
977          uint16 value;          uint16 value;
978            PixelColour pc;
979    
980          while (out < end)          if (g_xserver_be)
981          {          {
982                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                         BSWAP16(pixel);  
                 }  
   
                 value = make_colour(split_colour15(pixel));  
   
                 if (g_xserver_be)  
983                  {                  {
984                          *(out++) = value >> 8;                          pixel = *(data++);
985                          *(out++) = value;                          if (g_host_be)
986                            {
987                                    BSWAP16(pixel);
988                            }
989                            SPLITCOLOUR15(pixel, pc);
990                            value = MAKECOLOUR(pc);
991                            BOUT16(out, value);
992                  }                  }
993                  else          }
994            else
995            {
996                    while (out < end)
997                  {                  {
998                          *(out++) = value;                          pixel = *(data++);
999                          *(out++) = value >> 8;                          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;          uint16 pixel;
1015            PixelColour pc;
1016    
1017          while (out < end)          if (g_compatible_arch)
1018          {          {
1019                  pixel = *(data++);                  /* *INDENT-OFF* */
1020                    REPEAT3
1021                  if (g_host_be)                  (
1022                  {                          pixel = *(data++);
1023                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
1024                  }                          *(out++) = pc.blue;
1025                            *(out++) = pc.green;
1026                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
1027                  if (g_xserver_be)                  )
1028                    /* *INDENT-ON* */
1029            }
1030            else if (g_xserver_be)
1031            {
1032                    while (out < end)
1033                  {                  {
1034                          *(out++) = value >> 16;                          pixel = *(data++);
1035                          *(out++) = value >> 8;                          if (g_host_be)
1036                          *(out++) = value;                          {
1037                                    BSWAP16(pixel);
1038                            }
1039                            SPLITCOLOUR15(pixel, pc);
1040                            value = MAKECOLOUR(pc);
1041                            BOUT24(out, value);
1042                  }                  }
1043                  else          }
1044            else
1045            {
1046                    while (out < end)
1047                  {                  {
1048                          *(out++) = value;                          pixel = *(data++);
1049                          *(out++) = value >> 8;                          if (g_host_be)
1050                          *(out++) = value >> 16;                          {
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, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
1062  {  {
1063          uint16 pixel;          uint16 pixel;
1064          uint32 value;          uint32 value;
1065            PixelColour pc;
1066    
1067          while (out < end)          if (g_compatible_arch)
1068          {          {
1069                  pixel = *(data++);                  /* *INDENT-OFF* */
1070                    REPEAT4
1071                  if (g_host_be)                  (
1072                  {                          pixel = *(data++);
1073                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
1074                  }                          *(out++) = pc.blue;
1075                            *(out++) = pc.green;
1076                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
1077                            *(out++) = 0;
1078                  if (g_xserver_be)                  )
1079                    /* *INDENT-ON* */
1080            }
1081            else if (g_xserver_be)
1082            {
1083                    while (out < end)
1084                  {                  {
1085                          *(out++) = value >> 24;                          pixel = *(data++);
1086                          *(out++) = value >> 16;                          if (g_host_be)
1087                          *(out++) = value >> 8;                          {
1088                          *(out++) = value;                                  BSWAP16(pixel);
1089                            }
1090                            SPLITCOLOUR15(pixel, pc);
1091                            value = MAKECOLOUR(pc);
1092                            BOUT32(out, value);
1093                  }                  }
1094                  else          }
1095            else
1096            {
1097                    while (out < end)
1098                  {                  {
1099                          *(out++) = value;                          pixel = *(data++);
1100                          *(out++) = value >> 8;                          if (g_host_be)
1101                          *(out++) = value >> 16;                          {
1102                          *(out++) = value >> 24;                                  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, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
1113  {  {
1114          uint16 pixel;          uint16 pixel;
1115          uint16 value;          uint16 value;
1116            PixelColour pc;
1117    
1118          while (out < end)          if (g_xserver_be)
1119          {          {
                 pixel = *(data++);  
   
1120                  if (g_host_be)                  if (g_host_be)
1121                  {                  {
1122                          BSWAP16(pixel);                          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
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
1132                  {                  {
1133                          *(out++) = value >> 8;                          while (out < end)
1134                          *(out++) = value;                          {
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                  else
1156                  {                  {
1157                          *(out++) = value;                          while (out < end)
1158                          *(out++) = value >> 8;                          {
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;          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          {          {
                 pixel = *(data++);  
   
1190                  if (g_host_be)                  if (g_host_be)
1191                  {                  {
1192                          BSWAP16(pixel);                          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
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
1202                  {                  {
1203                          *(out++) = value >> 16;                          while (out < end)
1204                          *(out++) = value >> 8;                          {
1205                          *(out++) = value;                                  pixel = *(data++);
1206                                    SPLITCOLOUR16(pixel, pc);
1207                                    value = MAKECOLOUR(pc);
1208                                    BOUT24(out, value);
1209                            }
1210                    }
1211            }
1212            else
1213            {
1214                    if (g_host_be)
1215                    {
1216                            while (out < end)
1217                            {
1218                                    pixel = *(data++);
1219                                    BSWAP16(pixel);
1220                                    SPLITCOLOUR16(pixel, pc);
1221                                    value = MAKECOLOUR(pc);
1222                                    LOUT24(out, value);
1223                            }
1224                  }                  }
1225                  else                  else
1226                  {                  {
1227                          *(out++) = value;                          while (out < end)
1228                          *(out++) = value >> 8;                          {
1229                          *(out++) = value >> 16;                                  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, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
1240  {  {
1241          uint16 pixel;          uint16 pixel;
1242          uint32 value;          uint32 value;
1243            PixelColour pc;
1244    
1245          while (out < end)          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          {          {
                 pixel = *(data++);  
   
1261                  if (g_host_be)                  if (g_host_be)
1262                  {                  {
1263                          BSWAP16(pixel);                          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                  value = make_colour(split_colour16(pixel));                  {
1274                            while (out < end)
1275                  if (g_xserver_be)                          {
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                          *(out++) = value >> 24;                          while (out < end)
1288                          *(out++) = value >> 16;                          {
1289                          *(out++) = value >> 8;                                  pixel = *(data++);
1290                          *(out++) = value;                                  BSWAP16(pixel);
1291                                    SPLITCOLOUR16(pixel, pc);
1292                                    value = MAKECOLOUR(pc);
1293                                    LOUT32(out, value);
1294                            }
1295                  }                  }
1296                  else                  else
1297                  {                  {
1298                          *(out++) = value;                          while (out < end)
1299                          *(out++) = value >> 8;                          {
1300                          *(out++) = value >> 16;                                  pixel = *(data++);
1301                          *(out++) = value >> 24;                                  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, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1311  {  {
1312          uint32 pixel = 0;          uint32 pixel = 0;
1313          uint16 value;          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                    SPLITCOLOUR24(pixel, pc);
1322                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1323                  if (g_xserver_be)                  if (g_xserver_be)
1324                  {                  {
1325                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1326                  }                  }
1327                  else                  else
1328                  {                  {
1329                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
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          uint32 pixel;          uint32 pixel;
1338          uint32 value;          uint32 value;
1339            PixelColour pc;
1340    
1341          while (out < end)          if (g_xserver_be)
1342          {          {
1343                  pixel = *(data++) << 16;                  while (out < end)
                 pixel |= *(data++) << 8;  
                 pixel |= *(data++);  
   
                 value = make_colour(split_colour24(pixel));  
   
                 if (g_xserver_be)  
1344                  {                  {
1345                          *(out++) = value >> 16;                          pixel = *(data++) << 16;
1346                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1347                          *(out++) = value;                          pixel |= *(data++);
1348                            SPLITCOLOUR24(pixel, pc);
1349                            value = MAKECOLOUR(pc);
1350                            BOUT24(out, value);
1351                  }                  }
1352                  else          }
1353            else
1354            {
1355                    while (out < end)
1356                  {                  {
1357                          *(out++) = value;                          pixel = *(data++) << 16;
1358                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1359                          *(out++) = value >> 16;                          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, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1369  {  {
1370          uint32 pixel;          uint32 pixel;
1371          uint32 value;          uint32 value;
1372            PixelColour pc;
1373    
1374          while (out < end)          if (g_compatible_arch)
1375          {          {
1376                  pixel = *(data++) << 16;                  /* *INDENT-OFF* */
1377                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
1378                  pixel |= *(data++);                  REPEAT4
1379                    (
1380                  value = make_colour(split_colour24(pixel));                          *(out++) = *(data++);
1381                            *(out++) = *(data++);
1382                  if (g_xserver_be)                          *(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                          *(out++) = value >> 24;                          pixel = *(data++) << 16;
1401                          *(out++) = value >> 16;                          pixel |= *(data++) << 8;
1402                          *(out++) = value >> 8;                          pixel |= *(data++);
1403                          *(out++) = value;                          SPLITCOLOUR24(pixel, pc);
1404                            value = MAKECOLOUR(pc);
1405                            BOUT32(out, value);
1406                  }                  }
1407                  else          }
1408            else
1409            {
1410                    while (out < end)
1411                  {                  {
1412                          *(out++) = value;                          pixel = *(data++) << 16;
1413                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1414                          *(out++) = value >> 16;                          pixel |= *(data++);
1415                          *(out++) = value >> 24;                          SPLITCOLOUR24(pixel, pc);
1416                            value = MAKECOLOUR(pc);
1417                            LOUT32(out, value);
1418                  }                  }
1419          }          }
1420  }  }
# Line 618  translate_image(int width, int height, u Line 1426  translate_image(int width, int height, u
1426          uint8 *out;          uint8 *out;
1427          uint8 *end;          uint8 *end;
1428    
1429          /* if server and xserver bpp match, */          /*
1430          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1431          /* just return data */             and arch(endian) matches, no need to translate:
1432          if (g_arch_match)             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            /* todo */
1439            if (g_server_depth == 32 && g_depth == 24)
1440          {          {
1441                  if (g_depth == 15 && g_server_bpp == 15)                  return data;
1442                          return data;          }
1443                  if (g_depth == 16 && g_server_bpp == 16)  
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;                          return data;
1450          }          }
1451    
# Line 633  translate_image(int width, int height, u Line 1453  translate_image(int width, int height, u
1453          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1454          end = out + size;          end = out + size;
1455    
1456          switch (g_server_bpp)          switch (g_server_depth)
1457          {          {
1458                  case 24:                  case 24:
1459                          switch (g_bpp)                          switch (g_bpp)
# Line 698  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            for (i = 0; i < pointer_buttons; ++i)
1529            {
1530                    /* This might produce multiple logical buttons mapping
1531                       to a single physical one, but hey, that's
1532                       life... */
1533                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1534            }
1535    }
1536    
1537    RD_BOOL
1538  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1539  {  {
1540          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 731  calculate_shifts(uint32 mask, int *shift Line 1567  calculate_shifts(uint32 mask, int *shift
1567          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1568  }  }
1569    
1570  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1571  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1572     */
1573    static unsigned
1574    calculate_mask_weight(uint32 mask)
1575    {
1576            unsigned weight = 0;
1577            do
1578            {
1579                    weight += (mask & 1);
1580            }
1581            while (mask >>= 1);
1582            return weight;
1583    }
1584    
1585    static RD_BOOL
1586    select_visual(int screen_num)
1587  {  {
         XVisualInfo vi;  
1588          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1589          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1590          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1591          XVisualInfo template;          XVisualInfo template;
1592          Bool TrueColorVisual = False;          int i;
1593            unsigned red_weight, blue_weight, green_weight;
1594    
1595          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1596          if (g_display == NULL)  
1597            if (g_server_depth == -1)
1598          {          {
1599                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1600          }          }
1601    
1602          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1603          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1604          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1605          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1606                    XCloseDisplay(g_display);
1607                    return False;
1608            }
1609    
1610          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1611          template.class = TrueColor;          template.class = TrueColor;
1612          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          template.screen = screen_num;
1613            vmatches =
1614                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1615                                   &visuals_count);
1616            g_visual = NULL;
1617            g_no_translate_image = False;
1618            g_compatible_arch = False;
1619            if (vmatches != NULL)
1620            {
1621                    for (i = 0; i < visuals_count; ++i)
1622                    {
1623                            XVisualInfo *visual_info = &vmatches[i];
1624                            RD_BOOL can_translate_to_bpp = False;
1625                            int j;
1626    
1627                            /* Try to find a no-translation visual that'll
1628                               allow us to use RDP bitmaps directly as ZPixmaps. */
1629                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1630                                                   /* R5G5B5 */
1631                                                   (visual_info->red_mask == 0x7c00) &&
1632                                                   (visual_info->green_mask == 0x3e0) &&
1633                                                   (visual_info->blue_mask == 0x1f)) ||
1634                                                  ((visual_info->depth == 16) &&
1635                                                   /* R5G6B5 */
1636                                                   (visual_info->red_mask == 0xf800) &&
1637                                                   (visual_info->green_mask == 0x7e0) &&
1638                                                   (visual_info->blue_mask == 0x1f)) ||
1639                                                  ((visual_info->depth == 24) &&
1640                                                   /* R8G8B8 */
1641                                                   (visual_info->red_mask == 0xff0000) &&
1642                                                   (visual_info->green_mask == 0xff00) &&
1643                                                   (visual_info->blue_mask == 0xff))))
1644                            {
1645                                    g_visual = visual_info->visual;
1646                                    g_depth = visual_info->depth;
1647                                    g_compatible_arch = !g_host_be;
1648                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1649                                    if (g_no_translate_image)
1650                                            /* We found the best visual */
1651                                            break;
1652                            }
1653                            else
1654                            {
1655                                    g_compatible_arch = False;
1656                            }
1657    
1658          nvisuals--;                          if (visual_info->depth > 24)
1659          while (nvisuals >= 0)                          {
1660          {                                  /* Avoid 32-bit visuals and likes like the plague.
1661                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1662                  {                                     (e.g. nvidia's Composite 32-bit visual).
1663                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1664                                    continue;
1665                            }
1666    
1667                            /* Only care for visuals, for whose BPPs (not depths!)
1668                               we have a translateXtoY function. */
1669                            for (j = 0; j < pixmap_formats_count; ++j)
1670                            {
1671                                    if (pfm[j].depth == visual_info->depth)
1672                                    {
1673                                            if ((pfm[j].bits_per_pixel == 16) ||
1674                                                (pfm[j].bits_per_pixel == 24) ||
1675                                                (pfm[j].bits_per_pixel == 32))
1676                                            {
1677                                                    can_translate_to_bpp = True;
1678                                            }
1679                                            break;
1680                                    }
1681                            }
1682    
1683                            /* Prefer formats which have the most colour depth.
1684                               We're being truly aristocratic here, minding each
1685                               weight on its own. */
1686                            if (can_translate_to_bpp)
1687                            {
1688                                    unsigned vis_red_weight =
1689                                            calculate_mask_weight(visual_info->red_mask);
1690                                    unsigned vis_green_weight =
1691                                            calculate_mask_weight(visual_info->green_mask);
1692                                    unsigned vis_blue_weight =
1693                                            calculate_mask_weight(visual_info->blue_mask);
1694                                    if ((vis_red_weight >= red_weight)
1695                                        && (vis_green_weight >= green_weight)
1696                                        && (vis_blue_weight >= blue_weight))
1697                                    {
1698                                            red_weight = vis_red_weight;
1699                                            green_weight = vis_green_weight;
1700                                            blue_weight = vis_blue_weight;
1701                                            g_visual = visual_info->visual;
1702                                            g_depth = visual_info->depth;
1703                                    }
1704                            }
1705                  }                  }
1706                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1707          }          }
1708    
1709          test = 1;          if (g_visual != NULL)
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
         if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))  
1710          {          {
1711                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1712                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1713                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1714                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
                 /* Do not allocate colours on a TrueColor visual */  
                 if (g_visual->class == TrueColor)  
                 {  
                         g_owncolmap = False;  
                 }  
1715          }          }
1716          else          else
1717          {          {
1718                  /* need a truecolour visual */                  template.class = PseudoColor;
1719                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1720                  {                  template.colormap_size = 256;
1721                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1722                            XGetVisualInfo(g_display,
1723                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1724                                           &template, &visuals_count);
1725                    if (vmatches == NULL)
1726                    {
1727                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1728                            XCloseDisplay(g_display);
1729                            XFree(pfm);
1730                          return False;                          return False;
1731                  }                  }
1732    
1733                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1734                  g_owncolmap = False;                  g_owncolmap = True;
1735                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1736                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
                 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);  
   
                 /* if RGB video and averything is little endian */  
                 if (vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask)  
                         if (!g_xserver_be && !g_host_be)  
                                 g_arch_match = True;  
1737          }          }
1738    
1739          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1740          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1741          {          {
1742                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1743                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1744                  {                  {
1745                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1746    
1747                            if (g_no_translate_image)
1748                          {                          {
1749                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1750                                    {
1751                                            case 15:
1752                                            case 16:
1753                                                    if (g_bpp != 16)
1754                                                            g_no_translate_image = False;
1755                                                    break;
1756                                            case 24:
1757                                                    /* Yes, this will force image translation
1758                                                       on most modern servers which use 32 bits
1759                                                       for R8G8B8. */
1760                                                    if (g_bpp != 24)
1761                                                            g_no_translate_image = False;
1762                                                    break;
1763                                            default:
1764                                                    g_no_translate_image = False;
1765                                                    break;
1766                                    }
1767                          }                          }
1768    
1769                            /* Pixmap formats list is a depth-to-bpp mapping --
1770                               there's just a single entry for every depth,
1771                               so we can safely break here */
1772                            break;
1773                  }                  }
                 XFree(pfm);  
1774          }          }
1775            XFree(pfm);
1776            pfm = NULL;
1777            return True;
1778    }
1779    
1780    static XErrorHandler g_old_error_handler;
1781    static RD_BOOL g_error_expected = False;
1782    
1783    /* Check if the X11 window corresponding to a seamless window with
1784       specified id exists. */
1785    RD_BOOL
1786    sw_window_exists(unsigned long id)
1787    {
1788            seamless_window *sw;
1789            char *name;
1790            Status sts = 0;
1791    
1792          if (g_bpp < 8)          sw = sw_get_window_by_id(id);
1793            if (!sw)
1794                    return False;
1795    
1796            g_error_expected = True;
1797            sts = XFetchName(g_display, sw->wnd, &name);
1798            g_error_expected = False;
1799            if (sts)
1800          {          {
1801                  error("Less than 8 bpp not currently supported.\n");                  XFree(name);
1802                  XCloseDisplay(g_display);          }
1803    
1804            return sts;
1805    }
1806    
1807    static int
1808    error_handler(Display * dpy, XErrorEvent * eev)
1809    {
1810            if (g_error_expected)
1811                    return 0;
1812    
1813            return g_old_error_handler(dpy, eev);
1814    }
1815    
1816    RD_BOOL
1817    ui_init(void)
1818    {
1819            int screen_num;
1820    
1821            g_display = XOpenDisplay(NULL);
1822            if (g_display == NULL)
1823            {
1824                    error("Failed to open display: %s\n", XDisplayName(NULL));
1825                    return False;
1826            }
1827    
1828            {
1829                    uint16 endianess_test = 1;
1830                    g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1831            }
1832    
1833            g_old_error_handler = XSetErrorHandler(error_handler);
1834            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1835            screen_num = DefaultScreen(g_display);
1836            g_x_socket = ConnectionNumber(g_display);
1837            g_screen = ScreenOfDisplay(g_display, screen_num);
1838            g_depth = DefaultDepthOfScreen(g_screen);
1839    
1840            if (!select_visual(screen_num))
1841                  return False;                  return False;
1842    
1843            if (g_no_translate_image)
1844            {
1845                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1846          }          }
1847    
1848            if (g_server_depth > g_bpp)
1849            {
1850                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1851                            g_server_depth, g_bpp);
1852            }
1853    
1854            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1855                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1856    
1857          if (!g_owncolmap)          if (!g_owncolmap)
1858          {          {
1859                  g_xcolmap =                  g_xcolmap =
1860                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1861                                          AllocNone);                                          AllocNone);
1862                  if (g_depth <= 8)                  if (g_depth <= 8)
1863                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");                          warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1864          }          }
1865    
1866          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1867          {          {
1868                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1869                  g_ownbackstore = True;                  g_ownbackstore = True;
1870          }          }
1871    
# Line 850  ui_init(void) Line 1876  ui_init(void)
1876          {          {
1877                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1878                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1879                    g_using_full_workarea = True;
1880          }          }
1881          else if (g_width < 0)          else if (g_width < 0)
1882          {          {
1883                  /* Percent of screen */                  /* Percent of screen */
1884                    if (-g_width >= 100)
1885                            g_using_full_workarea = True;
1886                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1887                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1888          }          }
# Line 861  ui_init(void) Line 1890  ui_init(void)
1890          {          {
1891                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1892                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1893                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1894                  {                  {
1895                          g_width = cx;                          g_width = cx;
1896                          g_height = cy;                          g_height = cy;
1897                            g_using_full_workarea = True;
1898                  }                  }
1899                  else                  else
1900                  {                  {
1901                          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");
1902                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1903                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1904                  }                  }
1905          }          }
1906    
# Line 879  ui_init(void) Line 1908  ui_init(void)
1908          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1909    
1910          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1911            xwin_refresh_pointer_map();
1912    
1913          xkeymap_init();          xkeymap_init();
1914    
# Line 886  ui_init(void) Line 1916  ui_init(void)
1916                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1917    
1918          xclip_init();          xclip_init();
1919            ewmh_init();
1920            if (g_seamless_rdp)
1921            {
1922                    seamless_restack_test();
1923                    seamless_init();
1924            }
1925    
1926          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1927    
1928          return True;          return True;
1929  }  }
# Line 895  ui_init(void) Line 1931  ui_init(void)
1931  void  void
1932  ui_deinit(void)  ui_deinit(void)
1933  {  {
1934            while (g_seamless_windows)
1935            {
1936                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1937                    sw_remove_window(g_seamless_windows);
1938            }
1939    
1940            xclip_deinit();
1941    
1942          if (g_IM != NULL)          if (g_IM != NULL)
1943                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1944    
# Line 911  ui_deinit(void) Line 1955  ui_deinit(void)
1955          g_display = NULL;          g_display = NULL;
1956  }  }
1957    
1958  BOOL  
1959    static void
1960    get_window_attribs(XSetWindowAttributes * attribs)
1961    {
1962            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1963            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1964            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1965            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1966            attribs->override_redirect = g_fullscreen;
1967            attribs->colormap = g_xcolmap;
1968    }
1969    
1970    static void
1971    get_input_mask(long *input_mask)
1972    {
1973            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1974                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1975    
1976            if (g_sendmotion)
1977                    *input_mask |= PointerMotionMask;
1978            if (g_ownbackstore)
1979                    *input_mask |= ExposureMask;
1980            if (g_fullscreen || g_grab_keyboard)
1981                    *input_mask |= EnterWindowMask;
1982            if (g_grab_keyboard)
1983                    *input_mask |= LeaveWindowMask;
1984    }
1985    
1986    RD_BOOL
1987  ui_create_window(void)  ui_create_window(void)
1988  {  {
1989          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1990          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1991    
1992          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1993          XClassHint *classhints;          XClassHint *classhints;
1994          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 926  ui_create_window(void) Line 1999  ui_create_window(void)
1999          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
2000          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
2001    
2002          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
2003          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
2004          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
2005          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2006          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2007    
2008          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,          get_window_attribs(&attribs);
2009                                0, g_depth, InputOutput, g_visual,  
2010                                CWBackPixel | CWBackingStore | CWOverrideRedirect |          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
2011                                CWColormap | CWBorderPixel, &attribs);                                wndheight, 0, g_depth, InputOutput, g_visual,
2012                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
2013                                  CWBorderPixel, &attribs);
2014    
2015          if (g_gc == NULL)          if (g_gc == NULL)
2016            {
2017                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2018                    ui_reset_clip();
2019            }
2020    
2021            if (g_create_bitmap_gc == NULL)
2022                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2023    
2024          if ((g_ownbackstore) && (g_backstore == 0))          if ((g_ownbackstore) && (g_backstore == 0))
2025          {          {
# Line 950  ui_create_window(void) Line 2031  ui_create_window(void)
2031          }          }
2032    
2033          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
2034            ewmh_set_wm_name(g_wnd, g_title);
2035    
2036          if (g_hide_decorations)          if (g_hide_decorations)
2037                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2038    
2039          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2040          if (classhints != NULL)          if (classhints != NULL)
# Line 966  ui_create_window(void) Line 2048  ui_create_window(void)
2048          if (sizehints)          if (sizehints)
2049          {          {
2050                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
2051                    if (g_pos)
2052                            sizehints->flags |= PPosition;
2053                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
2054                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
2055                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 977  ui_create_window(void) Line 2061  ui_create_window(void)
2061                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2062          }          }
2063    
2064          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask;  
   
         if (g_sendmotion)  
                 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;  
2065    
2066          if (g_IM != NULL)          if (g_IM != NULL)
2067          {          {
# Line 1029  void Line 2103  void
2103  ui_resize_window()  ui_resize_window()
2104  {  {
2105          XSizeHints *sizehints;          XSizeHints *sizehints;
2106            Pixmap bs;
2107    
2108          sizehints = XAllocSizeHints();          sizehints = XAllocSizeHints();
2109          if (sizehints)          if (sizehints)
# Line 1044  ui_resize_window() Line 2119  ui_resize_window()
2119          {          {
2120                  XResizeWindow(g_display, g_wnd, g_width, g_height);                  XResizeWindow(g_display, g_wnd, g_width, g_height);
2121          }          }
2122    
2123            /* create new backstore pixmap */
2124            if (g_backstore != 0)
2125            {
2126                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2127                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
2128                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
2129                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
2130                    XFreePixmap(g_display, g_backstore);
2131                    g_backstore = bs;
2132            }
2133  }  }
2134    
2135  void  void
# Line 1060  xwin_toggle_fullscreen(void) Line 2146  xwin_toggle_fullscreen(void)
2146  {  {
2147          Pixmap contents = 0;          Pixmap contents = 0;
2148    
2149            if (g_seamless_active)
2150                    /* Turn off SeamlessRDP mode */
2151                    ui_seamless_toggle();
2152    
2153          if (!g_ownbackstore)          if (!g_ownbackstore)
2154          {          {
2155                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1080  xwin_toggle_fullscreen(void) Line 2170  xwin_toggle_fullscreen(void)
2170          }          }
2171  }  }
2172    
2173  /* Process all events in Xlib queue  static void
2174    handle_button_event(XEvent xevent, RD_BOOL down)
2175    {
2176            uint16 button, flags = 0;
2177            g_last_gesturetime = xevent.xbutton.time;
2178            /* Reverse the pointer button mapping, e.g. in the case of
2179               "left-handed mouse mode"; the RDP session expects to
2180               receive physical buttons (true in mstsc as well) and
2181               logical button behavior depends on the remote desktop's own
2182               mouse settings */
2183            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
2184            button = xkeymap_translate_button(xevent.xbutton.button);
2185            if (button == 0)
2186                    return;
2187    
2188            if (down)
2189                    flags = MOUSE_FLAG_DOWN;
2190    
2191            /* Stop moving window when button is released, regardless of cursor position */
2192            if (g_moving_wnd && (xevent.type == ButtonRelease))
2193                    g_moving_wnd = False;
2194    
2195            /* If win_button_size is nonzero, enable single app mode */
2196            if (xevent.xbutton.y < g_win_button_size)
2197            {
2198                    /*  Check from right to left: */
2199                    if (xevent.xbutton.x >= g_width - g_win_button_size)
2200                    {
2201                            /* The close button, continue */
2202                            ;
2203                    }
2204                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
2205                    {
2206                            /* The maximize/restore button. Do not send to
2207                               server.  It might be a good idea to change the
2208                               cursor or give some other visible indication
2209                               that rdesktop inhibited this click */
2210                            if (xevent.type == ButtonPress)
2211                                    return;
2212                    }
2213                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
2214                    {
2215                            /* The minimize button. Iconify window. */
2216                            if (xevent.type == ButtonRelease)
2217                            {
2218                                    /* Release the mouse button outside the minimize button, to prevent the
2219                                       actual minimazation to happen */
2220                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
2221                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
2222                                    return;
2223                            }
2224                    }
2225                    else if (xevent.xbutton.x <= g_win_button_size)
2226                    {
2227                            /* The system menu. Ignore. */
2228                            if (xevent.type == ButtonPress)
2229                                    return;
2230                    }
2231                    else
2232                    {
2233                            /* The title bar. */
2234                            if (xevent.type == ButtonPress)
2235                            {
2236                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
2237                                    {
2238                                            g_moving_wnd = True;
2239                                            g_move_x_offset = xevent.xbutton.x;
2240                                            g_move_y_offset = xevent.xbutton.y;
2241                                    }
2242                                    return;
2243                            }
2244                    }
2245            }
2246    
2247            if (xevent.xmotion.window == g_wnd)
2248            {
2249                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2250                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
2251            }
2252            else
2253            {
2254                    /* SeamlessRDP */
2255                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2256                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
2257            }
2258    }
2259    
2260    
2261    /* Process events in Xlib queue
2262     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
2263  static int  static int
2264  xwin_process_events(void)  xwin_process_events(void)
2265  {  {
2266          XEvent xevent;          XEvent xevent;
2267          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
2268          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
2269          char str[256];          char str[256];
2270          Status status;          Status status;
2271            int events = 0;
2272            seamless_window *sw;
2273    
2274          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
2275          {          {
2276                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
2277    
# Line 1103  xwin_process_events(void) Line 2281  xwin_process_events(void)
2281                          continue;                          continue;
2282                  }                  }
2283    
                 flags = 0;  
   
2284                  switch (xevent.type)                  switch (xevent.type)
2285                  {                  {
2286                          case VisibilityNotify:                          case VisibilityNotify:
2287                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
2288                                            g_Unobscured =
2289                                                    xevent.xvisibility.state == VisibilityUnobscured;
2290    
2291                                  break;                                  break;
2292                          case ClientMessage:                          case ClientMessage:
2293                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2294                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2295                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2296                                          /* Quit */                                  {
2297                                          return 0;                                          /* When killing a seamless window, close the window on the
2298                                               serverside instead of terminating rdesktop */
2299                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2300                                            if (!sw)
2301                                                    /* Otherwise, quit */
2302                                                    return 0;
2303                                            /* send seamless destroy process message */
2304                                            seamless_send_destroy(sw->id);
2305                                    }
2306                                  break;                                  break;
2307    
2308                          case KeyPress:                          case KeyPress:
# Line 1141  xwin_process_events(void) Line 2328  xwin_process_events(void)
2328                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2329                                  }                                  }
2330    
2331                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2332                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2333    
2334                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2335                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2336                                          break;                                          break;
2337    
2338                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2339                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
2340                                  break;                                  break;
2341    
2342                          case KeyRelease:                          case KeyRelease:
# Line 1166  xwin_process_events(void) Line 2344  xwin_process_events(void)
2344                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2345                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2346    
2347                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2348                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2349    
2350                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2351                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2352                                          break;                                          break;
2353    
2354                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2355                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2356                                  break;                                  break;
2357    
2358                          case ButtonPress:                          case ButtonPress:
2359                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2360                                  /* fall through */                                  break;
2361    
2362                          case ButtonRelease:                          case ButtonRelease:
2363                                  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);  
2364                                  break;                                  break;
2365    
2366                          case MotionNotify:                          case MotionNotify:
# Line 1259  xwin_process_events(void) Line 2375  xwin_process_events(void)
2375                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2376                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2377                                                         CurrentTime);                                                         CurrentTime);
2378                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2379                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2380                                    {
2381                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2382                                                           xevent.xmotion.x, xevent.xmotion.y);
2383                                    }
2384                                    else
2385                                    {
2386                                            /* SeamlessRDP */
2387                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2388                                                           xevent.xmotion.x_root,
2389                                                           xevent.xmotion.y_root);
2390                                    }
2391                                  break;                                  break;
2392    
2393                          case FocusIn:                          case FocusIn:
# Line 1271  xwin_process_events(void) Line 2398  xwin_process_events(void)
2398                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2399                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2400                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2401    
2402                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2403                                    if (!sw)
2404                                            break;
2405    
2406                                    /* Menu windows are real X11 windows,
2407                                       with focus. When such a window is
2408                                       destroyed, focus is reverted to the
2409                                       main application window, which
2410                                       would cause us to send FOCUS. This
2411                                       breaks window switching in, say,
2412                                       Seamonkey. We shouldn't need to
2413                                       send FOCUS: Windows should also
2414                                       revert focus to some other window
2415                                       when the menu window is
2416                                       destroyed. So, we only send FOCUS
2417                                       if the previous focus window still
2418                                       exists. */
2419                                    if (sw->id != g_seamless_focused)
2420                                    {
2421    
2422                                            if (sw_window_exists(g_seamless_focused))
2423                                                    seamless_send_focus(sw->id, 0);
2424                                            g_seamless_focused = sw->id;
2425                                    }
2426                                  break;                                  break;
2427    
2428                          case FocusOut:                          case FocusOut:
# Line 1303  xwin_process_events(void) Line 2455  xwin_process_events(void)
2455                                  break;                                  break;
2456    
2457                          case Expose:                          case Expose:
2458                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2459                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2460                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2461                                            xevent.xexpose.height,                                                    g_gc,
2462                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2463                                                      xevent.xexpose.width, xevent.xexpose.height,
2464                                                      xevent.xexpose.x, xevent.xexpose.y);
2465                                    }
2466                                    else
2467                                    {
2468                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2469                                            if (!sw)
2470                                                    break;
2471                                            XCopyArea(g_display, g_backstore,
2472                                                      xevent.xexpose.window, g_gc,
2473                                                      xevent.xexpose.x + sw->xoffset,
2474                                                      xevent.xexpose.y + sw->yoffset,
2475                                                      xevent.xexpose.width,
2476                                                      xevent.xexpose.height, xevent.xexpose.x,
2477                                                      xevent.xexpose.y);
2478                                    }
2479    
2480                                  break;                                  break;
2481    
2482                          case MappingNotify:                          case MappingNotify:
# Line 1322  xwin_process_events(void) Line 2491  xwin_process_events(void)
2491                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2492                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2493                                  }                                  }
2494    
2495                                    if (xevent.xmapping.request == MappingPointer)
2496                                    {
2497                                            xwin_refresh_pointer_map();
2498                                    }
2499    
2500                                  break;                                  break;
2501    
2502                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1336  xwin_process_events(void) Line 2511  xwin_process_events(void)
2511                                  break;                                  break;
2512                          case PropertyNotify:                          case PropertyNotify:
2513                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2514                                    if (xevent.xproperty.window == g_wnd)
2515                                            break;
2516                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2517                                            break;
2518    
2519                                    /* seamless */
2520                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2521                                    if (!sw)
2522                                            break;
2523    
2524                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2525                                        && (xevent.xproperty.state == PropertyNewValue))
2526                                    {
2527                                            sw->state = ewmh_get_window_state(sw->wnd);
2528                                            seamless_send_state(sw->id, sw->state, 0);
2529                                    }
2530    
2531                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2532                                        && (xevent.xproperty.state == PropertyNewValue))
2533                                    {
2534                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2535                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2536                                    }
2537    
2538                                    break;
2539                            case MapNotify:
2540                                    if (!g_seamless_active)
2541                                            rdp_send_client_window_status(1);
2542                                    break;
2543                            case UnmapNotify:
2544                                    if (!g_seamless_active)
2545                                            rdp_send_client_window_status(0);
2546                                    break;
2547                            case ConfigureNotify:
2548                                    if (!g_seamless_active)
2549                                            break;
2550    
2551                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2552                                    if (!sw)
2553                                            break;
2554    
2555                                    gettimeofday(sw->position_timer, NULL);
2556                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2557                                        1000000)
2558                                    {
2559                                            sw->position_timer->tv_usec +=
2560                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2561                                            sw->position_timer->tv_sec += 1;
2562                                    }
2563                                    else
2564                                    {
2565                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2566                                    }
2567    
2568                                    sw_handle_restack(sw);
2569                                  break;                                  break;
2570                  }                  }
2571          }          }
# Line 1350  ui_select(int rdp_socket) Line 2580  ui_select(int rdp_socket)
2580          int n;          int n;
2581          fd_set rfds, wfds;          fd_set rfds, wfds;
2582          struct timeval tv;          struct timeval tv;
2583          BOOL s_timeout = False;          RD_BOOL s_timeout = False;
2584    
2585          while (True)          while (True)
2586          {          {
# Line 1360  ui_select(int rdp_socket) Line 2590  ui_select(int rdp_socket)
2590                          /* User quit */                          /* User quit */
2591                          return 0;                          return 0;
2592    
2593                    if (g_seamless_active)
2594                            sw_check_timers();
2595    
2596                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2597                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2598                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2599                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2600    
 #ifdef WITH_RDPSND  
                 /* FIXME: there should be an API for registering fds */  
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd > n) ? g_dsp_fd : n;  
                 }  
 #endif  
2601                  /* default timeout */                  /* default timeout */
2602                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2603                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2604    
2605    #ifdef WITH_RDPSND
2606                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2607    #endif
2608    
2609                  /* add redirection handles */                  /* add redirection handles */
2610                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2611                    seamless_select_timeout(&tv);
2612    
2613                  n++;                  n++;
2614    
# Line 1388  ui_select(int rdp_socket) Line 2618  ui_select(int rdp_socket)
2618                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2619    
2620                          case 0:                          case 0:
2621                                  /* TODO: if tv.tv_sec just times out  #ifdef WITH_RDPSND
2622                                   * we will segfault.                                  rdpsnd_check_fds(&rfds, &wfds);
2623                                   * FIXME:  #endif
2624                                   */  
2625                                  //s_timeout = True;                                  /* Abort serial read calls */
2626                                  //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                  if (s_timeout)
2627                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2628                                  continue;                                  continue;
2629                  }                  }
2630    
2631                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);  #ifdef WITH_RDPSND
2632                    rdpsnd_check_fds(&rfds, &wfds);
2633    #endif
2634    
2635                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2636    
2637                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2638                          return 1;                          return 1;
2639    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2640          }          }
2641  }  }
2642    
# Line 1415  ui_move_pointer(int x, int y) Line 2646  ui_move_pointer(int x, int y)
2646          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);
2647  }  }
2648    
2649  HBITMAP  RD_HBITMAP
2650  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2651  {  {
2652          XImage *image;          XImage *image;
# Line 1423  ui_create_bitmap(int width, int height, Line 2654  ui_create_bitmap(int width, int height,
2654          uint8 *tdata;          uint8 *tdata;
2655          int bitmap_pad;          int bitmap_pad;
2656    
2657          if (g_server_bpp == 8)          if (g_server_depth == 8)
2658          {          {
2659                  bitmap_pad = 8;                  bitmap_pad = 8;
2660          }          }
# Line 1440  ui_create_bitmap(int width, int height, Line 2671  ui_create_bitmap(int width, int height,
2671          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2672                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2673    
2674          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);
2675    
2676          XFree(image);          XFree(image);
2677          if (tdata != data)          if (tdata != data)
2678                  xfree(tdata);                  xfree(tdata);
2679          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2680  }  }
2681    
2682  void  void
# Line 1455  ui_paint_bitmap(int x, int y, int cx, in Line 2686  ui_paint_bitmap(int x, int y, int cx, in
2686          uint8 *tdata;          uint8 *tdata;
2687          int bitmap_pad;          int bitmap_pad;
2688    
2689          if (g_server_bpp == 8)          if (g_server_depth == 8)
2690          {          {
2691                  bitmap_pad = 8;                  bitmap_pad = 8;
2692          }          }
# Line 1475  ui_paint_bitmap(int x, int y, int cx, in Line 2706  ui_paint_bitmap(int x, int y, int cx, in
2706          {          {
2707                  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);
2708                  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);
2709                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2710                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2711                                             x - sw->xoffset, y - sw->yoffset));
2712          }          }
2713          else          else
2714          {          {
2715                  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);
2716                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2717                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2718                                             x - sw->xoffset, y - sw->yoffset));
2719          }          }
2720    
2721          XFree(image);          XFree(image);
# Line 1487  ui_paint_bitmap(int x, int y, int cx, in Line 2724  ui_paint_bitmap(int x, int y, int cx, in
2724  }  }
2725    
2726  void  void
2727  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2728  {  {
2729          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2730  }  }
2731    
2732  HGLYPH  RD_HGLYPH
2733  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2734  {  {
2735          XImage *image;          XImage *image;
2736          Pixmap bitmap;          Pixmap bitmap;
2737          int scanline;          int scanline;
         GC gc;  
2738    
2739          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2740    
2741          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2742          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2743                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2744    
2745          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2746                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1511  ui_create_glyph(int width, int height, u Line 2748  ui_create_glyph(int width, int height, u
2748          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2749          XInitImage(image);          XInitImage(image);
2750    
2751          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);
2752    
2753          XFree(image);          XFree(image);
2754          XFreeGC(g_display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH) bitmap;  
2755  }  }
2756    
2757  void  void
2758  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2759  {  {
2760          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2761  }  }
2762    
2763  HCURSOR  RD_HCURSOR
2764  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,
2765                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2766  {  {
2767          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2768          XColor bg, fg;          XColor bg, fg;
2769          Cursor xcursor;          Cursor xcursor;
2770          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1592  ui_create_cursor(unsigned int x, unsigne Line 2828  ui_create_cursor(unsigned int x, unsigne
2828          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2829          xfree(mask);          xfree(mask);
2830          xfree(cursor);          xfree(cursor);
2831          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2832  }  }
2833    
2834  void  void
2835  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2836  {  {
2837          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2838          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2839            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2840  }  }
2841    
2842  void  void
2843  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2844  {  {
2845          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2846  }  }
# Line 1621  ui_set_null_cursor(void) Line 2858  ui_set_null_cursor(void)
2858                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2859    
2860    
2861  HCOLOURMAP  RD_HCOLOURMAP
2862  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2863  {  {
2864          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1717  ui_create_colourmap(COLOURMAP * colours) Line 2954  ui_create_colourmap(COLOURMAP * colours)
2954                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2955    
2956                  xfree(xcolours);                  xfree(xcolours);
2957                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2958          }          }
2959  }  }
2960    
2961  void  void
2962  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2963  {  {
2964          if (!g_owncolmap)          if (!g_owncolmap)
2965                  xfree(map);                  xfree(map);
# Line 1731  ui_destroy_colourmap(HCOLOURMAP map) Line 2968  ui_destroy_colourmap(HCOLOURMAP map)
2968  }  }
2969    
2970  void  void
2971  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2972  {  {
2973          if (!g_owncolmap)          if (!g_owncolmap)
2974          {          {
# Line 1741  ui_set_colourmap(HCOLOURMAP map) Line 2978  ui_set_colourmap(HCOLOURMAP map)
2978                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2979          }          }
2980          else          else
2981            {
2982                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2983                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2984            }
2985  }  }
2986    
2987  void  void
2988  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2989  {  {
2990          XRectangle rect;          g_clip_rectangle.x = x;
2991            g_clip_rectangle.y = y;
2992          rect.x = x;          g_clip_rectangle.width = cx;
2993          rect.y = y;          g_clip_rectangle.height = cy;
2994          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);  
2995  }  }
2996    
2997  void  void
2998  ui_reset_clip(void)  ui_reset_clip(void)
2999  {  {
3000          XRectangle rect;          g_clip_rectangle.x = 0;
3001            g_clip_rectangle.y = 0;
3002          rect.x = 0;          g_clip_rectangle.width = g_width;
3003          rect.y = 0;          g_clip_rectangle.height = g_height;
3004          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);  
3005  }  }
3006    
3007  void  void
# Line 1820  ui_patblt(uint8 opcode, Line 3056  ui_patblt(uint8 opcode,
3056                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3057                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3058                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3059                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3060                          break;                          break;
3061    
3062                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 1835  ui_patblt(uint8 opcode, Line 3071  ui_patblt(uint8 opcode,
3071                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3072                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3073                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3074                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3075                          break;                          break;
3076    
3077                  default:                  default:
# Line 1846  ui_patblt(uint8 opcode, Line 3082  ui_patblt(uint8 opcode,
3082    
3083          if (g_ownbackstore)          if (g_ownbackstore)
3084                  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);
3085            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3086                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3087                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3088  }  }
3089    
3090  void  void
# Line 1856  ui_screenblt(uint8 opcode, Line 3095  ui_screenblt(uint8 opcode,
3095          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3096          if (g_ownbackstore)          if (g_ownbackstore)
3097          {          {
3098                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3099                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3100                          XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  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);  
                 }  
                 else  
                 {  
                         XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
                         XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,  
                                   y);  
                 }  
3101          }          }
3102          else          else
3103          {          {
3104                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3105          }          }
3106    
3107            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3108                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3109                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3110    
3111          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3112  }  }
3113    
3114  void  void
3115  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3116            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3117            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3118  {  {
3119          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3120          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);
3121            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3122                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3123                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3124          if (g_ownbackstore)          if (g_ownbackstore)
3125                  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);
3126          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1891  ui_memblt(uint8 opcode, Line 3129  ui_memblt(uint8 opcode,
3129  void  void
3130  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3131            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3132            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3133            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3134  {  {
3135          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1929  ui_line(uint8 opcode, Line 3167  ui_line(uint8 opcode,
3167          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3168          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3169          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3170            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3171                                                startx - sw->xoffset, starty - sw->yoffset,
3172                                                endx - sw->xoffset, endy - sw->yoffset));
3173          if (g_ownbackstore)          if (g_ownbackstore)
3174                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3175          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1943  ui_rect( Line 3184  ui_rect(
3184          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
3185  }  }
3186    
3187    void
3188    ui_polygon(uint8 opcode,
3189               /* mode */ uint8 fillmode,
3190               /* dest */ RD_POINT * point, int npoints,
3191               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3192    {
3193            uint8 style, i, ipattern[8];
3194            Pixmap fill;
3195    
3196            SET_FUNCTION(opcode);
3197    
3198            switch (fillmode)
3199            {
3200                    case ALTERNATE:
3201                            XSetFillRule(g_display, g_gc, EvenOddRule);
3202                            break;
3203                    case WINDING:
3204                            XSetFillRule(g_display, g_gc, WindingRule);
3205                            break;
3206                    default:
3207                            unimpl("fill mode %d\n", fillmode);
3208            }
3209    
3210            if (brush)
3211                    style = brush->style;
3212            else
3213                    style = 0;
3214    
3215            switch (style)
3216            {
3217                    case 0: /* Solid */
3218                            SET_FOREGROUND(fgcolour);
3219                            FILL_POLYGON((XPoint *) point, npoints);
3220                            break;
3221    
3222                    case 2: /* Hatch */
3223                            fill = (Pixmap) ui_create_glyph(8, 8,
3224                                                            hatch_patterns + brush->pattern[0] * 8);
3225                            SET_FOREGROUND(fgcolour);
3226                            SET_BACKGROUND(bgcolour);
3227                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3228                            XSetStipple(g_display, g_gc, fill);
3229                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3230                            FILL_POLYGON((XPoint *) point, npoints);
3231                            XSetFillStyle(g_display, g_gc, FillSolid);
3232                            XSetTSOrigin(g_display, g_gc, 0, 0);
3233                            ui_destroy_glyph((RD_HGLYPH) fill);
3234                            break;
3235    
3236                    case 3: /* Pattern */
3237                            for (i = 0; i != 8; i++)
3238                                    ipattern[7 - i] = brush->pattern[i];
3239                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3240                            SET_FOREGROUND(bgcolour);
3241                            SET_BACKGROUND(fgcolour);
3242                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3243                            XSetStipple(g_display, g_gc, fill);
3244                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3245                            FILL_POLYGON((XPoint *) point, npoints);
3246                            XSetFillStyle(g_display, g_gc, FillSolid);
3247                            XSetTSOrigin(g_display, g_gc, 0, 0);
3248                            ui_destroy_glyph((RD_HGLYPH) fill);
3249                            break;
3250    
3251                    default:
3252                            unimpl("brush %d\n", brush->style);
3253            }
3254    
3255            RESET_FUNCTION(opcode);
3256    }
3257    
3258    void
3259    ui_polyline(uint8 opcode,
3260                /* dest */ RD_POINT * points, int npoints,
3261                /* pen */ PEN * pen)
3262    {
3263            /* TODO: set join style */
3264            SET_FUNCTION(opcode);
3265            SET_FOREGROUND(pen->colour);
3266            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
3267            if (g_ownbackstore)
3268                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3269                               CoordModePrevious);
3270    
3271            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3272                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3273    
3274            RESET_FUNCTION(opcode);
3275    }
3276    
3277    void
3278    ui_ellipse(uint8 opcode,
3279               /* mode */ uint8 fillmode,
3280               /* dest */ int x, int y, int cx, int cy,
3281               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3282    {
3283            uint8 style, i, ipattern[8];
3284            Pixmap fill;
3285    
3286            SET_FUNCTION(opcode);
3287    
3288            if (brush)
3289                    style = brush->style;
3290            else
3291                    style = 0;
3292    
3293            switch (style)
3294            {
3295                    case 0: /* Solid */
3296                            SET_FOREGROUND(fgcolour);
3297                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3298                            break;
3299    
3300                    case 2: /* Hatch */
3301                            fill = (Pixmap) ui_create_glyph(8, 8,
3302                                                            hatch_patterns + brush->pattern[0] * 8);
3303                            SET_FOREGROUND(fgcolour);
3304                            SET_BACKGROUND(bgcolour);
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                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3309                            XSetFillStyle(g_display, g_gc, FillSolid);
3310                            XSetTSOrigin(g_display, g_gc, 0, 0);
3311                            ui_destroy_glyph((RD_HGLYPH) fill);
3312                            break;
3313    
3314                    case 3: /* Pattern */
3315                            for (i = 0; i != 8; i++)
3316                                    ipattern[7 - i] = brush->pattern[i];
3317                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3318                            SET_FOREGROUND(bgcolour);
3319                            SET_BACKGROUND(fgcolour);
3320                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3321                            XSetStipple(g_display, g_gc, fill);
3322                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3323                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3324                            XSetFillStyle(g_display, g_gc, FillSolid);
3325                            XSetTSOrigin(g_display, g_gc, 0, 0);
3326                            ui_destroy_glyph((RD_HGLYPH) fill);
3327                            break;
3328    
3329                    default:
3330                            unimpl("brush %d\n", brush->style);
3331            }
3332    
3333            RESET_FUNCTION(opcode);
3334    }
3335    
3336  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3337  void  void
3338  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3339                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3340                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3341                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3342  {  {
3343          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1998  ui_draw_glyph(int mixmode, Line 3388  ui_draw_glyph(int mixmode,
3388  }  }
3389    
3390  void  void
3391  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,
3392               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3393               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3394               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3395  {  {
3396            /* TODO: use brush appropriately */
3397    
3398          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3399          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
3400          DATABLOB *entry;          DATABLOB *entry;
# Line 2034  ui_draw_text(uint8 font, uint8 flags, in Line 3426  ui_draw_text(uint8 font, uint8 flags, in
3426                  switch (text[i])                  switch (text[i])
3427                  {                  {
3428                          case 0xff:                          case 0xff:
3429                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3430                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3431                                  {                                  {
3432                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3433                                          exit(1);                                          for (j = 0; j < length; j++)
3434                                                    fprintf(stderr, "%02x ", text[j]);
3435                                            fprintf(stderr, "\n");
3436                                            i = length = 0;
3437                                            break;
3438                                  }                                  }
3439                                    cache_put_text(text[i + 1], text, text[i + 2]);
3440                                    i += 3;
3441                                    length -= i;
3442                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3443                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3444                                  i = 0;                                  i = 0;
3445                                  break;                                  break;
3446    
3447                          case 0xfe:                          case 0xfe:
3448                                    /* At least one byte needs to follow */
3449                                    if (i + 2 > length)
3450                                    {
3451                                            warning("Skipping short 0xfe command:");
3452                                            for (j = 0; j < length; j++)
3453                                                    fprintf(stderr, "%02x ", text[j]);
3454                                            fprintf(stderr, "\n");
3455                                            i = length = 0;
3456                                            break;
3457                                    }
3458                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3459                                  if (entry != NULL)                                  if (entry->data != NULL)
3460                                  {                                  {
3461                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3462                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3463                                          {                                          {
3464                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3465                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2084  ui_draw_text(uint8 font, uint8 flags, in Line 3491  ui_draw_text(uint8 font, uint8 flags, in
3491          if (g_ownbackstore)          if (g_ownbackstore)
3492          {          {
3493                  if (boxcx > 1)                  if (boxcx > 1)
3494                    {
3495                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3496                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3497                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3498                                                    (g_display, g_backstore, sw->wnd, g_gc,
3499                                                     boxx, boxy,
3500                                                     boxcx, boxcy,
3501                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3502                    }
3503                  else                  else
3504                    {
3505                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3506                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3507                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3508                                                    (g_display, g_backstore, sw->wnd, g_gc,
3509                                                     clipx, clipy,
3510                                                     clipcx, clipcy, clipx - sw->xoffset,
3511                                                     clipy - sw->yoffset));
3512                    }
3513          }          }
3514  }  }
3515    
# Line 2101  ui_desktop_save(uint32 offset, int x, in Line 3522  ui_desktop_save(uint32 offset, int x, in
3522          if (g_ownbackstore)          if (g_ownbackstore)
3523          {          {
3524                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3525                    exit_if_null(image);
3526          }          }
3527          else          else
3528          {          {
3529                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3530                  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);
3531                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3532                    exit_if_null(image);
3533                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3534          }          }
3535    
# Line 2128  ui_desktop_restore(uint32 offset, int x, Line 3551  ui_desktop_restore(uint32 offset, int x,
3551                  return;                  return;
3552    
3553          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3554                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3555    
3556          if (g_ownbackstore)          if (g_ownbackstore)
3557          {          {
3558                  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);
3559                  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);
3560                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3561                                            (g_display, g_backstore, sw->wnd, g_gc,
3562                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3563          }          }
3564          else          else
3565          {          {
3566                  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);
3567                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3568                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3569                                             x - sw->xoffset, y - sw->yoffset));
3570          }          }
3571    
3572          XFree(image);          XFree(image);
3573  }  }
3574    
3575    /* these do nothing here but are used in uiports */
3576    void
3577    ui_begin_update(void)
3578    {
3579    }
3580    
3581    void
3582    ui_end_update(void)
3583    {
3584    }
3585    
3586    
3587    void
3588    ui_seamless_begin(RD_BOOL hidden)
3589    {
3590            if (!g_seamless_rdp)
3591                    return;
3592    
3593            if (g_seamless_started)
3594                    return;
3595    
3596            g_seamless_started = True;
3597            g_seamless_hidden = hidden;
3598    
3599            if (!hidden)
3600                    ui_seamless_toggle();
3601    }
3602    
3603    
3604    void
3605    ui_seamless_hide_desktop()
3606    {
3607            if (!g_seamless_rdp)
3608                    return;
3609    
3610            if (!g_seamless_started)
3611                    return;
3612    
3613            if (g_seamless_active)
3614                    ui_seamless_toggle();
3615    
3616            g_seamless_hidden = True;
3617    }
3618    
3619    
3620    void
3621    ui_seamless_unhide_desktop()
3622    {
3623            if (!g_seamless_rdp)
3624                    return;
3625    
3626            if (!g_seamless_started)
3627                    return;
3628    
3629            g_seamless_hidden = False;
3630    
3631            ui_seamless_toggle();
3632    }
3633    
3634    
3635    void
3636    ui_seamless_toggle()
3637    {
3638            if (!g_seamless_rdp)
3639                    return;
3640    
3641            if (!g_seamless_started)
3642                    return;
3643    
3644            if (g_seamless_hidden)
3645                    return;
3646    
3647            if (g_seamless_active)
3648            {
3649                    /* Deactivate */
3650                    while (g_seamless_windows)
3651                    {
3652                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3653                            sw_remove_window(g_seamless_windows);
3654                    }
3655                    XMapWindow(g_display, g_wnd);
3656            }
3657            else
3658            {
3659                    /* Activate */
3660                    XUnmapWindow(g_display, g_wnd);
3661                    seamless_send_sync();
3662            }
3663    
3664            g_seamless_active = !g_seamless_active;
3665    }
3666    
3667    
3668    void
3669    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3670                              unsigned long flags)
3671    {
3672            Window wnd;
3673            XSetWindowAttributes attribs;
3674            XClassHint *classhints;
3675            XSizeHints *sizehints;
3676            XWMHints *wmhints;
3677            long input_mask;
3678            seamless_window *sw, *sw_parent;
3679    
3680            if (!g_seamless_active)
3681                    return;
3682    
3683            /* Ignore CREATEs for existing windows */
3684            sw = sw_get_window_by_id(id);
3685            if (sw)
3686                    return;
3687    
3688            get_window_attribs(&attribs);
3689            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3690                                InputOutput, g_visual,
3691                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3692    
3693            XStoreName(g_display, wnd, "SeamlessRDP");
3694            ewmh_set_wm_name(wnd, "SeamlessRDP");
3695    
3696            mwm_hide_decorations(wnd);
3697    
3698            classhints = XAllocClassHint();
3699            if (classhints != NULL)
3700            {
3701                    classhints->res_name = "rdesktop";
3702                    classhints->res_class = "SeamlessRDP";
3703                    XSetClassHint(g_display, wnd, classhints);
3704                    XFree(classhints);
3705            }
3706    
3707            /* WM_NORMAL_HINTS */
3708            sizehints = XAllocSizeHints();
3709            if (sizehints != NULL)
3710            {
3711                    sizehints->flags = USPosition;
3712                    XSetWMNormalHints(g_display, wnd, sizehints);
3713                    XFree(sizehints);
3714            }
3715    
3716            /* Parent-less transient windows */
3717            if (parent == 0xFFFFFFFF)
3718            {
3719                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3720                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3721                       using some other hints. */
3722                    ewmh_set_window_popup(wnd);
3723            }
3724            /* Normal transient windows */
3725            else if (parent != 0x00000000)
3726            {
3727                    sw_parent = sw_get_window_by_id(parent);
3728                    if (sw_parent)
3729                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3730                    else
3731                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3732            }
3733    
3734            if (flags & SEAMLESSRDP_CREATE_MODAL)
3735            {
3736                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3737                       somewhat at least */
3738                    if (parent == 0x00000000)
3739                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3740                    ewmh_set_window_modal(wnd);
3741            }
3742    
3743            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3744            {
3745                    /* Make window always-on-top */
3746                    ewmh_set_window_above(wnd);
3747            }
3748    
3749            /* FIXME: Support for Input Context:s */
3750    
3751            get_input_mask(&input_mask);
3752            input_mask |= PropertyChangeMask;
3753    
3754            XSelectInput(g_display, wnd, input_mask);
3755    
3756            /* handle the WM_DELETE_WINDOW protocol. */
3757            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3758    
3759            sw = xmalloc(sizeof(seamless_window));
3760    
3761            memset(sw, 0, sizeof(seamless_window));
3762    
3763            sw->wnd = wnd;
3764            sw->id = id;
3765            sw->group = sw_find_group(group, False);
3766            sw->group->refcnt++;
3767            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3768            sw->desktop = 0;
3769            sw->position_timer = xmalloc(sizeof(struct timeval));
3770            timerclear(sw->position_timer);
3771    
3772            sw->outstanding_position = False;
3773            sw->outpos_serial = 0;
3774            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3775            sw->outpos_width = sw->outpos_height = 0;
3776    
3777            sw->next = g_seamless_windows;
3778            g_seamless_windows = sw;
3779    
3780            /* WM_HINTS */
3781            wmhints = XAllocWMHints();
3782            if (wmhints)
3783            {
3784                    wmhints->flags = WindowGroupHint;
3785                    wmhints->window_group = sw->group->wnd;
3786                    XSetWMHints(g_display, sw->wnd, wmhints);
3787                    XFree(wmhints);
3788            }
3789    }
3790    
3791    
3792    void
3793    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3794    {
3795            seamless_window *sw;
3796    
3797            if (!g_seamless_active)
3798                    return;
3799    
3800            sw = sw_get_window_by_id(id);
3801            if (!sw)
3802            {
3803                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3804                    return;
3805            }
3806    
3807            XDestroyWindow(g_display, sw->wnd);
3808            sw_remove_window(sw);
3809    }
3810    
3811    
3812    void
3813    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3814    {
3815            seamless_window *sw, *sw_next;
3816    
3817            if (!g_seamless_active)
3818                    return;
3819    
3820            for (sw = g_seamless_windows; sw; sw = sw_next)
3821            {
3822                    sw_next = sw->next;
3823    
3824                    if (sw->group->id == id)
3825                    {
3826                            XDestroyWindow(g_display, sw->wnd);
3827                            sw_remove_window(sw);
3828                    }
3829            }
3830    }
3831    
3832    
3833    void
3834    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3835                        const char *data, int chunk_len)
3836    {
3837            seamless_window *sw;
3838    
3839            if (!g_seamless_active)
3840                    return;
3841    
3842            sw = sw_get_window_by_id(id);
3843            if (!sw)
3844            {
3845                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3846                    return;
3847            }
3848    
3849            if (chunk == 0)
3850            {
3851                    if (sw->icon_size)
3852                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3853    
3854                    if (strcmp(format, "RGBA") != 0)
3855                    {
3856                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3857                            return;
3858                    }
3859    
3860                    sw->icon_size = width * height * 4;
3861                    if (sw->icon_size > 32 * 32 * 4)
3862                    {
3863                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3864                            sw->icon_size = 0;
3865                            return;
3866                    }
3867    
3868                    sw->icon_offset = 0;
3869            }
3870            else
3871            {
3872                    if (!sw->icon_size)
3873                            return;
3874            }
3875    
3876            if (chunk_len > (sw->icon_size - sw->icon_offset))
3877            {
3878                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3879                            chunk_len, sw->icon_size - sw->icon_offset);
3880                    sw->icon_size = 0;
3881                    return;
3882            }
3883    
3884            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3885            sw->icon_offset += chunk_len;
3886    
3887            if (sw->icon_offset == sw->icon_size)
3888            {
3889                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3890                    sw->icon_size = 0;
3891            }
3892    }
3893    
3894    
3895    void
3896    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3897    {
3898            seamless_window *sw;
3899    
3900            if (!g_seamless_active)
3901                    return;
3902    
3903            sw = sw_get_window_by_id(id);
3904            if (!sw)
3905            {
3906                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3907                    return;
3908            }
3909    
3910            if (strcmp(format, "RGBA") != 0)
3911            {
3912                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3913                    return;
3914            }
3915    
3916            ewmh_del_icon(sw->wnd, width, height);
3917    }
3918    
3919    
3920    void
3921    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3922    {
3923            seamless_window *sw;
3924    
3925            if (!g_seamless_active)
3926                    return;
3927    
3928            sw = sw_get_window_by_id(id);
3929            if (!sw)
3930            {
3931                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3932                    return;
3933            }
3934    
3935            /* We ignore server updates until it has handled our request. */
3936            if (sw->outstanding_position)
3937                    return;
3938    
3939            if (!width || !height)
3940                    /* X11 windows must be at least 1x1 */
3941                    return;
3942    
3943            sw->xoffset = x;
3944            sw->yoffset = y;
3945            sw->width = width;
3946            sw->height = height;
3947    
3948            /* If we move the window in a maximized state, then KDE won't
3949               accept restoration */
3950            switch (sw->state)
3951            {
3952                    case SEAMLESSRDP_MINIMIZED:
3953                    case SEAMLESSRDP_MAXIMIZED:
3954                            return;
3955            }
3956    
3957            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3958            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3959    }
3960    
3961    
3962    void
3963    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3964    {
3965            seamless_window *sw;
3966            XWindowChanges values;
3967            unsigned long restack_serial;
3968    
3969            if (!g_seamless_active)
3970                    return;
3971    
3972            sw = sw_get_window_by_id(id);
3973            if (!sw)
3974            {
3975                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3976                    return;
3977            }
3978    
3979            if (behind)
3980            {
3981                    seamless_window *sw_behind;
3982    
3983                    sw_behind = sw_get_window_by_id(behind);
3984                    if (!sw_behind)
3985                    {
3986                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
3987                            return;
3988                    }
3989    
3990                    if (!g_seamless_broken_restack)
3991                    {
3992                            values.stack_mode = Below;
3993                            values.sibling = sw_behind->wnd;
3994                            restack_serial = XNextRequest(g_display);
3995                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
3996                                                 CWStackMode | CWSibling, &values);
3997                            sw_wait_configurenotify(sw->wnd, restack_serial);
3998                    }
3999            }
4000            else
4001            {
4002                    values.stack_mode = Above;
4003                    restack_serial = XNextRequest(g_display);
4004                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4005                                         &values);
4006                    sw_wait_configurenotify(sw->wnd, restack_serial);
4007            }
4008    
4009            sw_restack_window(sw, behind);
4010    
4011            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4012            {
4013                    /* Make window always-on-top */
4014                    ewmh_set_window_above(sw->wnd);
4015            }
4016    }
4017    
4018    
4019    void
4020    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4021    {
4022            seamless_window *sw;
4023    
4024            if (!g_seamless_active)
4025                    return;
4026    
4027            sw = sw_get_window_by_id(id);
4028            if (!sw)
4029            {
4030                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4031                    return;
4032            }
4033    
4034            /* FIXME: Might want to convert the name for non-EWMH WMs */
4035            XStoreName(g_display, sw->wnd, title);
4036            ewmh_set_wm_name(sw->wnd, title);
4037    }
4038    
4039    
4040    void
4041    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
4042    {
4043            seamless_window *sw;
4044    
4045            if (!g_seamless_active)
4046                    return;
4047    
4048            sw = sw_get_window_by_id(id);
4049            if (!sw)
4050            {
4051                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
4052                    return;
4053            }
4054    
4055            switch (state)
4056            {
4057                    case SEAMLESSRDP_NORMAL:
4058                    case SEAMLESSRDP_MAXIMIZED:
4059                            ewmh_change_state(sw->wnd, state);
4060                            XMapWindow(g_display, sw->wnd);
4061                            break;
4062                    case SEAMLESSRDP_MINIMIZED:
4063                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4064                               the Window Manager should probably just ignore the request, since
4065                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4066                               such as minimization, rather than an independent state." Besides,
4067                               XIconifyWindow is easier. */
4068                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4069                            {
4070                                    XWMHints *hints;
4071                                    hints = XGetWMHints(g_display, sw->wnd);
4072                                    if (hints)
4073                                    {
4074                                            hints->flags |= StateHint;
4075                                            hints->initial_state = IconicState;
4076                                            XSetWMHints(g_display, sw->wnd, hints);
4077                                            XFree(hints);
4078                                    }
4079                                    XMapWindow(g_display, sw->wnd);
4080                            }
4081                            else
4082                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4083                            break;
4084                    default:
4085                            warning("SeamlessRDP: Invalid state %d\n", state);
4086                            break;
4087            }
4088    
4089            sw->state = state;
4090    }
4091    
4092    
4093    void
4094    ui_seamless_syncbegin(unsigned long flags)
4095    {
4096            if (!g_seamless_active)
4097                    return;
4098    
4099            /* Destroy all seamless windows */
4100            while (g_seamless_windows)
4101            {
4102                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4103                    sw_remove_window(g_seamless_windows);
4104            }
4105    }
4106    
4107    
4108    void
4109    ui_seamless_ack(unsigned int serial)
4110    {
4111            seamless_window *sw;
4112            for (sw = g_seamless_windows; sw; sw = sw->next)
4113            {
4114                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4115                    {
4116                            sw->xoffset = sw->outpos_xoffset;
4117                            sw->yoffset = sw->outpos_yoffset;
4118                            sw->width = sw->outpos_width;
4119                            sw->height = sw->outpos_height;
4120                            sw->outstanding_position = False;
4121    
4122                            /* Do a complete redraw of the window as part of the
4123                               completion of the move. This is to remove any
4124                               artifacts caused by our lack of synchronization. */
4125                            XCopyArea(g_display, g_backstore,
4126                                      sw->wnd, g_gc,
4127                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4128    
4129                            break;
4130                    }
4131            }
4132    }

Legend:
Removed from v.691  
changed lines
  Added in v.1461

  ViewVC Help
Powered by ViewVC 1.1.26