/[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 1022 by jsorg71, Thu Sep 29 03:34:33 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1193 by ossman_, Wed Mar 22 16:20:55 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    static BOOL g_seamless_hidden = False;  /* Desktop is hidden on server */
86    extern BOOL g_seamless_rdp;
87    
88  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
89  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
90  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
91  static GC g_gc = NULL;  static GC g_gc = NULL;
92  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
93  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
94    static XRectangle g_clip_rectangle;
95  static Visual *g_visual;  static Visual *g_visual;
96    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
97       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
98       as far as we're concerned. */
99  static int g_depth;  static int g_depth;
100    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
101       This may be larger than g_depth, in which case some of the bits would
102       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
103  static int g_bpp;  static int g_bpp;
104  static XIM g_IM;  static XIM g_IM;
105  static XIC g_IC;  static XIC g_IC;
# Line 61  static XModifierKeymap *g_mod_map; Line 107  static XModifierKeymap *g_mod_map;
107  static Cursor g_current_cursor;  static Cursor g_current_cursor;
108  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
109  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
110    extern Atom g_net_wm_state_atom;
111    extern Atom g_net_wm_desktop_atom;
112  static BOOL g_focused;  static BOOL g_focused;
113  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
114  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
115       1) visual has 15, 16 or 24 depth and the same color channel masks
116          as its RDP equivalent (implies X server is LE),
117       2) host is LE
118       This will trigger an optimization whose real value is questionable.
119    */
120    static BOOL g_compatible_arch;
121    /* Indicates whether RDP's bitmaps and our XImages have the same
122       binary format. If so, we can avoid an expensive translation.
123       Note that this can be true when g_compatible_arch is false,
124       e.g.:
125      
126         RDP(LE) <-> host(BE) <-> X-Server(LE)
127        
128       ('host' is the machine running rdesktop; the host simply memcpy's
129        so its endianess doesn't matter)
130     */
131    static BOOL g_no_translate_image = False;
132    
133  /* endianness */  /* endianness */
134  static BOOL g_host_be;  static BOOL g_host_be;
# Line 92  extern BOOL g_rdpsnd; Line 157  extern BOOL g_rdpsnd;
157  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
158  typedef struct  typedef struct
159  {  {
160          uint32 flags;          unsigned long flags;
161          uint32 functions;          unsigned long functions;
162          uint32 decorations;          unsigned long decorations;
163          sint32 inputMode;          long inputMode;
164          uint32 status;          unsigned long status;
165  }  }
166  PropMotifWmHints;  PropMotifWmHints;
167    
# Line 108  typedef struct Line 173  typedef struct
173  }  }
174  PixelColour;  PixelColour;
175    
176    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
177            do { \
178                    seamless_window *sw; \
179                    XRectangle rect; \
180                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
181                        rect.x = g_clip_rectangle.x - sw->xoffset; \
182                        rect.y = g_clip_rectangle.y - sw->yoffset; \
183                        rect.width = g_clip_rectangle.width; \
184                        rect.height = g_clip_rectangle.height; \
185                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
186                        func args; \
187                    } \
188                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
189            } while (0)
190    
191    static void
192    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
193    {
194            points[0].x -= xoffset;
195            points[0].y -= yoffset;
196            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
197            points[0].x += xoffset;
198            points[0].y += yoffset;
199    }
200    
201    static void
202    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
203    {
204            points[0].x -= xoffset;
205            points[0].y -= yoffset;
206            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
207            points[0].x += xoffset;
208            points[0].y += yoffset;
209    }
210    
211  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
212  { \  { \
213          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
214            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
215          if (g_ownbackstore) \          if (g_ownbackstore) \
216                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
217  }  }
# Line 126  PixelColour; Line 226  PixelColour;
226          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
227          if (g_ownbackstore) \          if (g_ownbackstore) \
228                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
229            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
230  }  }
231    
232  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 134  PixelColour; Line 235  PixelColour;
235          { \          { \
236                  case 0: /* Outline */ \                  case 0: /* Outline */ \
237                          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); \
238                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
239                          if (g_ownbackstore) \                          if (g_ownbackstore) \
240                                  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); \
241                          break; \                          break; \
242                  case 1: /* Filled */ \                  case 1: /* Filled */ \
243                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
244                                     cx, cy, 0, 360*64); \
245                            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)); \
246                          if (g_ownbackstore) \                          if (g_ownbackstore) \
247                                  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); \
248                          break; \                          break; \
# Line 150  extern BOOL g_owncolmap; Line 254  extern BOOL g_owncolmap;
254  static Colormap g_xcolmap;  static Colormap g_xcolmap;
255  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
256    
257  #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] )
258  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
259  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
260    
# Line 176  static int rop2_map[] = { Line 280  static int rop2_map[] = {
280  #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]); }
281  #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); }
282    
283    static seamless_window *
284    sw_get_window_by_id(unsigned long id)
285    {
286            seamless_window *sw;
287            for (sw = g_seamless_windows; sw; sw = sw->next)
288            {
289                    if (sw->id == id)
290                            return sw;
291            }
292            return NULL;
293    }
294    
295    
296    static seamless_window *
297    sw_get_window_by_wnd(Window wnd)
298    {
299            seamless_window *sw;
300            for (sw = g_seamless_windows; sw; sw = sw->next)
301            {
302                    if (sw->wnd == wnd)
303                            return sw;
304            }
305            return NULL;
306    }
307    
308    
309  static void  static void
310  mwm_hide_decorations(void)  sw_remove_window(seamless_window * win)
311    {
312            seamless_window *sw, **prevnext = &g_seamless_windows;
313            for (sw = g_seamless_windows; sw; sw = sw->next)
314            {
315                    if (sw == win)
316                    {
317                            *prevnext = sw->next;
318                            sw->group->refcnt--;
319                            if (sw->group->refcnt == 0)
320                            {
321                                    XDestroyWindow(g_display, sw->group->wnd);
322                                    xfree(sw->group);
323                            }
324                            xfree(sw->position_timer);
325                            xfree(sw);
326                            return;
327                    }
328                    prevnext = &sw->next;
329            }
330            return;
331    }
332    
333    
334    /* Move all windows except wnd to new desktop */
335    static void
336    sw_all_to_desktop(Window wnd, unsigned int desktop)
337    {
338            seamless_window *sw;
339            for (sw = g_seamless_windows; sw; sw = sw->next)
340            {
341                    if (sw->wnd == wnd)
342                            continue;
343                    if (sw->desktop != desktop)
344                    {
345                            ewmh_move_to_desktop(sw->wnd, desktop);
346                            sw->desktop = desktop;
347                    }
348            }
349    }
350    
351    
352    /* Send our position */
353    static void
354    sw_update_position(seamless_window * sw)
355    {
356            XWindowAttributes wa;
357            int x, y;
358            Window child_return;
359            unsigned int serial;
360    
361            XGetWindowAttributes(g_display, sw->wnd, &wa);
362            XTranslateCoordinates(g_display, sw->wnd, wa.root,
363                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
364    
365            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
366    
367            sw->outstanding_position = True;
368            sw->outpos_serial = serial;
369    
370            sw->outpos_xoffset = x;
371            sw->outpos_yoffset = y;
372            sw->outpos_width = wa.width;
373            sw->outpos_height = wa.height;
374    }
375    
376    
377    /* Check if it's time to send our position */
378    static void
379    sw_check_timers()
380    {
381            seamless_window *sw;
382            struct timeval now;
383    
384            gettimeofday(&now, NULL);
385            for (sw = g_seamless_windows; sw; sw = sw->next)
386            {
387                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
388                    {
389                            timerclear(sw->position_timer);
390                            sw_update_position(sw);
391                    }
392            }
393    }
394    
395    
396    static void
397    sw_restack_window(seamless_window * sw, unsigned long behind)
398    {
399            seamless_window *sw_above;
400    
401            /* Remove window from stack */
402            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
403            {
404                    if (sw_above->behind == sw->id)
405                            break;
406            }
407    
408            if (sw_above)
409                    sw_above->behind = sw->behind;
410    
411            /* And then add it at the new position */
412    
413            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
414            {
415                    if (sw_above->behind == behind)
416                            break;
417            }
418    
419            if (sw_above)
420                    sw_above->behind = sw->id;
421    
422            sw->behind = behind;
423    }
424    
425    
426    static void
427    sw_handle_restack(seamless_window * sw)
428    {
429            Status status;
430            Window root, parent, *children;
431            unsigned int nchildren, i;
432            seamless_window *sw_below;
433    
434            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
435                                &root, &parent, &children, &nchildren);
436            if (!status || !nchildren)
437                    return;
438    
439            sw_below = NULL;
440    
441            i = 0;
442            while (children[i] != sw->wnd)
443            {
444                    i++;
445                    if (i >= nchildren)
446                            goto end;
447            }
448    
449            for (i++; i < nchildren; i++)
450            {
451                    sw_below = sw_get_window_by_wnd(children[i]);
452                    if (sw_below)
453                            break;
454            }
455    
456            if (!sw_below && !sw->behind)
457                    goto end;
458            if (sw_below && (sw_below->id == sw->behind))
459                    goto end;
460    
461            if (sw_below)
462            {
463                    seamless_send_zchange(sw->id, sw_below->id, 0);
464                    sw_restack_window(sw, sw_below->id);
465            }
466            else
467            {
468                    seamless_send_zchange(sw->id, 0, 0);
469                    sw_restack_window(sw, 0);
470            }
471    
472          end:
473            XFree(children);
474    }
475    
476    
477    static seamless_group *
478    sw_find_group(unsigned long id, BOOL dont_create)
479    {
480            seamless_window *sw;
481            seamless_group *sg;
482            XSetWindowAttributes attribs;
483    
484            for (sw = g_seamless_windows; sw; sw = sw->next)
485            {
486                    if (sw->group->id == id)
487                            return sw->group;
488            }
489    
490            if (dont_create)
491                    return NULL;
492    
493            sg = xmalloc(sizeof(seamless_group));
494    
495            sg->wnd =
496                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
497                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
498    
499            sg->id = id;
500            sg->refcnt = 0;
501    
502            return sg;
503    }
504    
505    
506    static void
507    mwm_hide_decorations(Window wnd)
508  {  {
509          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
510          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 521  mwm_hide_decorations(void)
521                  return;                  return;
522          }          }
523    
524          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
525                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
526    
527  }  }
528    
529  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 557  mwm_hide_decorations(void)
557  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
558                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
559    
560    /* The following macros output the same octet sequences
561       on both BE and LE hosts: */
562    
563  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
564  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
565  #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 571  static uint32
571  translate_colour(uint32 colour)  translate_colour(uint32 colour)
572  {  {
573          PixelColour pc;          PixelColour pc;
574          switch (g_server_bpp)          switch (g_server_depth)
575          {          {
576                  case 15:                  case 15:
577                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 251  translate_colour(uint32 colour) Line 582  translate_colour(uint32 colour)
582                  case 24:                  case 24:
583                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
584                          break;                          break;
585                    default:
586                            /* Avoid warning */
587                            pc.red = 0;
588                            pc.green = 0;
589                            pc.blue = 0;
590                            break;
591          }          }
592          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
593  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 639  translate8to16(const uint8 * data, uint8
639  {  {
640          uint16 value;          uint16 value;
641    
642          if (g_arch_match)          if (g_compatible_arch)
643          {          {
644                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
645                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 673  translate8to24(const uint8 * data, uint8
673  {  {
674          uint32 value;          uint32 value;
675    
676          if (g_xserver_be)          if (g_compatible_arch)
677          {          {
678                  while (out < end)                  while (out < end)
679                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 696  translate8to32(const uint8 * data, uint8
696  {  {
697          uint32 value;          uint32 value;
698    
699          if (g_arch_match)          if (g_compatible_arch)
700          {          {
701                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
702                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 768  translate15to24(const uint16 * data, uin
768          uint16 pixel;          uint16 pixel;
769          PixelColour pc;          PixelColour pc;
770    
771          if (g_arch_match)          if (g_compatible_arch)
772          {          {
773                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
774                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 818  translate15to32(const uint16 * data, uin
818          uint32 value;          uint32 value;
819          PixelColour pc;          PixelColour pc;
820    
821          if (g_arch_match)          if (g_compatible_arch)
822          {          {
823                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
824                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 926  translate16to24(const uint16 * data, uin
926          uint16 pixel;          uint16 pixel;
927          PixelColour pc;          PixelColour pc;
928    
929          if (g_arch_match)          if (g_compatible_arch)
930          {          {
931                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
932                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 996  translate16to32(const uint16 * data, uin
996          uint32 value;          uint32 value;
997          PixelColour pc;          PixelColour pc;
998    
999          if (g_arch_match)          if (g_compatible_arch)
1000          {          {
1001                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1002                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 1125  translate24to32(const uint8 * data, uint
1125          uint32 value;          uint32 value;
1126          PixelColour pc;          PixelColour pc;
1127    
1128          if (g_arch_match)          if (g_compatible_arch)
1129          {          {
1130                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1131  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 1139  translate24to32(const uint8 * data, uint
1139  #else  #else
1140                  REPEAT4                  REPEAT4
1141                  (                  (
1142                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1143                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1144                          data += 3;                   out += 4;
1145                     data += 3;
1146                  )                  )
1147  #endif  #endif
1148                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 842  translate_image(int width, int height, u Line 1180  translate_image(int width, int height, u
1180          uint8 *out;          uint8 *out;
1181          uint8 *end;          uint8 *end;
1182    
1183          /* if server and xserver bpp match, */          /*
1184          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1185          /* just return data */             and arch(endian) matches, no need to translate:
1186          if (g_arch_match)             just return data.
1187               Note: select_visual should've already ensured g_no_translate
1188               is only set for compatible depths, but the RDP depth might've
1189               changed during connection negotiations.
1190             */
1191            if (g_no_translate_image)
1192          {          {
1193                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1194                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1195                  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)  
1196                          return data;                          return data;
1197          }          }
1198    
# Line 859  translate_image(int width, int height, u Line 1200  translate_image(int width, int height, u
1200          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1201          end = out + size;          end = out + size;
1202    
1203          switch (g_server_bpp)          switch (g_server_depth)
1204          {          {
1205                  case 24:                  case 24:
1206                          switch (g_bpp)                          switch (g_bpp)
# Line 957  calculate_shifts(uint32 mask, int *shift Line 1298  calculate_shifts(uint32 mask, int *shift
1298          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1299  }  }
1300    
1301  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1302  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1303     */
1304    static unsigned
1305    calculate_mask_weight(uint32 mask)
1306    {
1307            unsigned weight = 0;
1308            do
1309            {
1310                    weight += (mask & 1);
1311            }
1312            while (mask >>= 1);
1313            return weight;
1314    }
1315    
1316    static BOOL
1317    select_visual()
1318  {  {
         XVisualInfo vi;  
1319          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1320          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1321          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1322          XVisualInfo template;          XVisualInfo template;
1323          Bool TrueColorVisual = False;          int i;
1324            unsigned red_weight, blue_weight, green_weight;
1325    
1326          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1327          if (g_display == NULL)  
1328            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1329            if (pfm == NULL)
1330          {          {
1331                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1332                    XCloseDisplay(g_display);
1333                  return False;                  return False;
1334          }          }
1335    
1336          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 */  
1337          template.class = TrueColor;          template.class = TrueColor;
1338          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1339            g_visual = NULL;
1340            g_no_translate_image = False;
1341            g_compatible_arch = False;
1342            if (vmatches != NULL)
1343            {
1344                    for (i = 0; i < visuals_count; ++i)
1345                    {
1346                            XVisualInfo *visual_info = &vmatches[i];
1347    
1348                            /* Try to find a no-translation visual that'll
1349                               allow us to use RDP bitmaps directly as ZPixmaps. */
1350                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1351                                                   /* R5G5B5 */
1352                                                   (visual_info->red_mask == 0x7c00) &&
1353                                                   (visual_info->green_mask == 0x3e0) &&
1354                                                   (visual_info->blue_mask == 0x1f)) ||
1355                                                  ((visual_info->depth == 16) &&
1356                                                   /* R5G6B5 */
1357                                                   (visual_info->red_mask == 0xf800) &&
1358                                                   (visual_info->green_mask == 0x7e0) &&
1359                                                   (visual_info->blue_mask == 0x1f)) ||
1360                                                  ((visual_info->depth == 24) &&
1361                                                   /* R8G8B8 */
1362                                                   (visual_info->red_mask == 0xff0000) &&
1363                                                   (visual_info->green_mask == 0xff00) &&
1364                                                   (visual_info->blue_mask == 0xff))))
1365                            {
1366                                    g_visual = visual_info->visual;
1367                                    g_depth = visual_info->depth;
1368                                    g_compatible_arch = !g_host_be;
1369                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1370                                    if (g_no_translate_image)
1371                                            /* We found the best visual */
1372                                            break;
1373                            }
1374                            else
1375                            {
1376                                    g_compatible_arch = False;
1377                            }
1378    
1379          nvisuals--;                          if (visual_info->depth > 24)
1380          while (nvisuals >= 0)                          {
1381          {                                  /* Avoid 32-bit visuals and likes like the plague.
1382                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1383                  {                                     (e.g. nvidia's Composite 32-bit visual).
1384                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1385                                    continue;
1386                            }
1387    
1388                            /* Only care for visuals, for whose BPPs (not depths!)
1389                               we have a translateXtoY function. */
1390                            BOOL can_translate_to_bpp = False;
1391                            int j;
1392                            for (j = 0; j < pixmap_formats_count; ++j)
1393                            {
1394                                    if (pfm[j].depth == visual_info->depth)
1395                                    {
1396                                            if ((pfm[j].bits_per_pixel == 16) ||
1397                                                (pfm[j].bits_per_pixel == 24) ||
1398                                                (pfm[j].bits_per_pixel == 32))
1399                                            {
1400                                                    can_translate_to_bpp = True;
1401                                            }
1402                                            break;
1403                                    }
1404                            }
1405    
1406                            /* Prefer formats which have the most colour depth.
1407                               We're being truly aristocratic here, minding each
1408                               weight on its own. */
1409                            if (can_translate_to_bpp)
1410                            {
1411                                    unsigned vis_red_weight =
1412                                            calculate_mask_weight(visual_info->red_mask);
1413                                    unsigned vis_green_weight =
1414                                            calculate_mask_weight(visual_info->green_mask);
1415                                    unsigned vis_blue_weight =
1416                                            calculate_mask_weight(visual_info->blue_mask);
1417                                    if ((vis_red_weight >= red_weight)
1418                                        && (vis_green_weight >= green_weight)
1419                                        && (vis_blue_weight >= blue_weight))
1420                                    {
1421                                            red_weight = vis_red_weight;
1422                                            green_weight = vis_green_weight;
1423                                            blue_weight = vis_blue_weight;
1424                                            g_visual = visual_info->visual;
1425                                            g_depth = visual_info->depth;
1426                                    }
1427                            }
1428                  }                  }
1429                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1430          }          }
1431    
1432          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)))  
1433          {          {
1434                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1435                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1436                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1437                    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;  
                 }  
1438          }          }
1439          else          else
1440          {          {
1441                  /* need a truecolour visual */                  template.class = PseudoColor;
1442                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1443                  {                  template.colormap_size = 256;
1444                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1445                            XGetVisualInfo(g_display,
1446                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1447                                           &template, &visuals_count);
1448                    if (vmatches == NULL)
1449                    {
1450                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1451                            XCloseDisplay(g_display);
1452                            XFree(pfm);
1453                          return False;                          return False;
1454                  }                  }
1455    
1456                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1457                  g_owncolmap = False;                  g_owncolmap = True;
1458                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1459                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1460                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1461    
1462                  /* if RGB video and everything is little endian */          g_bpp = 0;
1463                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1464                      !g_xserver_be && !g_host_be)          {
1465                    XPixmapFormatValues *pf = &pfm[i];
1466                    if (pf->depth == g_depth)
1467                  {                  {
1468                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1469                                                g_blue_shift_l == 0))  
1470                            if (g_no_translate_image)
1471                          {                          {
1472                                  g_arch_match = True;                                  switch (g_server_depth)
1473                                    {
1474                                            case 15:
1475                                            case 16:
1476                                                    if (g_bpp != 16)
1477                                                            g_no_translate_image = False;
1478                                                    break;
1479                                            case 24:
1480                                                    /* Yes, this will force image translation
1481                                                       on most modern servers which use 32 bits
1482                                                       for R8G8B8. */
1483                                                    if (g_bpp != 24)
1484                                                            g_no_translate_image = False;
1485                                                    break;
1486                                            default:
1487                                                    g_no_translate_image = False;
1488                                                    break;
1489                                    }
1490                          }                          }
                 }  
1491    
1492                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1493                  {                             there's just a single entry for every depth,
1494                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1495                            break;
1496                  }                  }
1497          }          }
1498            XFree(pfm);
1499            pfm = NULL;
1500            return True;
1501    }
1502    
1503    static XErrorHandler g_old_error_handler;
1504    
1505          pfm = XListPixmapFormats(g_display, &i);  static int
1506          if (pfm != NULL)  error_handler(Display * dpy, XErrorEvent * eev)
1507    {
1508            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1509          {          {
1510                  /* Use maximum bpp for this depth - this is generally                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1511                     desirable, e.g. 24 bits->32 bits. */                  fprintf(stderr,
1512                  while (i--)                          "This is most likely caused by a broken window manager (commonly KWin).\n");
1513                  {                  return 0;
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1514          }          }
1515    
1516          if (g_bpp < 8)          return g_old_error_handler(dpy, eev);
1517    }
1518    
1519    BOOL
1520    ui_init(void)
1521    {
1522            int screen_num;
1523    
1524            g_display = XOpenDisplay(NULL);
1525            if (g_display == NULL)
1526          {          {
1527                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(g_display);  
1528                  return False;                  return False;
1529          }          }
1530    
1531            {
1532                    uint16 endianess_test = 1;
1533                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1534            }
1535    
1536            g_old_error_handler = XSetErrorHandler(error_handler);
1537    
1538            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1539            screen_num = DefaultScreen(g_display);
1540            g_x_socket = ConnectionNumber(g_display);
1541            g_screen = ScreenOfDisplay(g_display, screen_num);
1542            g_depth = DefaultDepthOfScreen(g_screen);
1543    
1544            if (!select_visual())
1545                    return False;
1546    
1547            if (g_no_translate_image)
1548            {
1549                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1550            }
1551    
1552            if (g_server_depth > g_bpp)
1553            {
1554                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1555                            g_server_depth, g_bpp);
1556            }
1557    
1558            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1559                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1560    
1561          if (!g_owncolmap)          if (!g_owncolmap)
1562          {          {
1563                  g_xcolmap =                  g_xcolmap =
1564                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1565                                          AllocNone);                                          AllocNone);
1566                  if (g_depth <= 8)                  if (g_depth <= 8)
1567                          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);
1568          }          }
1569    
1570          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1571          {          {
1572                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1573                  g_ownbackstore = True;                  g_ownbackstore = True;
1574          }          }
1575    
# Line 1087  ui_init(void) Line 1580  ui_init(void)
1580          {          {
1581                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1582                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1583                    g_using_full_workarea = True;
1584          }          }
1585          else if (g_width < 0)          else if (g_width < 0)
1586          {          {
# Line 1100  ui_init(void) Line 1594  ui_init(void)
1594          {          {
1595                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1596                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
                 g_using_full_workarea = True;  
   
1597                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1598                  {                  {
1599                          g_width = cx;                          g_width = cx;
1600                          g_height = cy;                          g_height = cy;
1601                            g_using_full_workarea = True;
1602                  }                  }
1603                  else                  else
1604                  {                  {
1605                          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");
1606                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1607                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1608                  }                  }
1609          }          }
1610    
# Line 1126  ui_init(void) Line 1619  ui_init(void)
1619                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1620    
1621          xclip_init();          xclip_init();
1622            ewmh_init();
1623            if (g_seamless_rdp)
1624                    seamless_init();
1625    
1626          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));
1627    
1628          return True;          return True;
1629  }  }
# Line 1135  ui_init(void) Line 1631  ui_init(void)
1631  void  void
1632  ui_deinit(void)  ui_deinit(void)
1633  {  {
1634            while (g_seamless_windows)
1635            {
1636                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1637                    sw_remove_window(g_seamless_windows);
1638            }
1639    
1640          if (g_IM != NULL)          if (g_IM != NULL)
1641                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1642    
# Line 1151  ui_deinit(void) Line 1653  ui_deinit(void)
1653          g_display = NULL;          g_display = NULL;
1654  }  }
1655    
1656    
1657    static void
1658    get_window_attribs(XSetWindowAttributes * attribs)
1659    {
1660            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1661            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1662            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1663            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1664            attribs->override_redirect = g_fullscreen;
1665            attribs->colormap = g_xcolmap;
1666    }
1667    
1668    static void
1669    get_input_mask(long *input_mask)
1670    {
1671            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1672                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1673    
1674            if (g_sendmotion)
1675                    *input_mask |= PointerMotionMask;
1676            if (g_ownbackstore)
1677                    *input_mask |= ExposureMask;
1678            if (g_fullscreen || g_grab_keyboard)
1679                    *input_mask |= EnterWindowMask;
1680            if (g_grab_keyboard)
1681                    *input_mask |= LeaveWindowMask;
1682    }
1683    
1684  BOOL  BOOL
1685  ui_create_window(void)  ui_create_window(void)
1686  {  {
# Line 1173  ui_create_window(void) Line 1703  ui_create_window(void)
1703          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1704                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1705    
1706          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;  
1707    
1708          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,
1709                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1185  ui_create_window(void) Line 1711  ui_create_window(void)
1711                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1712    
1713          if (g_gc == NULL)          if (g_gc == NULL)
1714            {
1715                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1716                    ui_reset_clip();
1717            }
1718    
1719          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1720                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1202  ui_create_window(void) Line 1731  ui_create_window(void)
1731          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1732    
1733          if (g_hide_decorations)          if (g_hide_decorations)
1734                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1735    
1736          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1737          if (classhints != NULL)          if (classhints != NULL)
# Line 1229  ui_create_window(void) Line 1758  ui_create_window(void)
1758                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1759          }          }
1760    
1761          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;  
1762    
1763          if (g_IM != NULL)          if (g_IM != NULL)
1764          {          {
# Line 1252  ui_create_window(void) Line 1771  ui_create_window(void)
1771          }          }
1772    
1773          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1774    
1775            XMapWindow(g_display, g_wnd);
1776          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1777          do          do
1778          {          {
# Line 1324  xwin_toggle_fullscreen(void) Line 1843  xwin_toggle_fullscreen(void)
1843  {  {
1844          Pixmap contents = 0;          Pixmap contents = 0;
1845    
1846            if (g_seamless_active)
1847                    /* Turn off SeamlessRDP mode */
1848                    ui_seamless_toggle();
1849    
1850          if (!g_ownbackstore)          if (!g_ownbackstore)
1851          {          {
1852                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1412  handle_button_event(XEvent xevent, BOOL Line 1935  handle_button_event(XEvent xevent, BOOL
1935                  }                  }
1936          }          }
1937    
1938          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
1939                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
1940                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1941                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1942            }
1943            else
1944            {
1945                    /* SeamlessRDP */
1946                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1947                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1948            }
1949  }  }
1950    
1951    
1952  /* Process events in Xlib queue  /* Process events in Xlib queue
1953     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1954  static int  static int
# Line 1427  xwin_process_events(void) Line 1960  xwin_process_events(void)
1960          char str[256];          char str[256];
1961          Status status;          Status status;
1962          int events = 0;          int events = 0;
1963            seamless_window *sw;
1964    
1965          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1966          {          {
# Line 1441  xwin_process_events(void) Line 1975  xwin_process_events(void)
1975                  switch (xevent.type)                  switch (xevent.type)
1976                  {                  {
1977                          case VisibilityNotify:                          case VisibilityNotify:
1978                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1979                                            g_Unobscured =
1980                                                    xevent.xvisibility.state == VisibilityUnobscured;
1981    
1982                                  break;                                  break;
1983                          case ClientMessage:                          case ClientMessage:
1984                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1521  xwin_process_events(void) Line 2058  xwin_process_events(void)
2058                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2059                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2060                                                         CurrentTime);                                                         CurrentTime);
2061                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2062                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2063                                    {
2064                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2065                                                           xevent.xmotion.x, xevent.xmotion.y);
2066                                    }
2067                                    else
2068                                    {
2069                                            /* SeamlessRDP */
2070                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2071                                                           xevent.xmotion.x_root,
2072                                                           xevent.xmotion.y_root);
2073                                    }
2074                                  break;                                  break;
2075    
2076                          case FocusIn:                          case FocusIn:
# Line 1533  xwin_process_events(void) Line 2081  xwin_process_events(void)
2081                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2082                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2083                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2084    
2085                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2086                                    if (!sw)
2087                                            break;
2088    
2089                                    if (sw->id != g_seamless_focused)
2090                                    {
2091                                            seamless_send_focus(sw->id, 0);
2092                                            g_seamless_focused = sw->id;
2093                                    }
2094                                  break;                                  break;
2095    
2096                          case FocusOut:                          case FocusOut:
# Line 1565  xwin_process_events(void) Line 2123  xwin_process_events(void)
2123                                  break;                                  break;
2124    
2125                          case Expose:                          case Expose:
2126                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2127                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2128                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2129                                            xevent.xexpose.height,                                                    g_gc,
2130                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2131                                                      xevent.xexpose.width, xevent.xexpose.height,
2132                                                      xevent.xexpose.x, xevent.xexpose.y);
2133                                    }
2134                                    else
2135                                    {
2136                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2137                                            if (!sw)
2138                                                    break;
2139                                            XCopyArea(g_display, g_backstore,
2140                                                      xevent.xexpose.window, g_gc,
2141                                                      xevent.xexpose.x + sw->xoffset,
2142                                                      xevent.xexpose.y + sw->yoffset,
2143                                                      xevent.xexpose.width,
2144                                                      xevent.xexpose.height, xevent.xexpose.x,
2145                                                      xevent.xexpose.y);
2146                                    }
2147    
2148                                  break;                                  break;
2149    
2150                          case MappingNotify:                          case MappingNotify:
# Line 1598  xwin_process_events(void) Line 2173  xwin_process_events(void)
2173                                  break;                                  break;
2174                          case PropertyNotify:                          case PropertyNotify:
2175                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2176                                    if (xevent.xproperty.window == g_wnd)
2177                                            break;
2178                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2179                                            break;
2180    
2181                                    /* seamless */
2182                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2183                                    if (!sw)
2184                                            break;
2185    
2186                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2187                                        && (xevent.xproperty.state == PropertyNewValue))
2188                                    {
2189                                            sw->state = ewmh_get_window_state(sw->wnd);
2190                                            seamless_send_state(sw->id, sw->state, 0);
2191                                    }
2192    
2193                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2194                                        && (xevent.xproperty.state == PropertyNewValue))
2195                                    {
2196                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2197                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2198                                    }
2199    
2200                                  break;                                  break;
2201                          case MapNotify:                          case MapNotify:
2202                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2203                                            rdp_send_client_window_status(1);
2204                                  break;                                  break;
2205                          case UnmapNotify:                          case UnmapNotify:
2206                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2207                                            rdp_send_client_window_status(0);
2208                                    break;
2209                            case ConfigureNotify:
2210                                    if (!g_seamless_active)
2211                                            break;
2212    
2213                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2214                                    if (!sw)
2215                                            break;
2216    
2217                                    gettimeofday(sw->position_timer, NULL);
2218                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2219                                        1000000)
2220                                    {
2221                                            sw->position_timer->tv_usec +=
2222                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2223                                            sw->position_timer->tv_sec += 1;
2224                                    }
2225                                    else
2226                                    {
2227                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2228                                    }
2229    
2230                                    sw_handle_restack(sw);
2231                                  break;                                  break;
2232                  }                  }
2233          }          }
# Line 1628  ui_select(int rdp_socket) Line 2252  ui_select(int rdp_socket)
2252                          /* User quit */                          /* User quit */
2253                          return 0;                          return 0;
2254    
2255                    if (g_seamless_active)
2256                            sw_check_timers();
2257    
2258                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2259                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2260                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1647  ui_select(int rdp_socket) Line 2274  ui_select(int rdp_socket)
2274    
2275                  /* add redirection handles */                  /* add redirection handles */
2276                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2277                    seamless_select_timeout(&tv);
2278    
2279                  n++;                  n++;
2280    
# Line 1688  ui_create_bitmap(int width, int height, Line 2316  ui_create_bitmap(int width, int height,
2316          uint8 *tdata;          uint8 *tdata;
2317          int bitmap_pad;          int bitmap_pad;
2318    
2319          if (g_server_bpp == 8)          if (g_server_depth == 8)
2320          {          {
2321                  bitmap_pad = 8;                  bitmap_pad = 8;
2322          }          }
# Line 1720  ui_paint_bitmap(int x, int y, int cx, in Line 2348  ui_paint_bitmap(int x, int y, int cx, in
2348          uint8 *tdata;          uint8 *tdata;
2349          int bitmap_pad;          int bitmap_pad;
2350    
2351          if (g_server_bpp == 8)          if (g_server_depth == 8)
2352          {          {
2353                  bitmap_pad = 8;                  bitmap_pad = 8;
2354          }          }
# Line 1740  ui_paint_bitmap(int x, int y, int cx, in Line 2368  ui_paint_bitmap(int x, int y, int cx, in
2368          {          {
2369                  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);
2370                  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);
2371                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2372                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2373                                             x - sw->xoffset, y - sw->yoffset));
2374          }          }
2375          else          else
2376          {          {
2377                  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);
2378                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2379                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2380                                             x - sw->xoffset, y - sw->yoffset));
2381          }          }
2382    
2383          XFree(image);          XFree(image);
# Line 1864  ui_set_cursor(HCURSOR cursor) Line 2498  ui_set_cursor(HCURSOR cursor)
2498  {  {
2499          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2500          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2501            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2502  }  }
2503    
2504  void  void
# Line 2005  ui_set_colourmap(HCOLOURMAP map) Line 2640  ui_set_colourmap(HCOLOURMAP map)
2640                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2641          }          }
2642          else          else
2643            {
2644                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2645                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2646            }
2647  }  }
2648    
2649  void  void
2650  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2651  {  {
2652          XRectangle rect;          g_clip_rectangle.x = x;
2653            g_clip_rectangle.y = y;
2654          rect.x = x;          g_clip_rectangle.width = cx;
2655          rect.y = y;          g_clip_rectangle.height = cy;
2656          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);  
2657  }  }
2658    
2659  void  void
2660  ui_reset_clip(void)  ui_reset_clip(void)
2661  {  {
2662          XRectangle rect;          g_clip_rectangle.x = 0;
2663            g_clip_rectangle.y = 0;
2664          rect.x = 0;          g_clip_rectangle.width = g_width;
2665          rect.y = 0;          g_clip_rectangle.height = g_height;
2666          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);  
2667  }  }
2668    
2669  void  void
# Line 2110  ui_patblt(uint8 opcode, Line 2744  ui_patblt(uint8 opcode,
2744    
2745          if (g_ownbackstore)          if (g_ownbackstore)
2746                  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);
2747            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2748                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2749                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2750  }  }
2751    
2752  void  void
# Line 2120  ui_screenblt(uint8 opcode, Line 2757  ui_screenblt(uint8 opcode,
2757          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2758          if (g_ownbackstore)          if (g_ownbackstore)
2759          {          {
2760                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2761                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2762                          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);  
                 }  
2763          }          }
2764          else          else
2765          {          {
2766                  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);
2767          }          }
2768    
2769            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2770                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2771                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2772    
2773          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2774  }  }
2775    
# Line 2147  ui_memblt(uint8 opcode, Line 2780  ui_memblt(uint8 opcode,
2780  {  {
2781          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2782          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);
2783            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2784                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2785                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2786          if (g_ownbackstore)          if (g_ownbackstore)
2787                  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);
2788          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2193  ui_line(uint8 opcode, Line 2829  ui_line(uint8 opcode,
2829          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2830          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2831          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2832            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2833                                                startx - sw->xoffset, starty - sw->yoffset,
2834                                                endx - sw->xoffset, endy - sw->yoffset));
2835          if (g_ownbackstore)          if (g_ownbackstore)
2836                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2837          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2290  ui_polyline(uint8 opcode, Line 2929  ui_polyline(uint8 opcode,
2929          if (g_ownbackstore)          if (g_ownbackstore)
2930                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2931                             CoordModePrevious);                             CoordModePrevious);
2932    
2933            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2934                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2935    
2936          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2937  }  }
2938    
# Line 2445  ui_draw_text(uint8 font, uint8 flags, ui Line 3088  ui_draw_text(uint8 font, uint8 flags, ui
3088                  switch (text[i])                  switch (text[i])
3089                  {                  {
3090                          case 0xff:                          case 0xff:
3091                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3092                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3093                                  {                                  {
3094                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3095                                          exit(1);                                          for (j = 0; j < length; j++)
3096                                                    fprintf(stderr, "%02x ", text[j]);
3097                                            fprintf(stderr, "\n");
3098                                            i = length = 0;
3099                                            break;
3100                                  }                                  }
3101                                    cache_put_text(text[i + 1], text, text[i + 2]);
3102                                    i += 3;
3103                                    length -= i;
3104                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3105                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3106                                  i = 0;                                  i = 0;
3107                                  break;                                  break;
3108    
3109                          case 0xfe:                          case 0xfe:
3110                                    /* At least one byte needs to follow */
3111                                    if (i + 2 > length)
3112                                    {
3113                                            warning("Skipping short 0xfe command:");
3114                                            for (j = 0; j < length; j++)
3115                                                    fprintf(stderr, "%02x ", text[j]);
3116                                            fprintf(stderr, "\n");
3117                                            i = length = 0;
3118                                            break;
3119                                    }
3120                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3121                                  if (entry != NULL)                                  if (entry->data != NULL)
3122                                  {                                  {
3123                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3124                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3125                                          {                                          {
3126                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3127                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2495  ui_draw_text(uint8 font, uint8 flags, ui Line 3153  ui_draw_text(uint8 font, uint8 flags, ui
3153          if (g_ownbackstore)          if (g_ownbackstore)
3154          {          {
3155                  if (boxcx > 1)                  if (boxcx > 1)
3156                    {
3157                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3158                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3159                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3160                                                    (g_display, g_backstore, sw->wnd, g_gc,
3161                                                     boxx, boxy,
3162                                                     boxcx, boxcy,
3163                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3164                    }
3165                  else                  else
3166                    {
3167                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3168                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3169                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3170                                                    (g_display, g_backstore, sw->wnd, g_gc,
3171                                                     clipx, clipy,
3172                                                     clipcx, clipcy, clipx - sw->xoffset,
3173                                                     clipy - sw->yoffset));
3174                    }
3175          }          }
3176  }  }
3177    
# Line 2545  ui_desktop_restore(uint32 offset, int x, Line 3217  ui_desktop_restore(uint32 offset, int x,
3217          {          {
3218                  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);
3219                  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);
3220                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3221                                            (g_display, g_backstore, sw->wnd, g_gc,
3222                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3223          }          }
3224          else          else
3225          {          {
3226                  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);
3227                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3228                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3229                                             x - sw->xoffset, y - sw->yoffset));
3230          }          }
3231    
3232          XFree(image);          XFree(image);
# Line 2564  void Line 3242  void
3242  ui_end_update(void)  ui_end_update(void)
3243  {  {
3244  }  }
3245    
3246    
3247    void
3248    ui_seamless_begin(BOOL hidden)
3249    {
3250            if (!g_seamless_rdp)
3251                    return;
3252    
3253            if (g_seamless_started)
3254                    return;
3255    
3256            g_seamless_started = True;
3257            g_seamless_hidden = hidden;
3258    
3259            if (!hidden)
3260                    ui_seamless_toggle();
3261    }
3262    
3263    
3264    void
3265    ui_seamless_hide_desktop()
3266    {
3267            if (!g_seamless_rdp)
3268                    return;
3269    
3270            if (!g_seamless_started)
3271                    return;
3272    
3273            if (g_seamless_active)
3274                    ui_seamless_toggle();
3275    
3276            g_seamless_hidden = True;
3277    }
3278    
3279    
3280    void
3281    ui_seamless_unhide_desktop()
3282    {
3283            if (!g_seamless_rdp)
3284                    return;
3285    
3286            if (!g_seamless_started)
3287                    return;
3288    
3289            g_seamless_hidden = False;
3290    
3291            ui_seamless_toggle();
3292    }
3293    
3294    
3295    void
3296    ui_seamless_toggle()
3297    {
3298            if (!g_seamless_rdp)
3299                    return;
3300    
3301            if (!g_seamless_started)
3302                    return;
3303    
3304            if (g_seamless_hidden)
3305                    return;
3306    
3307            if (g_seamless_active)
3308            {
3309                    /* Deactivate */
3310                    while (g_seamless_windows)
3311                    {
3312                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3313                            sw_remove_window(g_seamless_windows);
3314                    }
3315                    XMapWindow(g_display, g_wnd);
3316            }
3317            else
3318            {
3319                    /* Activate */
3320                    XUnmapWindow(g_display, g_wnd);
3321                    seamless_send_sync();
3322            }
3323    
3324            g_seamless_active = !g_seamless_active;
3325    }
3326    
3327    
3328    void
3329    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3330                              unsigned long flags)
3331    {
3332            Window wnd;
3333            XSetWindowAttributes attribs;
3334            XClassHint *classhints;
3335            XSizeHints *sizehints;
3336            XWMHints *wmhints;
3337            long input_mask;
3338            seamless_window *sw, *sw_parent;
3339    
3340            if (!g_seamless_active)
3341                    return;
3342    
3343            /* Ignore CREATEs for existing windows */
3344            sw = sw_get_window_by_id(id);
3345            if (sw)
3346                    return;
3347    
3348            get_window_attribs(&attribs);
3349            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3350                                InputOutput, g_visual,
3351                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3352    
3353            XStoreName(g_display, wnd, "SeamlessRDP");
3354            ewmh_set_wm_name(wnd, "SeamlessRDP");
3355    
3356            mwm_hide_decorations(wnd);
3357    
3358            classhints = XAllocClassHint();
3359            if (classhints != NULL)
3360            {
3361                    classhints->res_name = "rdesktop";
3362                    classhints->res_class = "SeamlessRDP";
3363                    XSetClassHint(g_display, wnd, classhints);
3364                    XFree(classhints);
3365            }
3366    
3367            /* WM_NORMAL_HINTS */
3368            sizehints = XAllocSizeHints();
3369            if (sizehints != NULL)
3370            {
3371                    sizehints->flags = USPosition;
3372                    XSetWMNormalHints(g_display, wnd, sizehints);
3373                    XFree(sizehints);
3374            }
3375    
3376            /* Parent-less transient windows */
3377            if (parent == 0xFFFFFFFF)
3378            {
3379                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3380                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3381                       using some other hints. */
3382                    ewmh_set_window_popup(wnd);
3383            }
3384            /* Normal transient windows */
3385            else if (parent != 0x00000000)
3386            {
3387                    sw_parent = sw_get_window_by_id(parent);
3388                    if (sw_parent)
3389                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3390                    else
3391                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3392            }
3393    
3394            if (flags & SEAMLESSRDP_CREATE_MODAL)
3395            {
3396                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3397                       somewhat at least */
3398                    if (parent == 0x00000000)
3399                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3400                    ewmh_set_window_modal(wnd);
3401            }
3402    
3403            /* FIXME: Support for Input Context:s */
3404    
3405            get_input_mask(&input_mask);
3406            input_mask |= PropertyChangeMask;
3407    
3408            XSelectInput(g_display, wnd, input_mask);
3409    
3410            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3411               seamless window, we could try to close the window on the
3412               serverside, instead of terminating rdesktop */
3413            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3414    
3415            sw = xmalloc(sizeof(seamless_window));
3416            sw->wnd = wnd;
3417            sw->id = id;
3418            sw->behind = 0;
3419            sw->group = sw_find_group(group, False);
3420            sw->group->refcnt++;
3421            sw->xoffset = 0;
3422            sw->yoffset = 0;
3423            sw->width = 0;
3424            sw->height = 0;
3425            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3426            sw->desktop = 0;
3427            sw->position_timer = xmalloc(sizeof(struct timeval));
3428            timerclear(sw->position_timer);
3429    
3430            sw->outstanding_position = False;
3431            sw->outpos_serial = 0;
3432            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3433            sw->outpos_width = sw->outpos_height = 0;
3434    
3435            sw->next = g_seamless_windows;
3436            g_seamless_windows = sw;
3437    
3438            /* WM_HINTS */
3439            wmhints = XAllocWMHints();
3440            if (wmhints)
3441            {
3442                    wmhints->flags = WindowGroupHint;
3443                    wmhints->window_group = sw->group->wnd;
3444                    XSetWMHints(g_display, sw->wnd, wmhints);
3445                    XFree(wmhints);
3446            }
3447    }
3448    
3449    
3450    void
3451    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3452    {
3453            seamless_window *sw;
3454    
3455            if (!g_seamless_active)
3456                    return;
3457    
3458            sw = sw_get_window_by_id(id);
3459            if (!sw)
3460            {
3461                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3462                    return;
3463            }
3464    
3465            XDestroyWindow(g_display, sw->wnd);
3466            sw_remove_window(sw);
3467    }
3468    
3469    
3470    void
3471    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3472    {
3473            seamless_window *sw;
3474    
3475            if (!g_seamless_active)
3476                    return;
3477    
3478            sw = sw_get_window_by_id(id);
3479            if (!sw)
3480            {
3481                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3482                    return;
3483            }
3484    
3485            /* We ignore server updates until it has handled our request. */
3486            if (sw->outstanding_position)
3487                    return;
3488    
3489            if (!width || !height)
3490                    /* X11 windows must be at least 1x1 */
3491                    return;
3492    
3493            sw->xoffset = x;
3494            sw->yoffset = y;
3495            sw->width = width;
3496            sw->height = height;
3497    
3498            /* If we move the window in a maximized state, then KDE won't
3499               accept restoration */
3500            switch (sw->state)
3501            {
3502                    case SEAMLESSRDP_MINIMIZED:
3503                    case SEAMLESSRDP_MAXIMIZED:
3504                            return;
3505            }
3506    
3507            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3508            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3509    }
3510    
3511    
3512    void
3513    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3514    {
3515            seamless_window *sw;
3516    
3517            if (!g_seamless_active)
3518                    return;
3519    
3520            sw = sw_get_window_by_id(id);
3521            if (!sw)
3522            {
3523                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3524                    return;
3525            }
3526    
3527            if (behind)
3528            {
3529                    seamless_window *sw_behind;
3530                    Window wnds[2];
3531    
3532                    sw_behind = sw_get_window_by_id(behind);
3533                    if (!sw_behind)
3534                    {
3535                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3536                                    behind);
3537                            return;
3538                    }
3539    
3540                    wnds[1] = sw_behind->wnd;
3541                    wnds[0] = sw->wnd;
3542    
3543                    XRestackWindows(g_display, wnds, 2);
3544            }
3545            else
3546            {
3547                    XRaiseWindow(g_display, sw->wnd);
3548            }
3549    
3550            sw_restack_window(sw, behind);
3551    }
3552    
3553    
3554    void
3555    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3556    {
3557            seamless_window *sw;
3558    
3559            if (!g_seamless_active)
3560                    return;
3561    
3562            sw = sw_get_window_by_id(id);
3563            if (!sw)
3564            {
3565                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3566                    return;
3567            }
3568    
3569            /* FIXME: Might want to convert the name for non-EWMH WMs */
3570            XStoreName(g_display, sw->wnd, title);
3571            ewmh_set_wm_name(sw->wnd, title);
3572    }
3573    
3574    
3575    void
3576    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3577    {
3578            seamless_window *sw;
3579    
3580            if (!g_seamless_active)
3581                    return;
3582    
3583            sw = sw_get_window_by_id(id);
3584            if (!sw)
3585            {
3586                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3587                    return;
3588            }
3589    
3590            switch (state)
3591            {
3592                    case SEAMLESSRDP_NORMAL:
3593                    case SEAMLESSRDP_MAXIMIZED:
3594                            ewmh_change_state(sw->wnd, state);
3595                            XMapWindow(g_display, sw->wnd);
3596                            break;
3597                    case SEAMLESSRDP_MINIMIZED:
3598                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3599                               the Window Manager should probably just ignore the request, since
3600                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3601                               such as minimization, rather than an independent state." Besides,
3602                               XIconifyWindow is easier. */
3603                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3604                            {
3605                                    XWMHints *hints;
3606                                    hints = XGetWMHints(g_display, sw->wnd);
3607                                    if (hints)
3608                                    {
3609                                            hints->flags |= StateHint;
3610                                            hints->initial_state = IconicState;
3611                                            XSetWMHints(g_display, sw->wnd, hints);
3612                                            XFree(hints);
3613                                    }
3614                                    XMapWindow(g_display, sw->wnd);
3615                            }
3616                            else
3617                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3618                            break;
3619                    default:
3620                            warning("SeamlessRDP: Invalid state %d\n", state);
3621                            break;
3622            }
3623    
3624            sw->state = state;
3625    }
3626    
3627    
3628    void
3629    ui_seamless_syncbegin(unsigned long flags)
3630    {
3631            if (!g_seamless_active)
3632                    return;
3633    
3634            /* Destroy all seamless windows */
3635            while (g_seamless_windows)
3636            {
3637                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3638                    sw_remove_window(g_seamless_windows);
3639            }
3640    }
3641    
3642    
3643    void
3644    ui_seamless_ack(unsigned int serial)
3645    {
3646            seamless_window *sw;
3647            for (sw = g_seamless_windows; sw; sw = sw->next)
3648            {
3649                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3650                    {
3651                            sw->xoffset = sw->outpos_xoffset;
3652                            sw->yoffset = sw->outpos_yoffset;
3653                            sw->width = sw->outpos_width;
3654                            sw->height = sw->outpos_height;
3655                            sw->outstanding_position = False;
3656    
3657                            /* Do a complete redraw of the window as part of the
3658                               completion of the move. This is to remove any
3659                               artifacts caused by our lack of synchronization. */
3660                            XCopyArea(g_display, g_backstore,
3661                                      sw->wnd, g_gc,
3662                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3663    
3664                            break;
3665                    }
3666            }
3667    }

Legend:
Removed from v.1022  
changed lines
  Added in v.1193

  ViewVC Help
Powered by ViewVC 1.1.26