/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

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

sourceforge.net/trunk/rdesktop/xwin.c revision 1040 by astrand, Tue Jan 24 12:24:40 2006 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1181 by ossman_, Tue Mar 21 15:29:47 2006 UTC
# Line 28  Line 28 
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31    /* We can't include Xproto.h because of conflicting defines for BOOL */
32    #define X_ConfigureWindow              12
33    
34  extern int g_width;  extern int g_width;
35  extern int g_height;  extern int g_height;
36  extern int g_xpos;  extern int g_xpos;
# Line 38  extern BOOL g_fullscreen; Line 41  extern BOOL g_fullscreen;
41  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
42  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
43  extern char g_title[];  extern char g_title[];
44  extern int g_server_bpp;  /* Color depth of the RDP session.
45       As of RDP 5.1, it may be 8, 15, 16 or 24. */
46    extern int g_server_depth;
47  extern int g_win_button_size;  extern int g_win_button_size;
48    
49  Display *g_display;  Display *g_display;
# Line 46  Time g_last_gesturetime; Line 51  Time g_last_gesturetime;
51  static int g_x_socket;  static int g_x_socket;
52  static Screen *g_screen;  static Screen *g_screen;
53  Window g_wnd;  Window g_wnd;
54    
55    /* SeamlessRDP support */
56    typedef struct _seamless_group
57    {
58            Window wnd;
59            unsigned long id;
60            unsigned int refcnt;
61    } seamless_group;
62    typedef struct _seamless_window
63    {
64            Window wnd;
65            unsigned long id;
66            unsigned long behind;
67            seamless_group *group;
68            int xoffset, yoffset;
69            int width, height;
70            int state;              /* normal/minimized/maximized. */
71            unsigned int desktop;
72            struct timeval *position_timer;
73    
74            BOOL outstanding_position;
75            unsigned int outpos_serial;
76            int outpos_xoffset, outpos_yoffset;
77            int outpos_width, outpos_height;
78    
79            struct _seamless_window *next;
80    } seamless_window;
81    static seamless_window *g_seamless_windows = NULL;
82    static unsigned long g_seamless_focused = 0;
83    static BOOL g_seamless_started = False; /* Server end is up and running */
84    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
85    extern BOOL g_seamless_rdp;
86    
87  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
88  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
89  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
90  static GC g_gc = NULL;  static GC g_gc = NULL;
91  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
92  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
93    static XRectangle g_clip_rectangle;
94  static Visual *g_visual;  static Visual *g_visual;
95    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
96       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
97       as far as we're concerned. */
98  static int g_depth;  static int g_depth;
99    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
100       This may be larger than g_depth, in which case some of the bits would
101       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
102  static int g_bpp;  static int g_bpp;
103  static XIM g_IM;  static XIM g_IM;
104  static XIC g_IC;  static XIC g_IC;
# Line 61  static XModifierKeymap *g_mod_map; Line 106  static XModifierKeymap *g_mod_map;
106  static Cursor g_current_cursor;  static Cursor g_current_cursor;
107  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
108  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
109    extern Atom g_net_wm_state_atom;
110    extern Atom g_net_wm_desktop_atom;
111  static BOOL g_focused;  static BOOL g_focused;
112  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
113  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
114       1) visual has 15, 16 or 24 depth and the same color channel masks
115          as its RDP equivalent (implies X server is LE),
116       2) host is LE
117       This will trigger an optimization whose real value is questionable.
118    */
119    static BOOL g_compatible_arch;
120    /* Indicates whether RDP's bitmaps and our XImages have the same
121       binary format. If so, we can avoid an expensive translation.
122       Note that this can be true when g_compatible_arch is false,
123       e.g.:
124      
125         RDP(LE) <-> host(BE) <-> X-Server(LE)
126        
127       ('host' is the machine running rdesktop; the host simply memcpy's
128        so its endianess doesn't matter)
129     */
130    static BOOL g_no_translate_image = False;
131    
132  /* endianness */  /* endianness */
133  static BOOL g_host_be;  static BOOL g_host_be;
# Line 108  typedef struct Line 172  typedef struct
172  }  }
173  PixelColour;  PixelColour;
174    
175    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
176            do { \
177                    seamless_window *sw; \
178                    XRectangle rect; \
179                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
180                        rect.x = g_clip_rectangle.x - sw->xoffset; \
181                        rect.y = g_clip_rectangle.y - sw->yoffset; \
182                        rect.width = g_clip_rectangle.width; \
183                        rect.height = g_clip_rectangle.height; \
184                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
185                        func args; \
186                    } \
187                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
188            } while (0)
189    
190    static void
191    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
192    {
193            points[0].x -= xoffset;
194            points[0].y -= yoffset;
195            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
196            points[0].x += xoffset;
197            points[0].y += yoffset;
198    }
199    
200    static void
201    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
202    {
203            points[0].x -= xoffset;
204            points[0].y -= yoffset;
205            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
206            points[0].x += xoffset;
207            points[0].y += yoffset;
208    }
209    
210  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
211  { \  { \
212          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
213            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
214          if (g_ownbackstore) \          if (g_ownbackstore) \
215                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
216  }  }
# Line 126  PixelColour; Line 225  PixelColour;
225          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
226          if (g_ownbackstore) \          if (g_ownbackstore) \
227                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
228            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
229  }  }
230    
231  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 134  PixelColour; Line 234  PixelColour;
234          { \          { \
235                  case 0: /* Outline */ \                  case 0: /* Outline */ \
236                          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); \
237                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
238                          if (g_ownbackstore) \                          if (g_ownbackstore) \
239                                  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); \
240                          break; \                          break; \
241                  case 1: /* Filled */ \                  case 1: /* Filled */ \
242                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
243                                     cx, cy, 0, 360*64); \
244                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
245                          if (g_ownbackstore) \                          if (g_ownbackstore) \
246                                  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); \
247                          break; \                          break; \
# Line 150  extern BOOL g_owncolmap; Line 253  extern BOOL g_owncolmap;
253  static Colormap g_xcolmap;  static Colormap g_xcolmap;
254  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
255    
256  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
257  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
258  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
259    
# Line 176  static int rop2_map[] = { Line 279  static int rop2_map[] = {
279  #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]); }
280  #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); }
281    
282    static seamless_window *
283    sw_get_window_by_id(unsigned long id)
284    {
285            seamless_window *sw;
286            for (sw = g_seamless_windows; sw; sw = sw->next)
287            {
288                    if (sw->id == id)
289                            return sw;
290            }
291            return NULL;
292    }
293    
294    
295    static seamless_window *
296    sw_get_window_by_wnd(Window wnd)
297    {
298            seamless_window *sw;
299            for (sw = g_seamless_windows; sw; sw = sw->next)
300            {
301                    if (sw->wnd == wnd)
302                            return sw;
303            }
304            return NULL;
305    }
306    
307    
308    static void
309    sw_remove_window(seamless_window * win)
310    {
311            seamless_window *sw, **prevnext = &g_seamless_windows;
312            for (sw = g_seamless_windows; sw; sw = sw->next)
313            {
314                    if (sw == win)
315                    {
316                            *prevnext = sw->next;
317                            sw->group->refcnt--;
318                            if (sw->group->refcnt == 0)
319                            {
320                                    XDestroyWindow(g_display, sw->group->wnd);
321                                    xfree(sw->group);
322                            }
323                            xfree(sw);
324                            return;
325                    }
326                    prevnext = &sw->next;
327            }
328            return;
329    }
330    
331    
332    /* Move all windows except wnd to new desktop */
333    static void
334    sw_all_to_desktop(Window wnd, unsigned int desktop)
335    {
336            seamless_window *sw;
337            for (sw = g_seamless_windows; sw; sw = sw->next)
338            {
339                    if (sw->wnd == wnd)
340                            continue;
341                    if (sw->desktop != desktop)
342                    {
343                            ewmh_move_to_desktop(sw->wnd, desktop);
344                            sw->desktop = desktop;
345                    }
346            }
347    }
348    
349    
350    /* Send our position */
351    static void
352    sw_update_position(seamless_window * sw)
353    {
354            XWindowAttributes wa;
355            int x, y;
356            Window child_return;
357            unsigned int serial;
358    
359            XGetWindowAttributes(g_display, sw->wnd, &wa);
360            XTranslateCoordinates(g_display, sw->wnd, wa.root,
361                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
362    
363            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
364    
365            sw->outstanding_position = True;
366            sw->outpos_serial = serial;
367    
368            sw->outpos_xoffset = x;
369            sw->outpos_yoffset = y;
370            sw->outpos_width = wa.width;
371            sw->outpos_height = wa.height;
372    }
373    
374    
375    /* Check if it's time to send our position */
376    static void
377    sw_check_timers()
378    {
379            seamless_window *sw;
380            struct timeval now;
381    
382            gettimeofday(&now, NULL);
383            for (sw = g_seamless_windows; sw; sw = sw->next)
384            {
385                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
386                    {
387                            timerclear(sw->position_timer);
388                            sw_update_position(sw);
389                    }
390            }
391    }
392    
393    
394    static void
395    sw_restack_window(seamless_window * sw, unsigned long behind)
396    {
397            seamless_window *sw_above;
398    
399            /* Remove window from stack */
400            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
401            {
402                    if (sw_above->behind == sw->id)
403                            break;
404            }
405    
406            if (sw_above)
407                    sw_above->behind = sw->behind;
408    
409            /* And then add it at the new position */
410    
411            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
412            {
413                    if (sw_above->behind == behind)
414                            break;
415            }
416    
417            if (sw_above)
418                    sw_above->behind = sw->id;
419    
420            sw->behind = behind;
421    }
422    
423    
424    static void
425    sw_handle_restack(seamless_window * sw)
426    {
427            Status status;
428            Window root, parent, *children;
429            unsigned int nchildren, i;
430            seamless_window *sw_below;
431    
432            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
433                                &root, &parent, &children, &nchildren);
434            if (!status || !nchildren)
435                    return;
436    
437            sw_below = NULL;
438    
439            i = 0;
440            while (children[i] != sw->wnd)
441            {
442                    i++;
443                    if (i >= nchildren)
444                            return;
445            }
446    
447            for (i++; i < nchildren; i++)
448            {
449                    sw_below = sw_get_window_by_wnd(children[i]);
450                    if (sw_below)
451                            break;
452            }
453    
454            if (!sw_below && !sw->behind)
455                    return;
456            if (sw_below && (sw_below->id == sw->behind))
457                    return;
458    
459            if (sw_below)
460            {
461                    seamless_send_zchange(sw->id, sw_below->id, 0);
462                    sw_restack_window(sw, sw_below->id);
463            }
464            else
465            {
466                    seamless_send_zchange(sw->id, 0, 0);
467                    sw_restack_window(sw, 0);
468            }
469    }
470    
471    
472    static seamless_group *
473    sw_find_group(unsigned long id, BOOL dont_create)
474    {
475            seamless_window *sw;
476            seamless_group *sg;
477            XSetWindowAttributes attribs;
478    
479            for (sw = g_seamless_windows; sw; sw = sw->next)
480            {
481                    if (sw->group->id == id)
482                            return sw->group;
483            }
484    
485            if (dont_create)
486                    return NULL;
487    
488            sg = xmalloc(sizeof(seamless_group));
489    
490            sg->wnd =
491                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
492                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
493    
494            sg->id = id;
495            sg->refcnt = 0;
496    
497            return sg;
498    }
499    
500    
501  static void  static void
502  mwm_hide_decorations(void)  mwm_hide_decorations(Window wnd)
503  {  {
504          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
505          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 516  mwm_hide_decorations(void)
516                  return;                  return;
517          }          }
518    
519          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
520                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
521    
522  }  }
523    
524  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 552  mwm_hide_decorations(void)
552  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
553                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
554    
555    /* The following macros output the same octet sequences
556       on both BE and LE hosts: */
557    
558  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
559  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
560  #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 240  static uint32 Line 566  static uint32
566  translate_colour(uint32 colour)  translate_colour(uint32 colour)
567  {  {
568          PixelColour pc;          PixelColour pc;
569          switch (g_server_bpp)          switch (g_server_depth)
570          {          {
571                  case 15:                  case 15:
572                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 251  translate_colour(uint32 colour) Line 577  translate_colour(uint32 colour)
577                  case 24:                  case 24:
578                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
579                          break;                          break;
580                    default:
581                            /* Avoid warning */
582                            pc.red = 0;
583                            pc.green = 0;
584                            pc.blue = 0;
585                            break;
586          }          }
587          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
588  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 634  translate8to16(const uint8 * data, uint8
634  {  {
635          uint16 value;          uint16 value;
636    
637          if (g_arch_match)          if (g_compatible_arch)
638          {          {
639                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
640                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 668  translate8to24(const uint8 * data, uint8
668  {  {
669          uint32 value;          uint32 value;
670    
671          if (g_xserver_be)          if (g_compatible_arch)
672          {          {
673                  while (out < end)                  while (out < end)
674                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 691  translate8to32(const uint8 * data, uint8
691  {  {
692          uint32 value;          uint32 value;
693    
694          if (g_arch_match)          if (g_compatible_arch)
695          {          {
696                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
697                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 763  translate15to24(const uint16 * data, uin
763          uint16 pixel;          uint16 pixel;
764          PixelColour pc;          PixelColour pc;
765    
766          if (g_arch_match)          if (g_compatible_arch)
767          {          {
768                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
769                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 813  translate15to32(const uint16 * data, uin
813          uint32 value;          uint32 value;
814          PixelColour pc;          PixelColour pc;
815    
816          if (g_arch_match)          if (g_compatible_arch)
817          {          {
818                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
819                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 921  translate16to24(const uint16 * data, uin
921          uint16 pixel;          uint16 pixel;
922          PixelColour pc;          PixelColour pc;
923    
924          if (g_arch_match)          if (g_compatible_arch)
925          {          {
926                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
927                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 991  translate16to32(const uint16 * data, uin
991          uint32 value;          uint32 value;
992          PixelColour pc;          PixelColour pc;
993    
994          if (g_arch_match)          if (g_compatible_arch)
995          {          {
996                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
997                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 1120  translate24to32(const uint8 * data, uint
1120          uint32 value;          uint32 value;
1121          PixelColour pc;          PixelColour pc;
1122    
1123          if (g_arch_match)          if (g_compatible_arch)
1124          {          {
1125                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1126  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 1134  translate24to32(const uint8 * data, uint
1134  #else  #else
1135                  REPEAT4                  REPEAT4
1136                  (                  (
1137                   /* Only read 3 bytes. Reading 4 bytes means reading beyound buffer. */                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1138                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1139                   out += 4;                   out += 4;
1140                   data += 3;                   data += 3;
# Line 843  translate_image(int width, int height, u Line 1175  translate_image(int width, int height, u
1175          uint8 *out;          uint8 *out;
1176          uint8 *end;          uint8 *end;
1177    
1178          /* if server and xserver bpp match, */          /*
1179          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1180          /* just return data */             and arch(endian) matches, no need to translate:
1181          if (g_arch_match)             just return data.
1182               Note: select_visual should've already ensured g_no_translate
1183               is only set for compatible depths, but the RDP depth might've
1184               changed during connection negotiations.
1185             */
1186            if (g_no_translate_image)
1187          {          {
1188                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1189                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1190                  if (g_depth == 16 && g_server_bpp == 16)                      (g_depth == 24 && g_server_depth == 24))
                         return data;  
                 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)  
1191                          return data;                          return data;
1192          }          }
1193    
# Line 860  translate_image(int width, int height, u Line 1195  translate_image(int width, int height, u
1195          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1196          end = out + size;          end = out + size;
1197    
1198          switch (g_server_bpp)          switch (g_server_depth)
1199          {          {
1200                  case 24:                  case 24:
1201                          switch (g_bpp)                          switch (g_bpp)
# Line 958  calculate_shifts(uint32 mask, int *shift Line 1293  calculate_shifts(uint32 mask, int *shift
1293          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1294  }  }
1295    
1296  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1297  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1298     */
1299    static unsigned
1300    calculate_mask_weight(uint32 mask)
1301    {
1302            unsigned weight = 0;
1303            do
1304            {
1305                    weight += (mask & 1);
1306            }
1307            while (mask >>= 1);
1308            return weight;
1309    }
1310    
1311    static BOOL
1312    select_visual()
1313  {  {
         XVisualInfo vi;  
1314          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1315          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1316          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1317          XVisualInfo template;          XVisualInfo template;
1318          Bool TrueColorVisual = False;          int i;
1319            unsigned red_weight, blue_weight, green_weight;
1320    
1321          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1322          if (g_display == NULL)  
1323            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1324            if (pfm == NULL)
1325          {          {
1326                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1327                    XCloseDisplay(g_display);
1328                  return False;                  return False;
1329          }          }
1330    
1331          screen_num = DefaultScreen(g_display);          /* Search for best TrueColor visual */
         g_x_socket = ConnectionNumber(g_display);  
         g_screen = ScreenOfDisplay(g_display, screen_num);  
         g_depth = DefaultDepthOfScreen(g_screen);  
   
         /* Search for best TrueColor depth */  
1332          template.class = TrueColor;          template.class = TrueColor;
1333          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1334            g_visual = NULL;
1335            g_no_translate_image = False;
1336            g_compatible_arch = False;
1337            if (vmatches != NULL)
1338            {
1339                    for (i = 0; i < visuals_count; ++i)
1340                    {
1341                            XVisualInfo *visual_info = &vmatches[i];
1342    
1343                            /* Try to find a no-translation visual that'll
1344                               allow us to use RDP bitmaps directly as ZPixmaps. */
1345                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1346                                                   /* R5G5B5 */
1347                                                   (visual_info->red_mask == 0x7c00) &&
1348                                                   (visual_info->green_mask == 0x3e0) &&
1349                                                   (visual_info->blue_mask == 0x1f)) ||
1350                                                  ((visual_info->depth == 16) &&
1351                                                   /* R5G6B5 */
1352                                                   (visual_info->red_mask == 0xf800) &&
1353                                                   (visual_info->green_mask == 0x7e0) &&
1354                                                   (visual_info->blue_mask == 0x1f)) ||
1355                                                  ((visual_info->depth == 24) &&
1356                                                   /* R8G8B8 */
1357                                                   (visual_info->red_mask == 0xff0000) &&
1358                                                   (visual_info->green_mask == 0xff00) &&
1359                                                   (visual_info->blue_mask == 0xff))))
1360                            {
1361                                    g_visual = visual_info->visual;
1362                                    g_depth = visual_info->depth;
1363                                    g_compatible_arch = !g_host_be;
1364                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1365                                    if (g_no_translate_image)
1366                                            /* We found the best visual */
1367                                            break;
1368                            }
1369                            else
1370                            {
1371                                    g_compatible_arch = False;
1372                            }
1373    
1374                            if (visual_info->depth > 24)
1375                            {
1376                                    /* Avoid 32-bit visuals and likes like the plague.
1377                                       They're either untested or proven to work bad
1378                                       (e.g. nvidia's Composite 32-bit visual).
1379                                       Most implementation offer a 24-bit visual anyway. */
1380                                    continue;
1381                            }
1382    
1383          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1384          while (nvisuals >= 0)                             we have a translateXtoY function. */
1385          {                          BOOL can_translate_to_bpp = False;
1386                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1387                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1388                          g_depth = (vmatches + nvisuals)->depth;                          {
1389                                    if (pfm[j].depth == visual_info->depth)
1390                                    {
1391                                            if ((pfm[j].bits_per_pixel == 16) ||
1392                                                (pfm[j].bits_per_pixel == 24) ||
1393                                                (pfm[j].bits_per_pixel == 32))
1394                                            {
1395                                                    can_translate_to_bpp = True;
1396                                            }
1397                                            break;
1398                                    }
1399                            }
1400    
1401                            /* Prefer formats which have the most colour depth.
1402                               We're being truly aristocratic here, minding each
1403                               weight on its own. */
1404                            if (can_translate_to_bpp)
1405                            {
1406                                    unsigned vis_red_weight =
1407                                            calculate_mask_weight(visual_info->red_mask);
1408                                    unsigned vis_green_weight =
1409                                            calculate_mask_weight(visual_info->green_mask);
1410                                    unsigned vis_blue_weight =
1411                                            calculate_mask_weight(visual_info->blue_mask);
1412                                    if ((vis_red_weight >= red_weight)
1413                                        && (vis_green_weight >= green_weight)
1414                                        && (vis_blue_weight >= blue_weight))
1415                                    {
1416                                            red_weight = vis_red_weight;
1417                                            green_weight = vis_green_weight;
1418                                            blue_weight = vis_blue_weight;
1419                                            g_visual = visual_info->visual;
1420                                            g_depth = visual_info->depth;
1421                                    }
1422                            }
1423                  }                  }
1424                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1425          }          }
1426    
1427          test = 1;          if (g_visual != NULL)
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
         if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))  
1428          {          {
1429                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1430                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1431                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1432                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
                 /* Do not allocate colours on a TrueColor visual */  
                 if (g_visual->class == TrueColor)  
                 {  
                         g_owncolmap = False;  
                 }  
1433          }          }
1434          else          else
1435          {          {
1436                  /* need a truecolour visual */                  template.class = PseudoColor;
1437                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1438                  {                  template.colormap_size = 256;
1439                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1440                            XGetVisualInfo(g_display,
1441                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1442                                           &template, &visuals_count);
1443                    if (vmatches == NULL)
1444                    {
1445                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1446                            XCloseDisplay(g_display);
1447                            XFree(pfm);
1448                          return False;                          return False;
1449                  }                  }
1450    
1451                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1452                  g_owncolmap = False;                  g_owncolmap = True;
1453                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1454                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1455                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1456    
1457                  /* if RGB video and everything is little endian */          g_bpp = 0;
1458                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1459                      !g_xserver_be && !g_host_be)          {
1460                    XPixmapFormatValues *pf = &pfm[i];
1461                    if (pf->depth == g_depth)
1462                  {                  {
1463                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1464                                                g_blue_shift_l == 0))  
1465                            if (g_no_translate_image)
1466                          {                          {
1467                                  g_arch_match = True;                                  switch (g_server_depth)
1468                                    {
1469                                            case 15:
1470                                            case 16:
1471                                                    if (g_bpp != 16)
1472                                                            g_no_translate_image = False;
1473                                                    break;
1474                                            case 24:
1475                                                    /* Yes, this will force image translation
1476                                                       on most modern servers which use 32 bits
1477                                                       for R8G8B8. */
1478                                                    if (g_bpp != 24)
1479                                                            g_no_translate_image = False;
1480                                                    break;
1481                                            default:
1482                                                    g_no_translate_image = False;
1483                                                    break;
1484                                    }
1485                          }                          }
                 }  
1486    
1487                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1488                  {                             there's just a single entry for every depth,
1489                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1490                            break;
1491                  }                  }
1492          }          }
1493            XFree(pfm);
1494            pfm = NULL;
1495            return True;
1496    }
1497    
1498          pfm = XListPixmapFormats(g_display, &i);  static XErrorHandler g_old_error_handler;
1499          if (pfm != NULL)  
1500    static int
1501    error_handler(Display * dpy, XErrorEvent * eev)
1502    {
1503            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1504          {          {
1505                  /* Use maximum bpp for this depth - this is generally                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1506                     desirable, e.g. 24 bits->32 bits. */                  fprintf(stderr,
1507                  while (i--)                          "This is most likely caused by a broken window manager (commonly KWin).\n");
1508                  {                  return 0;
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1509          }          }
1510    
1511          if (g_bpp < 8)          return g_old_error_handler(dpy, eev);
1512    }
1513    
1514    BOOL
1515    ui_init(void)
1516    {
1517            int screen_num;
1518    
1519            g_display = XOpenDisplay(NULL);
1520            if (g_display == NULL)
1521          {          {
1522                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(g_display);  
1523                  return False;                  return False;
1524          }          }
1525    
1526            {
1527                    uint16 endianess_test = 1;
1528                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1529            }
1530    
1531            g_old_error_handler = XSetErrorHandler(error_handler);
1532    
1533            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1534            screen_num = DefaultScreen(g_display);
1535            g_x_socket = ConnectionNumber(g_display);
1536            g_screen = ScreenOfDisplay(g_display, screen_num);
1537            g_depth = DefaultDepthOfScreen(g_screen);
1538    
1539            if (!select_visual())
1540                    return False;
1541    
1542            if (g_no_translate_image)
1543            {
1544                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1545            }
1546    
1547            if (g_server_depth > g_bpp)
1548            {
1549                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1550                            g_server_depth, g_bpp);
1551            }
1552    
1553            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1554                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1555    
1556          if (!g_owncolmap)          if (!g_owncolmap)
1557          {          {
1558                  g_xcolmap =                  g_xcolmap =
1559                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1560                                          AllocNone);                                          AllocNone);
1561                  if (g_depth <= 8)                  if (g_depth <= 8)
1562                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");                          warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1563          }          }
1564    
1565          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1566          {          {
1567                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1568                  g_ownbackstore = True;                  g_ownbackstore = True;
1569          }          }
1570    
# Line 1088  ui_init(void) Line 1575  ui_init(void)
1575          {          {
1576                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1577                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1578                    g_using_full_workarea = True;
1579          }          }
1580          else if (g_width < 0)          else if (g_width < 0)
1581          {          {
# Line 1101  ui_init(void) Line 1589  ui_init(void)
1589          {          {
1590                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1591                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
                 g_using_full_workarea = True;  
   
1592                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1593                  {                  {
1594                          g_width = cx;                          g_width = cx;
1595                          g_height = cy;                          g_height = cy;
1596                            g_using_full_workarea = True;
1597                  }                  }
1598                  else                  else
1599                  {                  {
1600                          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");
1601                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1602                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1603                  }                  }
1604          }          }
1605    
# Line 1127  ui_init(void) Line 1614  ui_init(void)
1614                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1615    
1616          xclip_init();          xclip_init();
1617            ewmh_init();
1618            if (g_seamless_rdp)
1619                    seamless_init();
1620    
1621          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1622    
1623          return True;          return True;
1624  }  }
# Line 1152  ui_deinit(void) Line 1642  ui_deinit(void)
1642          g_display = NULL;          g_display = NULL;
1643  }  }
1644    
1645    
1646    static void
1647    get_window_attribs(XSetWindowAttributes * attribs)
1648    {
1649            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1650            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1651            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1652            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1653            attribs->override_redirect = g_fullscreen;
1654            attribs->colormap = g_xcolmap;
1655    }
1656    
1657    static void
1658    get_input_mask(long *input_mask)
1659    {
1660            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1661                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1662    
1663            if (g_sendmotion)
1664                    *input_mask |= PointerMotionMask;
1665            if (g_ownbackstore)
1666                    *input_mask |= ExposureMask;
1667            if (g_fullscreen || g_grab_keyboard)
1668                    *input_mask |= EnterWindowMask;
1669            if (g_grab_keyboard)
1670                    *input_mask |= LeaveWindowMask;
1671    }
1672    
1673  BOOL  BOOL
1674  ui_create_window(void)  ui_create_window(void)
1675  {  {
# Line 1174  ui_create_window(void) Line 1692  ui_create_window(void)
1692          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1693                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1694    
1695          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;  
1696    
1697          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,
1698                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1186  ui_create_window(void) Line 1700  ui_create_window(void)
1700                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1701    
1702          if (g_gc == NULL)          if (g_gc == NULL)
1703            {
1704                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1705                    ui_reset_clip();
1706            }
1707    
1708          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1709                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1203  ui_create_window(void) Line 1720  ui_create_window(void)
1720          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1721    
1722          if (g_hide_decorations)          if (g_hide_decorations)
1723                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1724    
1725          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1726          if (classhints != NULL)          if (classhints != NULL)
# Line 1230  ui_create_window(void) Line 1747  ui_create_window(void)
1747                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1748          }          }
1749    
1750          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;  
1751    
1752          if (g_IM != NULL)          if (g_IM != NULL)
1753          {          {
# Line 1253  ui_create_window(void) Line 1760  ui_create_window(void)
1760          }          }
1761    
1762          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1763    
1764            XMapWindow(g_display, g_wnd);
1765          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1766          do          do
1767          {          {
# Line 1325  xwin_toggle_fullscreen(void) Line 1832  xwin_toggle_fullscreen(void)
1832  {  {
1833          Pixmap contents = 0;          Pixmap contents = 0;
1834    
1835            if (g_seamless_active)
1836                    /* Turn off SeamlessRDP mode */
1837                    ui_seamless_toggle();
1838    
1839          if (!g_ownbackstore)          if (!g_ownbackstore)
1840          {          {
1841                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1413  handle_button_event(XEvent xevent, BOOL Line 1924  handle_button_event(XEvent xevent, BOOL
1924                  }                  }
1925          }          }
1926    
1927          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
1928                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
1929                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1930                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1931            }
1932            else
1933            {
1934                    /* SeamlessRDP */
1935                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1936                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1937            }
1938  }  }
1939    
1940    
1941  /* Process events in Xlib queue  /* Process events in Xlib queue
1942     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1943  static int  static int
# Line 1428  xwin_process_events(void) Line 1949  xwin_process_events(void)
1949          char str[256];          char str[256];
1950          Status status;          Status status;
1951          int events = 0;          int events = 0;
1952            seamless_window *sw;
1953    
1954          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1955          {          {
# Line 1442  xwin_process_events(void) Line 1964  xwin_process_events(void)
1964                  switch (xevent.type)                  switch (xevent.type)
1965                  {                  {
1966                          case VisibilityNotify:                          case VisibilityNotify:
1967                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1968                                            g_Unobscured =
1969                                                    xevent.xvisibility.state == VisibilityUnobscured;
1970    
1971                                  break;                                  break;
1972                          case ClientMessage:                          case ClientMessage:
1973                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1522  xwin_process_events(void) Line 2047  xwin_process_events(void)
2047                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2048                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2049                                                         CurrentTime);                                                         CurrentTime);
2050                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2051                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2052                                    {
2053                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2054                                                           xevent.xmotion.x, xevent.xmotion.y);
2055                                    }
2056                                    else
2057                                    {
2058                                            /* SeamlessRDP */
2059                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2060                                                           xevent.xmotion.x_root,
2061                                                           xevent.xmotion.y_root);
2062                                    }
2063                                  break;                                  break;
2064    
2065                          case FocusIn:                          case FocusIn:
# Line 1534  xwin_process_events(void) Line 2070  xwin_process_events(void)
2070                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2071                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2072                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2073    
2074                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2075                                    if (!sw)
2076                                            break;
2077    
2078                                    if (sw->id != g_seamless_focused)
2079                                    {
2080                                            seamless_send_focus(sw->id, 0);
2081                                            g_seamless_focused = sw->id;
2082                                    }
2083                                  break;                                  break;
2084    
2085                          case FocusOut:                          case FocusOut:
# Line 1566  xwin_process_events(void) Line 2112  xwin_process_events(void)
2112                                  break;                                  break;
2113    
2114                          case Expose:                          case Expose:
2115                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2116                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2117                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2118                                            xevent.xexpose.height,                                                    g_gc,
2119                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2120                                                      xevent.xexpose.width, xevent.xexpose.height,
2121                                                      xevent.xexpose.x, xevent.xexpose.y);
2122                                    }
2123                                    else
2124                                    {
2125                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2126                                            if (sw)
2127                                                    XCopyArea(g_display, g_backstore,
2128                                                              xevent.xexpose.window, g_gc,
2129                                                              xevent.xexpose.x + sw->xoffset,
2130                                                              xevent.xexpose.y + sw->yoffset,
2131                                                              xevent.xexpose.width,
2132                                                              xevent.xexpose.height, xevent.xexpose.x,
2133                                                              xevent.xexpose.y);
2134                                            else
2135                                            {
2136                                                    error("Expose for unknown window 0x%lx\n",
2137                                                          xevent.xexpose.window);
2138                                            }
2139                                    }
2140    
2141                                  break;                                  break;
2142    
2143                          case MappingNotify:                          case MappingNotify:
# Line 1599  xwin_process_events(void) Line 2166  xwin_process_events(void)
2166                                  break;                                  break;
2167                          case PropertyNotify:                          case PropertyNotify:
2168                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2169                                    if (xevent.xproperty.window == g_wnd)
2170                                            break;
2171                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2172                                            break;
2173    
2174                                    /* seamless */
2175                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2176                                    if (!sw)
2177                                            break;
2178    
2179                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2180                                        && (xevent.xproperty.state == PropertyNewValue))
2181                                    {
2182                                            sw->state = ewmh_get_window_state(sw->wnd);
2183                                            seamless_send_state(sw->id, sw->state, 0);
2184                                    }
2185    
2186                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2187                                        && (xevent.xproperty.state == PropertyNewValue))
2188                                    {
2189                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2190                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2191                                    }
2192    
2193                                  break;                                  break;
2194                          case MapNotify:                          case MapNotify:
2195                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2196                                            rdp_send_client_window_status(1);
2197                                  break;                                  break;
2198                          case UnmapNotify:                          case UnmapNotify:
2199                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2200                                            rdp_send_client_window_status(0);
2201                                    break;
2202                            case ConfigureNotify:
2203                                    if (!g_seamless_active)
2204                                            break;
2205    
2206                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2207                                    if (!sw)
2208                                    {
2209                                            error("ConfigureNotify for unknown window 0x%lx\n",
2210                                                  xevent.xconfigure.window);
2211                                    }
2212    
2213                                    gettimeofday(sw->position_timer, NULL);
2214                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2215                                        1000000)
2216                                    {
2217                                            sw->position_timer->tv_usec +=
2218                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2219                                            sw->position_timer->tv_sec += 1;
2220                                    }
2221                                    else
2222                                    {
2223                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2224                                    }
2225    
2226                                    sw_handle_restack(sw);
2227                                  break;                                  break;
2228                  }                  }
2229          }          }
# Line 1629  ui_select(int rdp_socket) Line 2248  ui_select(int rdp_socket)
2248                          /* User quit */                          /* User quit */
2249                          return 0;                          return 0;
2250    
2251                    if (g_seamless_active)
2252                            sw_check_timers();
2253    
2254                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2255                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2256                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1648  ui_select(int rdp_socket) Line 2270  ui_select(int rdp_socket)
2270    
2271                  /* add redirection handles */                  /* add redirection handles */
2272                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2273                    seamless_select_timeout(&tv);
2274    
2275                  n++;                  n++;
2276    
# Line 1689  ui_create_bitmap(int width, int height, Line 2312  ui_create_bitmap(int width, int height,
2312          uint8 *tdata;          uint8 *tdata;
2313          int bitmap_pad;          int bitmap_pad;
2314    
2315          if (g_server_bpp == 8)          if (g_server_depth == 8)
2316          {          {
2317                  bitmap_pad = 8;                  bitmap_pad = 8;
2318          }          }
# Line 1721  ui_paint_bitmap(int x, int y, int cx, in Line 2344  ui_paint_bitmap(int x, int y, int cx, in
2344          uint8 *tdata;          uint8 *tdata;
2345          int bitmap_pad;          int bitmap_pad;
2346    
2347          if (g_server_bpp == 8)          if (g_server_depth == 8)
2348          {          {
2349                  bitmap_pad = 8;                  bitmap_pad = 8;
2350          }          }
# Line 1741  ui_paint_bitmap(int x, int y, int cx, in Line 2364  ui_paint_bitmap(int x, int y, int cx, in
2364          {          {
2365                  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);
2366                  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);
2367                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2368                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2369                                             x - sw->xoffset, y - sw->yoffset));
2370          }          }
2371          else          else
2372          {          {
2373                  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);
2374                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2375                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2376                                             x - sw->xoffset, y - sw->yoffset));
2377          }          }
2378    
2379          XFree(image);          XFree(image);
# Line 1865  ui_set_cursor(HCURSOR cursor) Line 2494  ui_set_cursor(HCURSOR cursor)
2494  {  {
2495          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2496          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2497            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2498  }  }
2499    
2500  void  void
# Line 2006  ui_set_colourmap(HCOLOURMAP map) Line 2636  ui_set_colourmap(HCOLOURMAP map)
2636                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2637          }          }
2638          else          else
2639            {
2640                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2641                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2642            }
2643  }  }
2644    
2645  void  void
2646  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2647  {  {
2648          XRectangle rect;          g_clip_rectangle.x = x;
2649            g_clip_rectangle.y = y;
2650          rect.x = x;          g_clip_rectangle.width = cx;
2651          rect.y = y;          g_clip_rectangle.height = cy;
2652          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);  
2653  }  }
2654    
2655  void  void
2656  ui_reset_clip(void)  ui_reset_clip(void)
2657  {  {
2658          XRectangle rect;          g_clip_rectangle.x = 0;
2659            g_clip_rectangle.y = 0;
2660          rect.x = 0;          g_clip_rectangle.width = g_width;
2661          rect.y = 0;          g_clip_rectangle.height = g_height;
2662          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);  
2663  }  }
2664    
2665  void  void
# Line 2111  ui_patblt(uint8 opcode, Line 2740  ui_patblt(uint8 opcode,
2740    
2741          if (g_ownbackstore)          if (g_ownbackstore)
2742                  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);
2743            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2744                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2745                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2746  }  }
2747    
2748  void  void
# Line 2121  ui_screenblt(uint8 opcode, Line 2753  ui_screenblt(uint8 opcode,
2753          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2754          if (g_ownbackstore)          if (g_ownbackstore)
2755          {          {
2756                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2757                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2758                          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);  
                 }  
2759          }          }
2760          else          else
2761          {          {
2762                  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);
2763          }          }
2764    
2765            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2766                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2767                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2768    
2769          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2770  }  }
2771    
# Line 2148  ui_memblt(uint8 opcode, Line 2776  ui_memblt(uint8 opcode,
2776  {  {
2777          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2778          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);
2779            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2780                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2781                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2782          if (g_ownbackstore)          if (g_ownbackstore)
2783                  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);
2784          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2194  ui_line(uint8 opcode, Line 2825  ui_line(uint8 opcode,
2825          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2826          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2827          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2828            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2829                                                startx - sw->xoffset, starty - sw->yoffset,
2830                                                endx - sw->xoffset, endy - sw->yoffset));
2831          if (g_ownbackstore)          if (g_ownbackstore)
2832                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2833          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2291  ui_polyline(uint8 opcode, Line 2925  ui_polyline(uint8 opcode,
2925          if (g_ownbackstore)          if (g_ownbackstore)
2926                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2927                             CoordModePrevious);                             CoordModePrevious);
2928    
2929            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2930                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2931    
2932          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2933  }  }
2934    
# Line 2511  ui_draw_text(uint8 font, uint8 flags, ui Line 3149  ui_draw_text(uint8 font, uint8 flags, ui
3149          if (g_ownbackstore)          if (g_ownbackstore)
3150          {          {
3151                  if (boxcx > 1)                  if (boxcx > 1)
3152                    {
3153                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3154                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3155                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3156                                                    (g_display, g_backstore, sw->wnd, g_gc,
3157                                                     boxx, boxy,
3158                                                     boxcx, boxcy,
3159                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3160                    }
3161                  else                  else
3162                    {
3163                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3164                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3165                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3166                                                    (g_display, g_backstore, sw->wnd, g_gc,
3167                                                     clipx, clipy,
3168                                                     clipcx, clipcy, clipx - sw->xoffset,
3169                                                     clipy - sw->yoffset));
3170                    }
3171          }          }
3172  }  }
3173    
# Line 2561  ui_desktop_restore(uint32 offset, int x, Line 3213  ui_desktop_restore(uint32 offset, int x,
3213          {          {
3214                  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);
3215                  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);
3216                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3217                                            (g_display, g_backstore, sw->wnd, g_gc,
3218                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3219          }          }
3220          else          else
3221          {          {
3222                  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);
3223                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3224                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3225                                             x - sw->xoffset, y - sw->yoffset));
3226          }          }
3227    
3228          XFree(image);          XFree(image);
# Line 2580  void Line 3238  void
3238  ui_end_update(void)  ui_end_update(void)
3239  {  {
3240  }  }
3241    
3242    
3243    void
3244    ui_seamless_begin()
3245    {
3246            if (!g_seamless_rdp)
3247                    return;
3248    
3249            if (g_seamless_started)
3250                    return;
3251    
3252            g_seamless_started = True;
3253            ui_seamless_toggle();
3254    }
3255    
3256    
3257    void
3258    ui_seamless_toggle()
3259    {
3260            if (!g_seamless_rdp)
3261                    return;
3262    
3263            if (!g_seamless_started)
3264                    return;
3265    
3266            if (g_seamless_active)
3267            {
3268                    /* Deactivate */
3269                    while (g_seamless_windows)
3270                    {
3271                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3272                            sw_remove_window(g_seamless_windows);
3273                    }
3274                    XMapWindow(g_display, g_wnd);
3275            }
3276            else
3277            {
3278                    /* Activate */
3279                    XUnmapWindow(g_display, g_wnd);
3280                    seamless_send_sync();
3281            }
3282    
3283            g_seamless_active = !g_seamless_active;
3284    }
3285    
3286    
3287    void
3288    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3289                              unsigned long flags)
3290    {
3291            Window wnd;
3292            XSetWindowAttributes attribs;
3293            XClassHint *classhints;
3294            XSizeHints *sizehints;
3295            XWMHints *wmhints;
3296            long input_mask;
3297            seamless_window *sw, *sw_parent;
3298    
3299            if (!g_seamless_active)
3300                    return;
3301    
3302            /* Ignore CREATEs for existing windows */
3303            sw = sw_get_window_by_id(id);
3304            if (sw)
3305                    return;
3306    
3307            get_window_attribs(&attribs);
3308            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3309                                InputOutput, g_visual,
3310                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3311    
3312            XStoreName(g_display, wnd, "SeamlessRDP");
3313            ewmh_set_wm_name(wnd, "SeamlessRDP");
3314    
3315            mwm_hide_decorations(wnd);
3316    
3317            classhints = XAllocClassHint();
3318            if (classhints != NULL)
3319            {
3320                    classhints->res_name = "rdesktop";
3321                    classhints->res_class = "SeamlessRDP";
3322                    XSetClassHint(g_display, wnd, classhints);
3323                    XFree(classhints);
3324            }
3325    
3326            /* WM_NORMAL_HINTS */
3327            sizehints = XAllocSizeHints();
3328            if (sizehints != NULL)
3329            {
3330                    sizehints->flags = USPosition;
3331                    XSetWMNormalHints(g_display, wnd, sizehints);
3332                    XFree(sizehints);
3333            }
3334    
3335            /* Parent-less transient windows */
3336            if (parent == 0xFFFFFFFF)
3337            {
3338                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3339                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3340                       using some other hints. */
3341                    ewmh_set_window_popup(wnd);
3342            }
3343            /* Normal transient windows */
3344            else if (parent != 0x00000000)
3345            {
3346                    sw_parent = sw_get_window_by_id(parent);
3347                    if (sw_parent)
3348                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3349                    else
3350                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3351            }
3352    
3353            if (flags & SEAMLESSRDP_CREATE_MODAL)
3354            {
3355                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3356                       somewhat at least */
3357                    if (parent == 0x00000000)
3358                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3359                    ewmh_set_window_modal(wnd);
3360            }
3361    
3362            /* FIXME: Support for Input Context:s */
3363    
3364            get_input_mask(&input_mask);
3365            input_mask |= PropertyChangeMask;
3366    
3367            XSelectInput(g_display, wnd, input_mask);
3368    
3369            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3370               seamless window, we could try to close the window on the
3371               serverside, instead of terminating rdesktop */
3372            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3373    
3374            sw = xmalloc(sizeof(seamless_window));
3375            sw->wnd = wnd;
3376            sw->id = id;
3377            sw->behind = 0;
3378            sw->group = sw_find_group(group, False);
3379            sw->group->refcnt++;
3380            sw->xoffset = 0;
3381            sw->yoffset = 0;
3382            sw->width = 0;
3383            sw->height = 0;
3384            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3385            sw->desktop = 0;
3386            sw->position_timer = xmalloc(sizeof(struct timeval));
3387            timerclear(sw->position_timer);
3388    
3389            sw->outstanding_position = False;
3390            sw->outpos_serial = 0;
3391            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3392            sw->outpos_width = sw->outpos_height = 0;
3393    
3394            sw->next = g_seamless_windows;
3395            g_seamless_windows = sw;
3396    
3397            /* WM_HINTS */
3398            wmhints = XAllocWMHints();
3399            if (wmhints)
3400            {
3401                    wmhints->flags = WindowGroupHint;
3402                    wmhints->window_group = sw->group->wnd;
3403                    XSetWMHints(g_display, sw->wnd, wmhints);
3404                    XFree(wmhints);
3405            }
3406    }
3407    
3408    
3409    void
3410    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3411    {
3412            seamless_window *sw;
3413    
3414            if (!g_seamless_active)
3415                    return;
3416    
3417            sw = sw_get_window_by_id(id);
3418            if (!sw)
3419            {
3420                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3421                    return;
3422            }
3423    
3424            XDestroyWindow(g_display, sw->wnd);
3425            sw_remove_window(sw);
3426    }
3427    
3428    
3429    void
3430    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3431    {
3432            seamless_window *sw;
3433    
3434            if (!g_seamless_active)
3435                    return;
3436    
3437            sw = sw_get_window_by_id(id);
3438            if (!sw)
3439            {
3440                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3441                    return;
3442            }
3443    
3444            /* We ignore server updates until it has handled our request. */
3445            if (sw->outstanding_position)
3446                    return;
3447    
3448            if (!width || !height)
3449                    /* X11 windows must be at least 1x1 */
3450                    return;
3451    
3452            sw->xoffset = x;
3453            sw->yoffset = y;
3454            sw->width = width;
3455            sw->height = height;
3456    
3457            /* If we move the window in a maximized state, then KDE won't
3458               accept restoration */
3459            switch (sw->state)
3460            {
3461                    case SEAMLESSRDP_MINIMIZED:
3462                    case SEAMLESSRDP_MAXIMIZED:
3463                            return;
3464            }
3465    
3466            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3467            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3468    }
3469    
3470    
3471    void
3472    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3473    {
3474            seamless_window *sw;
3475    
3476            if (!g_seamless_active)
3477                    return;
3478    
3479            sw = sw_get_window_by_id(id);
3480            if (!sw)
3481            {
3482                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3483                    return;
3484            }
3485    
3486            if (behind)
3487            {
3488                    seamless_window *sw_behind;
3489                    Window wnds[2];
3490    
3491                    sw_behind = sw_get_window_by_id(behind);
3492                    if (!sw_behind)
3493                    {
3494                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3495                                    behind);
3496                            return;
3497                    }
3498    
3499                    wnds[1] = sw_behind->wnd;
3500                    wnds[0] = sw->wnd;
3501    
3502                    XRestackWindows(g_display, wnds, 2);
3503            }
3504            else
3505            {
3506                    XRaiseWindow(g_display, sw->wnd);
3507            }
3508    
3509            sw_restack_window(sw, behind);
3510    }
3511    
3512    
3513    void
3514    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3515    {
3516            seamless_window *sw;
3517    
3518            if (!g_seamless_active)
3519                    return;
3520    
3521            sw = sw_get_window_by_id(id);
3522            if (!sw)
3523            {
3524                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3525                    return;
3526            }
3527    
3528            /* FIXME: Might want to convert the name for non-EWMH WMs */
3529            XStoreName(g_display, sw->wnd, title);
3530            ewmh_set_wm_name(sw->wnd, title);
3531    }
3532    
3533    
3534    void
3535    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3536    {
3537            seamless_window *sw;
3538    
3539            if (!g_seamless_active)
3540                    return;
3541    
3542            sw = sw_get_window_by_id(id);
3543            if (!sw)
3544            {
3545                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3546                    return;
3547            }
3548    
3549            switch (state)
3550            {
3551                    case SEAMLESSRDP_NORMAL:
3552                    case SEAMLESSRDP_MAXIMIZED:
3553                            ewmh_change_state(sw->wnd, state);
3554                            XMapWindow(g_display, sw->wnd);
3555                            break;
3556                    case SEAMLESSRDP_MINIMIZED:
3557                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3558                               the Window Manager should probably just ignore the request, since
3559                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3560                               such as minimization, rather than an independent state." Besides,
3561                               XIconifyWindow is easier. */
3562                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3563                            {
3564                                    XWMHints *hints;
3565                                    hints = XGetWMHints(g_display, sw->wnd);
3566                                    if (hints)
3567                                    {
3568                                            hints->flags |= StateHint;
3569                                            hints->initial_state = IconicState;
3570                                            XSetWMHints(g_display, sw->wnd, hints);
3571                                            XFree(hints);
3572                                    }
3573                                    XMapWindow(g_display, sw->wnd);
3574                            }
3575                            else
3576                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3577                            break;
3578                    default:
3579                            warning("SeamlessRDP: Invalid state %d\n", state);
3580                            break;
3581            }
3582    
3583            sw->state = state;
3584    }
3585    
3586    
3587    void
3588    ui_seamless_syncbegin(unsigned long flags)
3589    {
3590            if (!g_seamless_active)
3591                    return;
3592    
3593            /* Destroy all seamless windows */
3594            while (g_seamless_windows)
3595            {
3596                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3597                    sw_remove_window(g_seamless_windows);
3598            }
3599    }
3600    
3601    
3602    void
3603    ui_seamless_ack(unsigned int serial)
3604    {
3605            seamless_window *sw;
3606            for (sw = g_seamless_windows; sw; sw = sw->next)
3607            {
3608                    if (sw->outpos_serial == serial)
3609                    {
3610                            sw->xoffset = sw->outpos_xoffset;
3611                            sw->yoffset = sw->outpos_yoffset;
3612                            sw->width = sw->outpos_width;
3613                            sw->height = sw->outpos_height;
3614                            sw->outstanding_position = False;
3615    
3616                            /* Do a complete redraw of the window as part of the
3617                               completion of the move. This is to remove any
3618                               artifacts caused by our lack of synchronization. */
3619                            XCopyArea(g_display, g_backstore,
3620                                      sw->wnd, g_gc,
3621                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3622    
3623                            break;
3624                    }
3625            }
3626    }

Legend:
Removed from v.1040  
changed lines
  Added in v.1181

  ViewVC Help
Powered by ViewVC 1.1.26