/[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 1042 by astrand, Tue Jan 24 12:40:24 2006 UTC revision 1463 by astrand, Fri Mar 28 11:36:15 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-2005     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 33  extern int g_height; Line 35  extern int g_height;
35  extern int g_xpos;  extern int g_xpos;
36  extern int g_ypos;  extern int g_ypos;
37  extern int g_pos;  extern int g_pos;
38  extern BOOL g_sendmotion;  extern RD_BOOL g_sendmotion;
39  extern BOOL g_fullscreen;  extern RD_BOOL g_fullscreen;
40  extern BOOL g_grab_keyboard;  extern RD_BOOL g_grab_keyboard;
41  extern BOOL g_hide_decorations;  extern RD_BOOL g_hide_decorations;
42  extern char g_title[];  extern char g_title[];
43  /* Color depth of the RDP session.  /* Color depth of the RDP session.
44     As of RDP 5.1, it may be 8, 15, 16 or 24. */     As of RDP 5.1, it may be 8, 15, 16 or 24. */
# Line 48  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;  static GC g_create_bitmap_gc = NULL;
97  static GC g_create_glyph_gc = NULL;  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).  /* 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     This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
# Line 66  static int g_bpp; Line 108  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  /* Indicates the visual is has 15, 16 or 24 depth  static RD_BOOL g_focused;
120     and the same color channel masks as its RDP equivalent. */  static RD_BOOL g_mouse_in_wnd;
121  static BOOL g_compatible_depth;  /* 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  /* Indicates whether RDP's bitmaps and our XImages have the same
129     binary format. If so, we can avoid an expensive translation.     binary format. If so, we can avoid an expensive translation.
130     If this is True, so is g_compatible_depth. */     Note that this can be true when g_compatible_arch is false,
131  static BOOL g_no_translate_image = False;     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 BOOL g_using_full_workarea = False;  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 122  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 140  PixelColour; Line 232  PixelColour;
232          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
233          if (g_ownbackstore) \          if (g_ownbackstore) \
234                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  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)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 148  PixelColour; Line 241  PixelColour;
241          { \          { \
242                  case 0: /* Outline */ \                  case 0: /* Outline */ \
243                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          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) \                          if (g_ownbackstore) \
246                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
247                          break; \                          break; \
248                  case 1: /* Filled */ \                  case 1: /* Filled */ \
249                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          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) \                          if (g_ownbackstore) \
252                                  XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \                                  XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
253                          break; \                          break; \
# Line 160  PixelColour; Line 255  PixelColour;
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    
# Line 190  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  static void
384  mwm_hide_decorations(void)  sw_check_timers()
385    {
386            seamless_window *sw;
387            struct timeval now;
388    
389            gettimeofday(&now, NULL);
390            for (sw = g_seamless_windows; sw; sw = sw->next)
391            {
392                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
393                    {
394                            timerclear(sw->position_timer);
395                            sw_update_position(sw);
396                    }
397            }
398    }
399    
400    
401    static void
402    sw_restack_window(seamless_window * sw, unsigned long behind)
403    {
404            seamless_window *sw_above;
405    
406            /* Remove window from stack */
407            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
408            {
409                    if (sw_above->behind == sw->id)
410                            break;
411            }
412    
413            if (sw_above)
414                    sw_above->behind = sw->behind;
415    
416            /* And then add it at the new position */
417            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
418            {
419                    if (sw_above->behind == behind)
420                            break;
421            }
422    
423            if (sw_above)
424                    sw_above->behind = sw->id;
425    
426            sw->behind = behind;
427    }
428    
429    
430    static void
431    sw_handle_restack(seamless_window * sw)
432    {
433            Status status;
434            Window root, parent, *children;
435            unsigned int nchildren, i;
436            seamless_window *sw_below;
437    
438            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
439                                &root, &parent, &children, &nchildren);
440            if (!status || !nchildren)
441                    return;
442    
443            sw_below = NULL;
444    
445            i = 0;
446            while (children[i] != sw->wnd)
447            {
448                    i++;
449                    if (i >= nchildren)
450                            goto end;
451            }
452    
453            for (i++; i < nchildren; i++)
454            {
455                    sw_below = sw_get_window_by_wnd(children[i]);
456                    if (sw_below)
457                            break;
458            }
459    
460            if (!sw_below && !sw->behind)
461                    goto end;
462            if (sw_below && (sw_below->id == sw->behind))
463                    goto end;
464    
465            if (sw_below)
466            {
467                    seamless_send_zchange(sw->id, sw_below->id, 0);
468                    sw_restack_window(sw, sw_below->id);
469            }
470            else
471            {
472                    seamless_send_zchange(sw->id, 0, 0);
473                    sw_restack_window(sw, 0);
474            }
475    
476          end:
477            XFree(children);
478    }
479    
480    
481    static seamless_group *
482    sw_find_group(unsigned long id, RD_BOOL dont_create)
483    {
484            seamless_window *sw;
485            seamless_group *sg;
486            XSetWindowAttributes attribs;
487    
488            for (sw = g_seamless_windows; sw; sw = sw->next)
489            {
490                    if (sw->group->id == id)
491                            return sw->group;
492            }
493    
494            if (dont_create)
495                    return NULL;
496    
497            sg = xmalloc(sizeof(seamless_group));
498    
499            sg->wnd =
500                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
501                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
502    
503            sg->id = id;
504            sg->refcnt = 0;
505    
506            return sg;
507    }
508    
509    
510    static void
511    mwm_hide_decorations(Window wnd)
512  {  {
513          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
514          Atom hintsatom;          Atom hintsatom;
# Line 208  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    typedef struct _sw_configurenotify_context
534    {
535            Window window;
536            unsigned long serial;
537    } sw_configurenotify_context;
538    
539    /* Predicate procedure for sw_wait_configurenotify */
540    static Bool
541    sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg)
542    {
543            sw_configurenotify_context *context = (sw_configurenotify_context *) arg;
544            if (xevent->xany.type == ConfigureNotify
545                && xevent->xconfigure.window == context->window
546                && xevent->xany.serial >= context->serial)
547                    return True;
548    
549            return False;
550    }
551    
552    /* Wait for a ConfigureNotify, with a equal or larger serial, on the
553       specified window. The event will be removed from the queue. We
554       could use XMaskEvent(StructureNotifyMask), but we would then risk
555       throwing away crucial events like DestroyNotify.
556    
557       After a ConfigureWindow, according to ICCCM section 4.1.5, we
558       should recieve a ConfigureNotify, either a real or synthetic
559       one. This indicates that the configure has been "completed".
560       However, some WMs such as several versions of Metacity fails to
561       send synthetic events. See bug
562       http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
563       timeout to avoid a hang. Tk uses the same approach. */
564    static void
565    sw_wait_configurenotify(Window wnd, unsigned long serial)
566    {
567            XEvent xevent;
568            sw_configurenotify_context context;
569            struct timeval now;
570            struct timeval nextsecond;
571            RD_BOOL got = False;
572    
573            context.window = wnd;
574            context.serial = serial;
575    
576            gettimeofday(&nextsecond, NULL);
577            nextsecond.tv_sec += 1;
578    
579            do
580            {
581                    if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context))
582                    {
583                            got = True;
584                            break;
585                    }
586                    usleep(100000);
587                    gettimeofday(&now, NULL);
588            }
589            while (timercmp(&now, &nextsecond, <));
590    
591            if (!got)
592            {
593                    warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
594            }
595    }
596    
597    /* Get the toplevel window, in case of reparenting */
598    static Window
599    sw_get_toplevel(Window wnd)
600    {
601            Window root, parent;
602            Window *child_list;
603            unsigned int num_children;
604    
605            while (1)
606            {
607                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
608                    if (root == parent)
609                    {
610                            break;
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) \  #define SPLITCOLOUR15(colour, rv) \
# Line 243  mwm_hide_decorations(void) Line 802  mwm_hide_decorations(void)
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; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
809  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #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; }  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
# Line 263  translate_colour(uint32 colour) Line 825  translate_colour(uint32 colour)
825                          SPLITCOLOUR16(colour, pc);                          SPLITCOLOUR16(colour, pc);
826                          break;                          break;
827                  case 24:                  case 24:
828                    case 32:
829                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
830                          break;                          break;
831                  default:                  default:
# Line 322  translate8to16(const uint8 * data, uint8 Line 885  translate8to16(const uint8 * data, uint8
885  {  {
886          uint16 value;          uint16 value;
887    
888          if (g_compatible_depth)          if (g_compatible_arch)
889          {          {
890                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
891                  REPEAT2                  REPEAT2
# Line 356  translate8to24(const uint8 * data, uint8 Line 919  translate8to24(const uint8 * data, uint8
919  {  {
920          uint32 value;          uint32 value;
921    
922          if (g_compatible_depth)          if (g_compatible_arch)
923          {          {
924                  while (out < end)                  while (out < end)
925                  {                  {
# Line 379  translate8to32(const uint8 * data, uint8 Line 942  translate8to32(const uint8 * data, uint8
942  {  {
943          uint32 value;          uint32 value;
944    
945          if (g_compatible_depth)          if (g_compatible_arch)
946          {          {
947                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
948                  REPEAT4                  REPEAT4
# Line 451  translate15to24(const uint16 * data, uin Line 1014  translate15to24(const uint16 * data, uin
1014          uint16 pixel;          uint16 pixel;
1015          PixelColour pc;          PixelColour pc;
1016    
1017          if (g_compatible_depth)          if (g_compatible_arch)
1018          {          {
1019                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1020                  REPEAT3                  REPEAT3
# Line 501  translate15to32(const uint16 * data, uin Line 1064  translate15to32(const uint16 * data, uin
1064          uint32 value;          uint32 value;
1065          PixelColour pc;          PixelColour pc;
1066    
1067          if (g_compatible_depth)          if (g_compatible_arch)
1068          {          {
1069                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1070                  REPEAT4                  REPEAT4
# Line 609  translate16to24(const uint16 * data, uin Line 1172  translate16to24(const uint16 * data, uin
1172          uint16 pixel;          uint16 pixel;
1173          PixelColour pc;          PixelColour pc;
1174    
1175          if (g_compatible_depth)          if (g_compatible_arch)
1176          {          {
1177                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1178                  REPEAT3                  REPEAT3
# Line 679  translate16to32(const uint16 * data, uin Line 1242  translate16to32(const uint16 * data, uin
1242          uint32 value;          uint32 value;
1243          PixelColour pc;          PixelColour pc;
1244    
1245          if (g_compatible_depth)          if (g_compatible_arch)
1246          {          {
1247                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1248                  REPEAT4                  REPEAT4
# Line 808  translate24to32(const uint8 * data, uint Line 1371  translate24to32(const uint8 * data, uint
1371          uint32 value;          uint32 value;
1372          PixelColour pc;          PixelColour pc;
1373    
1374          if (g_compatible_depth)          if (g_compatible_arch)
1375          {          {
1376                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1377  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 871  translate_image(int width, int height, u Line 1434  translate_image(int width, int height, u
1434             is only set for compatible depths, but the RDP depth might've             is only set for compatible depths, but the RDP depth might've
1435             changed during connection negotiations.             changed during connection negotiations.
1436           */           */
1437    
1438            /* todo */
1439            if (g_server_depth == 32 && g_depth == 24)
1440            {
1441                    return data;
1442            }
1443    
1444          if (g_no_translate_image)          if (g_no_translate_image)
1445          {          {
1446                  if ((g_depth == 15 && g_server_depth == 15) ||                  if ((g_depth == 15 && g_server_depth == 15) ||
# Line 948  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 996  calculate_mask_weight(uint32 mask) Line 1582  calculate_mask_weight(uint32 mask)
1582          return weight;          return weight;
1583  }  }
1584    
1585  static BOOL  static RD_BOOL
1586  select_visual()  select_visual(int screen_num)
1587  {  {
1588          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1589          int pixmap_formats_count, visuals_count;          int pixmap_formats_count, visuals_count;
# Line 1008  select_visual() Line 1594  select_visual()
1594    
1595          red_weight = blue_weight = green_weight = 0;          red_weight = blue_weight = green_weight = 0;
1596    
1597            if (g_server_depth == -1)
1598            {
1599                    g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1600            }
1601    
1602          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1603          if (pfm == NULL)          if (pfm == NULL)
1604          {          {
# Line 1018  select_visual() Line 1609  select_visual()
1609    
1610          /* Search for best TrueColor visual */          /* Search for best TrueColor visual */
1611          template.class = TrueColor;          template.class = TrueColor;
1612          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);          template.screen = screen_num;
1613            vmatches =
1614                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1615                                   &visuals_count);
1616          g_visual = NULL;          g_visual = NULL;
1617          g_no_translate_image = False;          g_no_translate_image = False;
1618          g_compatible_depth = False;          g_compatible_arch = False;
1619          if (vmatches != NULL)          if (vmatches != NULL)
1620          {          {
1621                  for (i = 0; i < visuals_count; ++i)                  for (i = 0; i < visuals_count; ++i)
1622                  {                  {
1623                          XVisualInfo *visual_info = &vmatches[i];                          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                          /* Try to find a no-translation visual that'll
1628                             allow us to use RDP bitmaps directly as ZPixmaps. */                             allow us to use RDP bitmaps directly as ZPixmaps. */
# Line 1048  select_visual() Line 1644  select_visual()
1644                          {                          {
1645                                  g_visual = visual_info->visual;                                  g_visual = visual_info->visual;
1646                                  g_depth = visual_info->depth;                                  g_depth = visual_info->depth;
1647                                  g_compatible_depth = True;                                  g_compatible_arch = !g_host_be;
1648                                  g_no_translate_image = (visual_info->depth == g_server_depth);                                  g_no_translate_image = (visual_info->depth == g_server_depth);
1649                                  if (g_no_translate_image)                                  if (g_no_translate_image)
1650                                          /* We found the best visual */                                          /* We found the best visual */
# Line 1056  select_visual() Line 1652  select_visual()
1652                          }                          }
1653                          else                          else
1654                          {                          {
1655                                  g_compatible_depth = False;                                  g_compatible_arch = False;
1656                          }                          }
1657    
1658                          if (visual_info->depth > 24)                          if (visual_info->depth > 24)
# Line 1070  select_visual() Line 1666  select_visual()
1666    
1667                          /* Only care for visuals, for whose BPPs (not depths!)                          /* Only care for visuals, for whose BPPs (not depths!)
1668                             we have a translateXtoY function. */                             we have a translateXtoY function. */
                         BOOL can_translate_to_bpp = False;  
                         int j;  
1669                          for (j = 0; j < pixmap_formats_count; ++j)                          for (j = 0; j < pixmap_formats_count; ++j)
1670                          {                          {
1671                                  if (pfm[j].depth == visual_info->depth)                                  if (pfm[j].depth == visual_info->depth)
# Line 1183  select_visual() Line 1777  select_visual()
1777          return True;          return True;
1778  }  }
1779    
1780  BOOL  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            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                    XFree(name);
1802            }
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)  ui_init(void)
1818  {  {
1819          int screen_num;          int screen_num;
# Line 1197  ui_init(void) Line 1827  ui_init(void)
1827    
1828          {          {
1829                  uint16 endianess_test = 1;                  uint16 endianess_test = 1;
1830                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));                  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);          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1835          screen_num = DefaultScreen(g_display);          screen_num = DefaultScreen(g_display);
1836          g_x_socket = ConnectionNumber(g_display);          g_x_socket = ConnectionNumber(g_display);
1837          g_screen = ScreenOfDisplay(g_display, screen_num);          g_screen = ScreenOfDisplay(g_display, screen_num);
1838          g_depth = DefaultDepthOfScreen(g_screen);          g_depth = DefaultDepthOfScreen(g_screen);
1839    
1840          if (!select_visual())          if (!select_visual(screen_num))
1841                  return False;                  return False;
1842    
1843          if (g_no_translate_image)          if (g_no_translate_image)
# Line 1245  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          {          {
# Line 1258  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;
                 g_using_full_workarea = True;  
   
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 1277  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 1284  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_init();
1923            }
1924    
1925          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1926    
# Line 1293  ui_init(void) Line 1930  ui_init(void)
1930  void  void
1931  ui_deinit(void)  ui_deinit(void)
1932  {  {
1933            while (g_seamless_windows)
1934            {
1935                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1936                    sw_remove_window(g_seamless_windows);
1937            }
1938    
1939            xclip_deinit();
1940    
1941          if (g_IM != NULL)          if (g_IM != NULL)
1942                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1943    
# Line 1309  ui_deinit(void) Line 1954  ui_deinit(void)
1954          g_display = NULL;          g_display = NULL;
1955  }  }
1956    
1957  BOOL  
1958    static void
1959    get_window_attribs(XSetWindowAttributes * attribs)
1960    {
1961            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1962            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1963            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1964            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1965            attribs->override_redirect = g_fullscreen;
1966            attribs->colormap = g_xcolmap;
1967    }
1968    
1969    static void
1970    get_input_mask(long *input_mask)
1971    {
1972            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1973                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1974    
1975            if (g_sendmotion)
1976                    *input_mask |= PointerMotionMask;
1977            if (g_ownbackstore)
1978                    *input_mask |= ExposureMask;
1979            if (g_fullscreen || g_grab_keyboard)
1980                    *input_mask |= EnterWindowMask;
1981            if (g_grab_keyboard)
1982                    *input_mask |= LeaveWindowMask;
1983    }
1984    
1985    RD_BOOL
1986  ui_create_window(void)  ui_create_window(void)
1987  {  {
1988          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
# Line 1331  ui_create_window(void) Line 2004  ui_create_window(void)
2004          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2005                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2006    
2007          attribs.background_pixel = BlackPixelOfScreen(g_screen);          get_window_attribs(&attribs);
         attribs.border_pixel = WhitePixelOfScreen(g_screen);  
         attribs.backing_store = g_ownbackstore ? NotUseful : Always;  
         attribs.override_redirect = g_fullscreen;  
         attribs.colormap = g_xcolmap;  
2008    
2009          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
2010                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1343  ui_create_window(void) Line 2012  ui_create_window(void)
2012                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
2013    
2014          if (g_gc == NULL)          if (g_gc == NULL)
2015            {
2016                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2017                    ui_reset_clip();
2018            }
2019    
2020          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
2021                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1358  ui_create_window(void) Line 2030  ui_create_window(void)
2030          }          }
2031    
2032          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
2033            ewmh_set_wm_name(g_wnd, g_title);
2034    
2035          if (g_hide_decorations)          if (g_hide_decorations)
2036                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2037    
2038          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2039          if (classhints != NULL)          if (classhints != NULL)
# Line 1387  ui_create_window(void) Line 2060  ui_create_window(void)
2060                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2061          }          }
2062    
2063          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;  
   
         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;  
2064    
2065          if (g_IM != NULL)          if (g_IM != NULL)
2066          {          {
# Line 1432  ui_create_window(void) Line 2095  ui_create_window(void)
2095          if (g_null_cursor == NULL)          if (g_null_cursor == NULL)
2096                  g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);                  g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
2097    
2098            if (g_seamless_rdp)
2099            {
2100                    seamless_restack_test();
2101            }
2102    
2103          return True;          return True;
2104  }  }
2105    
# Line 1482  xwin_toggle_fullscreen(void) Line 2150  xwin_toggle_fullscreen(void)
2150  {  {
2151          Pixmap contents = 0;          Pixmap contents = 0;
2152    
2153            if (g_seamless_active)
2154                    /* Turn off SeamlessRDP mode */
2155                    ui_seamless_toggle();
2156    
2157          if (!g_ownbackstore)          if (!g_ownbackstore)
2158          {          {
2159                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1503  xwin_toggle_fullscreen(void) Line 2175  xwin_toggle_fullscreen(void)
2175  }  }
2176    
2177  static void  static void
2178  handle_button_event(XEvent xevent, BOOL down)  handle_button_event(XEvent xevent, RD_BOOL down)
2179  {  {
2180          uint16 button, flags = 0;          uint16 button, flags = 0;
2181          g_last_gesturetime = xevent.xbutton.time;          g_last_gesturetime = xevent.xbutton.time;
2182            /* Reverse the pointer button mapping, e.g. in the case of
2183               "left-handed mouse mode"; the RDP session expects to
2184               receive physical buttons (true in mstsc as well) and
2185               logical button behavior depends on the remote desktop's own
2186               mouse settings */
2187            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
2188          button = xkeymap_translate_button(xevent.xbutton.button);          button = xkeymap_translate_button(xevent.xbutton.button);
2189          if (button == 0)          if (button == 0)
2190                  return;                  return;
# Line 1570  handle_button_event(XEvent xevent, BOOL Line 2248  handle_button_event(XEvent xevent, BOOL
2248                  }                  }
2249          }          }
2250    
2251          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
2252                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
2253                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2254                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
2255            }
2256            else
2257            {
2258                    /* SeamlessRDP */
2259                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2260                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
2261            }
2262  }  }
2263    
2264    
2265  /* Process events in Xlib queue  /* Process events in Xlib queue
2266     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
2267  static int  static int
# Line 1585  xwin_process_events(void) Line 2273  xwin_process_events(void)
2273          char str[256];          char str[256];
2274          Status status;          Status status;
2275          int events = 0;          int events = 0;
2276            seamless_window *sw;
2277    
2278          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
2279          {          {
# Line 1599  xwin_process_events(void) Line 2288  xwin_process_events(void)
2288                  switch (xevent.type)                  switch (xevent.type)
2289                  {                  {
2290                          case VisibilityNotify:                          case VisibilityNotify:
2291                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
2292                                            g_Unobscured =
2293                                                    xevent.xvisibility.state == VisibilityUnobscured;
2294    
2295                                  break;                                  break;
2296                          case ClientMessage:                          case ClientMessage:
2297                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2298                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2299                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2300                                          /* Quit */                                  {
2301                                          return 0;                                          /* When killing a seamless window, close the window on the
2302                                               serverside instead of terminating rdesktop */
2303                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2304                                            if (!sw)
2305                                                    /* Otherwise, quit */
2306                                                    return 0;
2307                                            /* send seamless destroy process message */
2308                                            seamless_send_destroy(sw->id);
2309                                    }
2310                                  break;                                  break;
2311    
2312                          case KeyPress:                          case KeyPress:
# Line 1679  xwin_process_events(void) Line 2379  xwin_process_events(void)
2379                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2380                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2381                                                         CurrentTime);                                                         CurrentTime);
2382                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2383                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2384                                    {
2385                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2386                                                           xevent.xmotion.x, xevent.xmotion.y);
2387                                    }
2388                                    else
2389                                    {
2390                                            /* SeamlessRDP */
2391                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2392                                                           xevent.xmotion.x_root,
2393                                                           xevent.xmotion.y_root);
2394                                    }
2395                                  break;                                  break;
2396    
2397                          case FocusIn:                          case FocusIn:
# Line 1691  xwin_process_events(void) Line 2402  xwin_process_events(void)
2402                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2403                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2404                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2405    
2406                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2407                                    if (!sw)
2408                                            break;
2409    
2410                                    /* Menu windows are real X11 windows,
2411                                       with focus. When such a window is
2412                                       destroyed, focus is reverted to the
2413                                       main application window, which
2414                                       would cause us to send FOCUS. This
2415                                       breaks window switching in, say,
2416                                       Seamonkey. We shouldn't need to
2417                                       send FOCUS: Windows should also
2418                                       revert focus to some other window
2419                                       when the menu window is
2420                                       destroyed. So, we only send FOCUS
2421                                       if the previous focus window still
2422                                       exists. */
2423                                    if (sw->id != g_seamless_focused)
2424                                    {
2425    
2426                                            if (sw_window_exists(g_seamless_focused))
2427                                                    seamless_send_focus(sw->id, 0);
2428                                            g_seamless_focused = sw->id;
2429                                    }
2430                                  break;                                  break;
2431    
2432                          case FocusOut:                          case FocusOut:
# Line 1723  xwin_process_events(void) Line 2459  xwin_process_events(void)
2459                                  break;                                  break;
2460    
2461                          case Expose:                          case Expose:
2462                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2463                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2464                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2465                                            xevent.xexpose.height,                                                    g_gc,
2466                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2467                                                      xevent.xexpose.width, xevent.xexpose.height,
2468                                                      xevent.xexpose.x, xevent.xexpose.y);
2469                                    }
2470                                    else
2471                                    {
2472                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2473                                            if (!sw)
2474                                                    break;
2475                                            XCopyArea(g_display, g_backstore,
2476                                                      xevent.xexpose.window, g_gc,
2477                                                      xevent.xexpose.x + sw->xoffset,
2478                                                      xevent.xexpose.y + sw->yoffset,
2479                                                      xevent.xexpose.width,
2480                                                      xevent.xexpose.height, xevent.xexpose.x,
2481                                                      xevent.xexpose.y);
2482                                    }
2483    
2484                                  break;                                  break;
2485    
2486                          case MappingNotify:                          case MappingNotify:
# Line 1742  xwin_process_events(void) Line 2495  xwin_process_events(void)
2495                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2496                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2497                                  }                                  }
2498    
2499                                    if (xevent.xmapping.request == MappingPointer)
2500                                    {
2501                                            xwin_refresh_pointer_map();
2502                                    }
2503    
2504                                  break;                                  break;
2505    
2506                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1756  xwin_process_events(void) Line 2515  xwin_process_events(void)
2515                                  break;                                  break;
2516                          case PropertyNotify:                          case PropertyNotify:
2517                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2518                                    if (xevent.xproperty.window == g_wnd)
2519                                            break;
2520                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2521                                            break;
2522    
2523                                    /* seamless */
2524                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2525                                    if (!sw)
2526                                            break;
2527    
2528                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2529                                        && (xevent.xproperty.state == PropertyNewValue))
2530                                    {
2531                                            sw->state = ewmh_get_window_state(sw->wnd);
2532                                            seamless_send_state(sw->id, sw->state, 0);
2533                                    }
2534    
2535                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2536                                        && (xevent.xproperty.state == PropertyNewValue))
2537                                    {
2538                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2539                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2540                                    }
2541    
2542                                  break;                                  break;
2543                          case MapNotify:                          case MapNotify:
2544                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2545                                            rdp_send_client_window_status(1);
2546                                  break;                                  break;
2547                          case UnmapNotify:                          case UnmapNotify:
2548                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2549                                            rdp_send_client_window_status(0);
2550                                    break;
2551                            case ConfigureNotify:
2552                                    if (!g_seamless_active)
2553                                            break;
2554    
2555                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2556                                    if (!sw)
2557                                            break;
2558    
2559                                    gettimeofday(sw->position_timer, NULL);
2560                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2561                                        1000000)
2562                                    {
2563                                            sw->position_timer->tv_usec +=
2564                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2565                                            sw->position_timer->tv_sec += 1;
2566                                    }
2567                                    else
2568                                    {
2569                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2570                                    }
2571    
2572                                    sw_handle_restack(sw);
2573                                  break;                                  break;
2574                  }                  }
2575          }          }
# Line 1776  ui_select(int rdp_socket) Line 2584  ui_select(int rdp_socket)
2584          int n;          int n;
2585          fd_set rfds, wfds;          fd_set rfds, wfds;
2586          struct timeval tv;          struct timeval tv;
2587          BOOL s_timeout = False;          RD_BOOL s_timeout = False;
2588    
2589          while (True)          while (True)
2590          {          {
# Line 1786  ui_select(int rdp_socket) Line 2594  ui_select(int rdp_socket)
2594                          /* User quit */                          /* User quit */
2595                          return 0;                          return 0;
2596    
2597                    if (g_seamless_active)
2598                            sw_check_timers();
2599    
2600                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2601                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2602                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2603                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2604    
 #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  
2605                  /* default timeout */                  /* default timeout */
2606                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2607                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2608    
2609    #ifdef WITH_RDPSND
2610                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2611    #endif
2612    
2613                  /* add redirection handles */                  /* add redirection handles */
2614                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2615                    seamless_select_timeout(&tv);
2616    
2617                  n++;                  n++;
2618    
# Line 1814  ui_select(int rdp_socket) Line 2622  ui_select(int rdp_socket)
2622                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2623    
2624                          case 0:                          case 0:
2625    #ifdef WITH_RDPSND
2626                                    rdpsnd_check_fds(&rfds, &wfds);
2627    #endif
2628    
2629                                  /* Abort serial read calls */                                  /* Abort serial read calls */
2630                                  if (s_timeout)                                  if (s_timeout)
2631                                          rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                          rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2632                                  continue;                                  continue;
2633                  }                  }
2634    
2635                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);  #ifdef WITH_RDPSND
2636                    rdpsnd_check_fds(&rfds, &wfds);
2637    #endif
2638    
2639                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2640    
2641                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2642                          return 1;                          return 1;
2643    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2644          }          }
2645  }  }
2646    
# Line 1838  ui_move_pointer(int x, int y) Line 2650  ui_move_pointer(int x, int y)
2650          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);
2651  }  }
2652    
2653  HBITMAP  RD_HBITMAP
2654  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2655  {  {
2656          XImage *image;          XImage *image;
# Line 1868  ui_create_bitmap(int width, int height, Line 2680  ui_create_bitmap(int width, int height,
2680          XFree(image);          XFree(image);
2681          if (tdata != data)          if (tdata != data)
2682                  xfree(tdata);                  xfree(tdata);
2683          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2684  }  }
2685    
2686  void  void
# Line 1898  ui_paint_bitmap(int x, int y, int cx, in Line 2710  ui_paint_bitmap(int x, int y, int cx, in
2710          {          {
2711                  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);
2712                  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);
2713                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2714                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2715                                             x - sw->xoffset, y - sw->yoffset));
2716          }          }
2717          else          else
2718          {          {
2719                  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);
2720                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2721                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2722                                             x - sw->xoffset, y - sw->yoffset));
2723          }          }
2724    
2725          XFree(image);          XFree(image);
# Line 1910  ui_paint_bitmap(int x, int y, int cx, in Line 2728  ui_paint_bitmap(int x, int y, int cx, in
2728  }  }
2729    
2730  void  void
2731  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2732  {  {
2733          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2734  }  }
2735    
2736  HGLYPH  RD_HGLYPH
2737  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2738  {  {
2739          XImage *image;          XImage *image;
# Line 1937  ui_create_glyph(int width, int height, u Line 2755  ui_create_glyph(int width, int height, u
2755          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2756    
2757          XFree(image);          XFree(image);
2758          return (HGLYPH) bitmap;          return (RD_HGLYPH) bitmap;
2759  }  }
2760    
2761  void  void
2762  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2763  {  {
2764          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2765  }  }
2766    
2767  HCURSOR  RD_HCURSOR
2768  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,
2769                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2770  {  {
2771          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2772          XColor bg, fg;          XColor bg, fg;
2773          Cursor xcursor;          Cursor xcursor;
2774          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 2014  ui_create_cursor(unsigned int x, unsigne Line 2832  ui_create_cursor(unsigned int x, unsigne
2832          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2833          xfree(mask);          xfree(mask);
2834          xfree(cursor);          xfree(cursor);
2835          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2836  }  }
2837    
2838  void  void
2839  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2840  {  {
2841          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2842          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2843            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2844  }  }
2845    
2846  void  void
2847  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2848  {  {
2849          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2850  }  }
# Line 2043  ui_set_null_cursor(void) Line 2862  ui_set_null_cursor(void)
2862                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2863    
2864    
2865  HCOLOURMAP  RD_HCOLOURMAP
2866  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2867  {  {
2868          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 2139  ui_create_colourmap(COLOURMAP * colours) Line 2958  ui_create_colourmap(COLOURMAP * colours)
2958                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2959    
2960                  xfree(xcolours);                  xfree(xcolours);
2961                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2962          }          }
2963  }  }
2964    
2965  void  void
2966  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2967  {  {
2968          if (!g_owncolmap)          if (!g_owncolmap)
2969                  xfree(map);                  xfree(map);
# Line 2153  ui_destroy_colourmap(HCOLOURMAP map) Line 2972  ui_destroy_colourmap(HCOLOURMAP map)
2972  }  }
2973    
2974  void  void
2975  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2976  {  {
2977          if (!g_owncolmap)          if (!g_owncolmap)
2978          {          {
# Line 2163  ui_set_colourmap(HCOLOURMAP map) Line 2982  ui_set_colourmap(HCOLOURMAP map)
2982                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2983          }          }
2984          else          else
2985            {
2986                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2987                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2988            }
2989  }  }
2990    
2991  void  void
2992  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2993  {  {
2994          XRectangle rect;          g_clip_rectangle.x = x;
2995            g_clip_rectangle.y = y;
2996          rect.x = x;          g_clip_rectangle.width = cx;
2997          rect.y = y;          g_clip_rectangle.height = cy;
2998          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);  
2999  }  }
3000    
3001  void  void
3002  ui_reset_clip(void)  ui_reset_clip(void)
3003  {  {
3004          XRectangle rect;          g_clip_rectangle.x = 0;
3005            g_clip_rectangle.y = 0;
3006          rect.x = 0;          g_clip_rectangle.width = g_width;
3007          rect.y = 0;          g_clip_rectangle.height = g_height;
3008          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);  
3009  }  }
3010    
3011  void  void
# Line 2242  ui_patblt(uint8 opcode, Line 3060  ui_patblt(uint8 opcode,
3060                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3061                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3062                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3063                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3064                          break;                          break;
3065    
3066                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2257  ui_patblt(uint8 opcode, Line 3075  ui_patblt(uint8 opcode,
3075                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3076                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3077                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3078                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3079                          break;                          break;
3080    
3081                  default:                  default:
# Line 2268  ui_patblt(uint8 opcode, Line 3086  ui_patblt(uint8 opcode,
3086    
3087          if (g_ownbackstore)          if (g_ownbackstore)
3088                  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);
3089            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3090                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3091                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3092  }  }
3093    
3094  void  void
# Line 2278  ui_screenblt(uint8 opcode, Line 3099  ui_screenblt(uint8 opcode,
3099          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3100          if (g_ownbackstore)          if (g_ownbackstore)
3101          {          {
3102                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3103                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3104                          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);  
                 }  
3105          }          }
3106          else          else
3107          {          {
3108                  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);
3109          }          }
3110    
3111            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3112                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3113                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3114    
3115          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3116  }  }
3117    
3118  void  void
3119  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3120            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3121            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3122  {  {
3123          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3124          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);
3125            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3126                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3127                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3128          if (g_ownbackstore)          if (g_ownbackstore)
3129                  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);
3130          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2313  ui_memblt(uint8 opcode, Line 3133  ui_memblt(uint8 opcode,
3133  void  void
3134  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3135            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3136            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3137            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3138  {  {
3139          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 2351  ui_line(uint8 opcode, Line 3171  ui_line(uint8 opcode,
3171          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3172          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3173          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3174            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3175                                                startx - sw->xoffset, starty - sw->yoffset,
3176                                                endx - sw->xoffset, endy - sw->yoffset));
3177          if (g_ownbackstore)          if (g_ownbackstore)
3178                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3179          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2368  ui_rect( Line 3191  ui_rect(
3191  void  void
3192  ui_polygon(uint8 opcode,  ui_polygon(uint8 opcode,
3193             /* mode */ uint8 fillmode,             /* mode */ uint8 fillmode,
3194             /* dest */ POINT * point, int npoints,             /* dest */ RD_POINT * point, int npoints,
3195             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3196  {  {
3197          uint8 style, i, ipattern[8];          uint8 style, i, ipattern[8];
# Line 2411  ui_polygon(uint8 opcode, Line 3234  ui_polygon(uint8 opcode,
3234                          FILL_POLYGON((XPoint *) point, npoints);                          FILL_POLYGON((XPoint *) point, npoints);
3235                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3236                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3237                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3238                          break;                          break;
3239    
3240                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2426  ui_polygon(uint8 opcode, Line 3249  ui_polygon(uint8 opcode,
3249                          FILL_POLYGON((XPoint *) point, npoints);                          FILL_POLYGON((XPoint *) point, npoints);
3250                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3251                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3252                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3253                          break;                          break;
3254    
3255                  default:                  default:
# Line 2438  ui_polygon(uint8 opcode, Line 3261  ui_polygon(uint8 opcode,
3261    
3262  void  void
3263  ui_polyline(uint8 opcode,  ui_polyline(uint8 opcode,
3264              /* dest */ POINT * points, int npoints,              /* dest */ RD_POINT * points, int npoints,
3265              /* pen */ PEN * pen)              /* pen */ PEN * pen)
3266  {  {
3267          /* TODO: set join style */          /* TODO: set join style */
# Line 2448  ui_polyline(uint8 opcode, Line 3271  ui_polyline(uint8 opcode,
3271          if (g_ownbackstore)          if (g_ownbackstore)
3272                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3273                             CoordModePrevious);                             CoordModePrevious);
3274    
3275            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3276                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3277    
3278          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3279  }  }
3280    
# Line 2485  ui_ellipse(uint8 opcode, Line 3312  ui_ellipse(uint8 opcode,
3312                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3313                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3314                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3315                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3316                          break;                          break;
3317    
3318                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2500  ui_ellipse(uint8 opcode, Line 3327  ui_ellipse(uint8 opcode,
3327                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3328                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3329                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3330                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3331                          break;                          break;
3332    
3333                  default:                  default:
# Line 2514  ui_ellipse(uint8 opcode, Line 3341  ui_ellipse(uint8 opcode,
3341  void  void
3342  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3343                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3344                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3345                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3346  {  {
3347          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 2668  ui_draw_text(uint8 font, uint8 flags, ui Line 3495  ui_draw_text(uint8 font, uint8 flags, ui
3495          if (g_ownbackstore)          if (g_ownbackstore)
3496          {          {
3497                  if (boxcx > 1)                  if (boxcx > 1)
3498                    {
3499                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3500                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3501                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3502                                                    (g_display, g_backstore, sw->wnd, g_gc,
3503                                                     boxx, boxy,
3504                                                     boxcx, boxcy,
3505                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3506                    }
3507                  else                  else
3508                    {
3509                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3510                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3511                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3512                                                    (g_display, g_backstore, sw->wnd, g_gc,
3513                                                     clipx, clipy,
3514                                                     clipcx, clipcy, clipx - sw->xoffset,
3515                                                     clipy - sw->yoffset));
3516                    }
3517          }          }
3518  }  }
3519    
# Line 2685  ui_desktop_save(uint32 offset, int x, in Line 3526  ui_desktop_save(uint32 offset, int x, in
3526          if (g_ownbackstore)          if (g_ownbackstore)
3527          {          {
3528                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3529                    exit_if_null(image);
3530          }          }
3531          else          else
3532          {          {
3533                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3534                  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);
3535                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3536                    exit_if_null(image);
3537                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3538          }          }
3539    
# Line 2712  ui_desktop_restore(uint32 offset, int x, Line 3555  ui_desktop_restore(uint32 offset, int x,
3555                  return;                  return;
3556    
3557          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3558                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3559    
3560          if (g_ownbackstore)          if (g_ownbackstore)
3561          {          {
3562                  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);
3563                  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);
3564                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3565                                            (g_display, g_backstore, sw->wnd, g_gc,
3566                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3567          }          }
3568          else          else
3569          {          {
3570                  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);
3571                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3572                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3573                                             x - sw->xoffset, y - sw->yoffset));
3574          }          }
3575    
3576          XFree(image);          XFree(image);
# Line 2737  void Line 3586  void
3586  ui_end_update(void)  ui_end_update(void)
3587  {  {
3588  }  }
3589    
3590    
3591    void
3592    ui_seamless_begin(RD_BOOL hidden)
3593    {
3594            if (!g_seamless_rdp)
3595                    return;
3596    
3597            if (g_seamless_started)
3598                    return;
3599    
3600            g_seamless_started = True;
3601            g_seamless_hidden = hidden;
3602    
3603            if (!hidden)
3604                    ui_seamless_toggle();
3605    }
3606    
3607    
3608    void
3609    ui_seamless_hide_desktop()
3610    {
3611            if (!g_seamless_rdp)
3612                    return;
3613    
3614            if (!g_seamless_started)
3615                    return;
3616    
3617            if (g_seamless_active)
3618                    ui_seamless_toggle();
3619    
3620            g_seamless_hidden = True;
3621    }
3622    
3623    
3624    void
3625    ui_seamless_unhide_desktop()
3626    {
3627            if (!g_seamless_rdp)
3628                    return;
3629    
3630            if (!g_seamless_started)
3631                    return;
3632    
3633            g_seamless_hidden = False;
3634    
3635            ui_seamless_toggle();
3636    }
3637    
3638    
3639    void
3640    ui_seamless_toggle()
3641    {
3642            if (!g_seamless_rdp)
3643                    return;
3644    
3645            if (!g_seamless_started)
3646                    return;
3647    
3648            if (g_seamless_hidden)
3649                    return;
3650    
3651            if (g_seamless_active)
3652            {
3653                    /* Deactivate */
3654                    while (g_seamless_windows)
3655                    {
3656                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3657                            sw_remove_window(g_seamless_windows);
3658                    }
3659                    XMapWindow(g_display, g_wnd);
3660            }
3661            else
3662            {
3663                    /* Activate */
3664                    XUnmapWindow(g_display, g_wnd);
3665                    seamless_send_sync();
3666            }
3667    
3668            g_seamless_active = !g_seamless_active;
3669    }
3670    
3671    
3672    void
3673    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3674                              unsigned long flags)
3675    {
3676            Window wnd;
3677            XSetWindowAttributes attribs;
3678            XClassHint *classhints;
3679            XSizeHints *sizehints;
3680            XWMHints *wmhints;
3681            long input_mask;
3682            seamless_window *sw, *sw_parent;
3683    
3684            if (!g_seamless_active)
3685                    return;
3686    
3687            /* Ignore CREATEs for existing windows */
3688            sw = sw_get_window_by_id(id);
3689            if (sw)
3690                    return;
3691    
3692            get_window_attribs(&attribs);
3693            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3694                                InputOutput, g_visual,
3695                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3696    
3697            XStoreName(g_display, wnd, "SeamlessRDP");
3698            ewmh_set_wm_name(wnd, "SeamlessRDP");
3699    
3700            mwm_hide_decorations(wnd);
3701    
3702            classhints = XAllocClassHint();
3703            if (classhints != NULL)
3704            {
3705                    classhints->res_name = "rdesktop";
3706                    classhints->res_class = "SeamlessRDP";
3707                    XSetClassHint(g_display, wnd, classhints);
3708                    XFree(classhints);
3709            }
3710    
3711            /* WM_NORMAL_HINTS */
3712            sizehints = XAllocSizeHints();
3713            if (sizehints != NULL)
3714            {
3715                    sizehints->flags = USPosition;
3716                    XSetWMNormalHints(g_display, wnd, sizehints);
3717                    XFree(sizehints);
3718            }
3719    
3720            /* Parent-less transient windows */
3721            if (parent == 0xFFFFFFFF)
3722            {
3723                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3724                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3725                       using some other hints. */
3726                    ewmh_set_window_popup(wnd);
3727            }
3728            /* Normal transient windows */
3729            else if (parent != 0x00000000)
3730            {
3731                    sw_parent = sw_get_window_by_id(parent);
3732                    if (sw_parent)
3733                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3734                    else
3735                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3736            }
3737    
3738            if (flags & SEAMLESSRDP_CREATE_MODAL)
3739            {
3740                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3741                       somewhat at least */
3742                    if (parent == 0x00000000)
3743                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3744                    ewmh_set_window_modal(wnd);
3745            }
3746    
3747            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3748            {
3749                    /* Make window always-on-top */
3750                    ewmh_set_window_above(wnd);
3751            }
3752    
3753            /* FIXME: Support for Input Context:s */
3754    
3755            get_input_mask(&input_mask);
3756            input_mask |= PropertyChangeMask;
3757    
3758            XSelectInput(g_display, wnd, input_mask);
3759    
3760            /* handle the WM_DELETE_WINDOW protocol. */
3761            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3762    
3763            sw = xmalloc(sizeof(seamless_window));
3764    
3765            memset(sw, 0, sizeof(seamless_window));
3766    
3767            sw->wnd = wnd;
3768            sw->id = id;
3769            sw->group = sw_find_group(group, False);
3770            sw->group->refcnt++;
3771            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3772            sw->desktop = 0;
3773            sw->position_timer = xmalloc(sizeof(struct timeval));
3774            timerclear(sw->position_timer);
3775    
3776            sw->outstanding_position = False;
3777            sw->outpos_serial = 0;
3778            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3779            sw->outpos_width = sw->outpos_height = 0;
3780    
3781            sw->next = g_seamless_windows;
3782            g_seamless_windows = sw;
3783    
3784            /* WM_HINTS */
3785            wmhints = XAllocWMHints();
3786            if (wmhints)
3787            {
3788                    wmhints->flags = WindowGroupHint;
3789                    wmhints->window_group = sw->group->wnd;
3790                    XSetWMHints(g_display, sw->wnd, wmhints);
3791                    XFree(wmhints);
3792            }
3793    }
3794    
3795    
3796    void
3797    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3798    {
3799            seamless_window *sw;
3800    
3801            if (!g_seamless_active)
3802                    return;
3803    
3804            sw = sw_get_window_by_id(id);
3805            if (!sw)
3806            {
3807                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3808                    return;
3809            }
3810    
3811            XDestroyWindow(g_display, sw->wnd);
3812            sw_remove_window(sw);
3813    }
3814    
3815    
3816    void
3817    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3818    {
3819            seamless_window *sw, *sw_next;
3820    
3821            if (!g_seamless_active)
3822                    return;
3823    
3824            for (sw = g_seamless_windows; sw; sw = sw_next)
3825            {
3826                    sw_next = sw->next;
3827    
3828                    if (sw->group->id == id)
3829                    {
3830                            XDestroyWindow(g_display, sw->wnd);
3831                            sw_remove_window(sw);
3832                    }
3833            }
3834    }
3835    
3836    
3837    void
3838    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3839                        const char *data, int chunk_len)
3840    {
3841            seamless_window *sw;
3842    
3843            if (!g_seamless_active)
3844                    return;
3845    
3846            sw = sw_get_window_by_id(id);
3847            if (!sw)
3848            {
3849                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3850                    return;
3851            }
3852    
3853            if (chunk == 0)
3854            {
3855                    if (sw->icon_size)
3856                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3857    
3858                    if (strcmp(format, "RGBA") != 0)
3859                    {
3860                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3861                            return;
3862                    }
3863    
3864                    sw->icon_size = width * height * 4;
3865                    if (sw->icon_size > 32 * 32 * 4)
3866                    {
3867                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3868                            sw->icon_size = 0;
3869                            return;
3870                    }
3871    
3872                    sw->icon_offset = 0;
3873            }
3874            else
3875            {
3876                    if (!sw->icon_size)
3877                            return;
3878            }
3879    
3880            if (chunk_len > (sw->icon_size - sw->icon_offset))
3881            {
3882                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3883                            chunk_len, sw->icon_size - sw->icon_offset);
3884                    sw->icon_size = 0;
3885                    return;
3886            }
3887    
3888            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3889            sw->icon_offset += chunk_len;
3890    
3891            if (sw->icon_offset == sw->icon_size)
3892            {
3893                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3894                    sw->icon_size = 0;
3895            }
3896    }
3897    
3898    
3899    void
3900    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3901    {
3902            seamless_window *sw;
3903    
3904            if (!g_seamless_active)
3905                    return;
3906    
3907            sw = sw_get_window_by_id(id);
3908            if (!sw)
3909            {
3910                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3911                    return;
3912            }
3913    
3914            if (strcmp(format, "RGBA") != 0)
3915            {
3916                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3917                    return;
3918            }
3919    
3920            ewmh_del_icon(sw->wnd, width, height);
3921    }
3922    
3923    
3924    void
3925    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3926    {
3927            seamless_window *sw;
3928    
3929            if (!g_seamless_active)
3930                    return;
3931    
3932            sw = sw_get_window_by_id(id);
3933            if (!sw)
3934            {
3935                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3936                    return;
3937            }
3938    
3939            /* We ignore server updates until it has handled our request. */
3940            if (sw->outstanding_position)
3941                    return;
3942    
3943            if (!width || !height)
3944                    /* X11 windows must be at least 1x1 */
3945                    return;
3946    
3947            sw->xoffset = x;
3948            sw->yoffset = y;
3949            sw->width = width;
3950            sw->height = height;
3951    
3952            /* If we move the window in a maximized state, then KDE won't
3953               accept restoration */
3954            switch (sw->state)
3955            {
3956                    case SEAMLESSRDP_MINIMIZED:
3957                    case SEAMLESSRDP_MAXIMIZED:
3958                            return;
3959            }
3960    
3961            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3962            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3963    }
3964    
3965    
3966    void
3967    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3968    {
3969            seamless_window *sw;
3970            XWindowChanges values;
3971            unsigned long restack_serial;
3972    
3973            if (!g_seamless_active)
3974                    return;
3975    
3976            sw = sw_get_window_by_id(id);
3977            if (!sw)
3978            {
3979                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3980                    return;
3981            }
3982    
3983            if (behind)
3984            {
3985                    seamless_window *sw_behind;
3986    
3987                    sw_behind = sw_get_window_by_id(behind);
3988                    if (!sw_behind)
3989                    {
3990                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
3991                            return;
3992                    }
3993    
3994                    if (!g_seamless_broken_restack)
3995                    {
3996                            values.stack_mode = Below;
3997                            values.sibling = sw_behind->wnd;
3998                            restack_serial = XNextRequest(g_display);
3999                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
4000                                                 CWStackMode | CWSibling, &values);
4001                            sw_wait_configurenotify(sw->wnd, restack_serial);
4002                    }
4003            }
4004            else
4005            {
4006                    values.stack_mode = Above;
4007                    restack_serial = XNextRequest(g_display);
4008                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4009                                         &values);
4010                    sw_wait_configurenotify(sw->wnd, restack_serial);
4011            }
4012    
4013            sw_restack_window(sw, behind);
4014    
4015            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4016            {
4017                    /* Make window always-on-top */
4018                    ewmh_set_window_above(sw->wnd);
4019            }
4020    }
4021    
4022    
4023    void
4024    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4025    {
4026            seamless_window *sw;
4027    
4028            if (!g_seamless_active)
4029                    return;
4030    
4031            sw = sw_get_window_by_id(id);
4032            if (!sw)
4033            {
4034                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4035                    return;
4036            }
4037    
4038            /* FIXME: Might want to convert the name for non-EWMH WMs */
4039            XStoreName(g_display, sw->wnd, title);
4040            ewmh_set_wm_name(sw->wnd, title);
4041    }
4042    
4043    
4044    void
4045    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
4046    {
4047            seamless_window *sw;
4048    
4049            if (!g_seamless_active)
4050                    return;
4051    
4052            sw = sw_get_window_by_id(id);
4053            if (!sw)
4054            {
4055                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
4056                    return;
4057            }
4058    
4059            switch (state)
4060            {
4061                    case SEAMLESSRDP_NORMAL:
4062                    case SEAMLESSRDP_MAXIMIZED:
4063                            ewmh_change_state(sw->wnd, state);
4064                            XMapWindow(g_display, sw->wnd);
4065                            break;
4066                    case SEAMLESSRDP_MINIMIZED:
4067                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4068                               the Window Manager should probably just ignore the request, since
4069                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4070                               such as minimization, rather than an independent state." Besides,
4071                               XIconifyWindow is easier. */
4072                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4073                            {
4074                                    XWMHints *hints;
4075                                    hints = XGetWMHints(g_display, sw->wnd);
4076                                    if (hints)
4077                                    {
4078                                            hints->flags |= StateHint;
4079                                            hints->initial_state = IconicState;
4080                                            XSetWMHints(g_display, sw->wnd, hints);
4081                                            XFree(hints);
4082                                    }
4083                                    XMapWindow(g_display, sw->wnd);
4084                            }
4085                            else
4086                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4087                            break;
4088                    default:
4089                            warning("SeamlessRDP: Invalid state %d\n", state);
4090                            break;
4091            }
4092    
4093            sw->state = state;
4094    }
4095    
4096    
4097    void
4098    ui_seamless_syncbegin(unsigned long flags)
4099    {
4100            if (!g_seamless_active)
4101                    return;
4102    
4103            /* Destroy all seamless windows */
4104            while (g_seamless_windows)
4105            {
4106                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4107                    sw_remove_window(g_seamless_windows);
4108            }
4109    }
4110    
4111    
4112    void
4113    ui_seamless_ack(unsigned int serial)
4114    {
4115            seamless_window *sw;
4116            for (sw = g_seamless_windows; sw; sw = sw->next)
4117            {
4118                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4119                    {
4120                            sw->xoffset = sw->outpos_xoffset;
4121                            sw->yoffset = sw->outpos_yoffset;
4122                            sw->width = sw->outpos_width;
4123                            sw->height = sw->outpos_height;
4124                            sw->outstanding_position = False;
4125    
4126                            /* Do a complete redraw of the window as part of the
4127                               completion of the move. This is to remove any
4128                               artifacts caused by our lack of synchronization. */
4129                            XCopyArea(g_display, g_backstore,
4130                                      sw->wnd, g_gc,
4131                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4132    
4133                            break;
4134                    }
4135            }
4136    }

Legend:
Removed from v.1042  
changed lines
  Added in v.1463

  ViewVC Help
Powered by ViewVC 1.1.26