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

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

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

revision 1029 by astrand, Fri Nov 18 22:46:38 2005 UTC revision 1199 by astrand, Mon Mar 27 08:17:34 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                    if (!g_seamless_windows) break; \
181                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
182                        rect.x = g_clip_rectangle.x - sw->xoffset; \
183                        rect.y = g_clip_rectangle.y - sw->yoffset; \
184                        rect.width = g_clip_rectangle.width; \
185                        rect.height = g_clip_rectangle.height; \
186                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
187                        func args; \
188                    } \
189                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
190            } while (0)
191    
192    static void
193    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
194    {
195            points[0].x -= xoffset;
196            points[0].y -= yoffset;
197            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
198            points[0].x += xoffset;
199            points[0].y += yoffset;
200    }
201    
202    static void
203    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
204    {
205            points[0].x -= xoffset;
206            points[0].y -= yoffset;
207            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
208            points[0].x += xoffset;
209            points[0].y += yoffset;
210    }
211    
212  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
213  { \  { \
214          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
215            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
216          if (g_ownbackstore) \          if (g_ownbackstore) \
217                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
218  }  }
# Line 126  PixelColour; Line 227  PixelColour;
227          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
228          if (g_ownbackstore) \          if (g_ownbackstore) \
229                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
230            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
231  }  }
232    
233  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 134  PixelColour; Line 236  PixelColour;
236          { \          { \
237                  case 0: /* Outline */ \                  case 0: /* Outline */ \
238                          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); \
239                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
240                          if (g_ownbackstore) \                          if (g_ownbackstore) \
241                                  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); \
242                          break; \                          break; \
243                  case 1: /* Filled */ \                  case 1: /* Filled */ \
244                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
245                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, \
246                                                                x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
247                          if (g_ownbackstore) \                          if (g_ownbackstore) \
248                                  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); \
249                          break; \                          break; \
# Line 150  extern BOOL g_owncolmap; Line 255  extern BOOL g_owncolmap;
255  static Colormap g_xcolmap;  static Colormap g_xcolmap;
256  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
257    
258  #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] )
259  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
260  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
261    
# Line 176  static int rop2_map[] = { Line 281  static int rop2_map[] = {
281  #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]); }
282  #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); }
283    
284    static seamless_window *
285    sw_get_window_by_id(unsigned long id)
286    {
287            seamless_window *sw;
288            for (sw = g_seamless_windows; sw; sw = sw->next)
289            {
290                    if (sw->id == id)
291                            return sw;
292            }
293            return NULL;
294    }
295    
296    
297    static seamless_window *
298    sw_get_window_by_wnd(Window wnd)
299    {
300            seamless_window *sw;
301            for (sw = g_seamless_windows; sw; sw = sw->next)
302            {
303                    if (sw->wnd == wnd)
304                            return sw;
305            }
306            return NULL;
307    }
308    
309    
310    static void
311    sw_remove_window(seamless_window * win)
312    {
313            seamless_window *sw, **prevnext = &g_seamless_windows;
314            for (sw = g_seamless_windows; sw; sw = sw->next)
315            {
316                    if (sw == win)
317                    {
318                            *prevnext = sw->next;
319                            sw->group->refcnt--;
320                            if (sw->group->refcnt == 0)
321                            {
322                                    XDestroyWindow(g_display, sw->group->wnd);
323                                    xfree(sw->group);
324                            }
325                            xfree(sw->position_timer);
326                            xfree(sw);
327                            return;
328                    }
329                    prevnext = &sw->next;
330            }
331            return;
332    }
333    
334    
335    /* Move all windows except wnd to new desktop */
336    static void
337    sw_all_to_desktop(Window wnd, unsigned int desktop)
338    {
339            seamless_window *sw;
340            for (sw = g_seamless_windows; sw; sw = sw->next)
341            {
342                    if (sw->wnd == wnd)
343                            continue;
344                    if (sw->desktop != desktop)
345                    {
346                            ewmh_move_to_desktop(sw->wnd, desktop);
347                            sw->desktop = desktop;
348                    }
349            }
350    }
351    
352    
353    /* Send our position */
354    static void
355    sw_update_position(seamless_window * sw)
356    {
357            XWindowAttributes wa;
358            int x, y;
359            Window child_return;
360            unsigned int serial;
361    
362            XGetWindowAttributes(g_display, sw->wnd, &wa);
363            XTranslateCoordinates(g_display, sw->wnd, wa.root,
364                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
365    
366            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
367    
368            sw->outstanding_position = True;
369            sw->outpos_serial = serial;
370    
371            sw->outpos_xoffset = x;
372            sw->outpos_yoffset = y;
373            sw->outpos_width = wa.width;
374            sw->outpos_height = wa.height;
375    }
376    
377    
378    /* Check if it's time to send our position */
379    static void
380    sw_check_timers()
381    {
382            seamless_window *sw;
383            struct timeval now;
384    
385            gettimeofday(&now, NULL);
386            for (sw = g_seamless_windows; sw; sw = sw->next)
387            {
388                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
389                    {
390                            timerclear(sw->position_timer);
391                            sw_update_position(sw);
392                    }
393            }
394    }
395    
396    
397    static void
398    sw_restack_window(seamless_window * sw, unsigned long behind)
399    {
400            seamless_window *sw_above;
401    
402            /* Remove window from stack */
403            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
404            {
405                    if (sw_above->behind == sw->id)
406                            break;
407            }
408    
409            if (sw_above)
410                    sw_above->behind = sw->behind;
411    
412            /* And then add it at the new position */
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  static void
427  mwm_hide_decorations(void)  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                            if (visual_info->depth > 24)
1380                            {
1381                                    /* Avoid 32-bit visuals and likes like the plague.
1382                                       They're either untested or proven to work bad
1383                                       (e.g. nvidia's Composite 32-bit visual).
1384                                       Most implementation offer a 24-bit visual anyway. */
1385                                    continue;
1386                            }
1387    
1388          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1389          while (nvisuals >= 0)                             we have a translateXtoY function. */
1390          {                          BOOL can_translate_to_bpp = False;
1391                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1392                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1393                          g_depth = (vmatches + nvisuals)->depth;                          {
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));
1528                  XCloseDisplay(g_display);                  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            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1538            screen_num = DefaultScreen(g_display);
1539            g_x_socket = ConnectionNumber(g_display);
1540            g_screen = ScreenOfDisplay(g_display, screen_num);
1541            g_depth = DefaultDepthOfScreen(g_screen);
1542    
1543            if (!select_visual())
1544                  return False;                  return False;
1545    
1546            if (g_no_translate_image)
1547            {
1548                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1549            }
1550    
1551            if (g_server_depth > g_bpp)
1552            {
1553                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1554                            g_server_depth, g_bpp);
1555          }          }
1556    
1557            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1558                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1559    
1560          if (!g_owncolmap)          if (!g_owncolmap)
1561          {          {
1562                  g_xcolmap =                  g_xcolmap =
1563                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1564                                          AllocNone);                                          AllocNone);
1565                  if (g_depth <= 8)                  if (g_depth <= 8)
1566                          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);
1567          }          }
1568    
1569          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1570          {          {
1571                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1572                  g_ownbackstore = True;                  g_ownbackstore = True;
1573          }          }
1574    
# Line 1087  ui_init(void) Line 1579  ui_init(void)
1579          {          {
1580                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1581                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1582                    g_using_full_workarea = True;
1583          }          }
1584          else if (g_width < 0)          else if (g_width < 0)
1585          {          {
# Line 1100  ui_init(void) Line 1593  ui_init(void)
1593          {          {
1594                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1595                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
                 g_using_full_workarea = True;  
   
1596                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1597                  {                  {
1598                          g_width = cx;                          g_width = cx;
1599                          g_height = cy;                          g_height = cy;
1600                            g_using_full_workarea = True;
1601                  }                  }
1602                  else                  else
1603                  {                  {
1604                          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");
1605                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1606                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1607                  }                  }
1608          }          }
1609    
# Line 1126  ui_init(void) Line 1618  ui_init(void)
1618                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1619    
1620          xclip_init();          xclip_init();
1621            ewmh_init();
1622            if (g_seamless_rdp)
1623                    seamless_init();
1624    
1625          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));
1626    
1627          return True;          return True;
1628  }  }
# Line 1135  ui_init(void) Line 1630  ui_init(void)
1630  void  void
1631  ui_deinit(void)  ui_deinit(void)
1632  {  {
1633            while (g_seamless_windows)
1634            {
1635                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1636                    sw_remove_window(g_seamless_windows);
1637            }
1638    
1639          if (g_IM != NULL)          if (g_IM != NULL)
1640                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1641    
# Line 1151  ui_deinit(void) Line 1652  ui_deinit(void)
1652          g_display = NULL;          g_display = NULL;
1653  }  }
1654    
1655    
1656    static void
1657    get_window_attribs(XSetWindowAttributes * attribs)
1658    {
1659            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1660            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1661            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1662            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1663            attribs->override_redirect = g_fullscreen;
1664            attribs->colormap = g_xcolmap;
1665    }
1666    
1667    static void
1668    get_input_mask(long *input_mask)
1669    {
1670            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1671                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1672    
1673            if (g_sendmotion)
1674                    *input_mask |= PointerMotionMask;
1675            if (g_ownbackstore)
1676                    *input_mask |= ExposureMask;
1677            if (g_fullscreen || g_grab_keyboard)
1678                    *input_mask |= EnterWindowMask;
1679            if (g_grab_keyboard)
1680                    *input_mask |= LeaveWindowMask;
1681    }
1682    
1683  BOOL  BOOL
1684  ui_create_window(void)  ui_create_window(void)
1685  {  {
# Line 1173  ui_create_window(void) Line 1702  ui_create_window(void)
1702          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1703                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1704    
1705          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;  
1706    
1707          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,
1708                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1185  ui_create_window(void) Line 1710  ui_create_window(void)
1710                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1711    
1712          if (g_gc == NULL)          if (g_gc == NULL)
1713            {
1714                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1715                    ui_reset_clip();
1716            }
1717    
1718          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1719                  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 1730  ui_create_window(void)
1730          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1731    
1732          if (g_hide_decorations)          if (g_hide_decorations)
1733                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1734    
1735          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1736          if (classhints != NULL)          if (classhints != NULL)
# Line 1229  ui_create_window(void) Line 1757  ui_create_window(void)
1757                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1758          }          }
1759    
1760          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;  
1761    
1762          if (g_IM != NULL)          if (g_IM != NULL)
1763          {          {
# Line 1324  xwin_toggle_fullscreen(void) Line 1842  xwin_toggle_fullscreen(void)
1842  {  {
1843          Pixmap contents = 0;          Pixmap contents = 0;
1844    
1845            if (g_seamless_active)
1846                    /* Turn off SeamlessRDP mode */
1847                    ui_seamless_toggle();
1848    
1849          if (!g_ownbackstore)          if (!g_ownbackstore)
1850          {          {
1851                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1412  handle_button_event(XEvent xevent, BOOL Line 1934  handle_button_event(XEvent xevent, BOOL
1934                  }                  }
1935          }          }
1936    
1937          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
1938                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
1939                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1940                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1941            }
1942            else
1943            {
1944                    /* SeamlessRDP */
1945                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1946                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1947            }
1948  }  }
1949    
1950    
1951  /* Process events in Xlib queue  /* Process events in Xlib queue
1952     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1953  static int  static int
# Line 1427  xwin_process_events(void) Line 1959  xwin_process_events(void)
1959          char str[256];          char str[256];
1960          Status status;          Status status;
1961          int events = 0;          int events = 0;
1962            seamless_window *sw;
1963    
1964          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1965          {          {
# Line 1441  xwin_process_events(void) Line 1974  xwin_process_events(void)
1974                  switch (xevent.type)                  switch (xevent.type)
1975                  {                  {
1976                          case VisibilityNotify:                          case VisibilityNotify:
1977                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1978                                            g_Unobscured =
1979                                                    xevent.xvisibility.state == VisibilityUnobscured;
1980    
1981                                  break;                                  break;
1982                          case ClientMessage:                          case ClientMessage:
1983                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1521  xwin_process_events(void) Line 2057  xwin_process_events(void)
2057                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2058                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2059                                                         CurrentTime);                                                         CurrentTime);
2060                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2061                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2062                                    {
2063                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2064                                                           xevent.xmotion.x, xevent.xmotion.y);
2065                                    }
2066                                    else
2067                                    {
2068                                            /* SeamlessRDP */
2069                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2070                                                           xevent.xmotion.x_root,
2071                                                           xevent.xmotion.y_root);
2072                                    }
2073                                  break;                                  break;
2074    
2075                          case FocusIn:                          case FocusIn:
# Line 1533  xwin_process_events(void) Line 2080  xwin_process_events(void)
2080                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2081                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2082                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2083    
2084                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2085                                    if (!sw)
2086                                            break;
2087    
2088                                    if (sw->id != g_seamless_focused)
2089                                    {
2090                                            seamless_send_focus(sw->id, 0);
2091                                            g_seamless_focused = sw->id;
2092                                    }
2093                                  break;                                  break;
2094    
2095                          case FocusOut:                          case FocusOut:
# Line 1565  xwin_process_events(void) Line 2122  xwin_process_events(void)
2122                                  break;                                  break;
2123    
2124                          case Expose:                          case Expose:
2125                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2126                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2127                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2128                                            xevent.xexpose.height,                                                    g_gc,
2129                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2130                                                      xevent.xexpose.width, xevent.xexpose.height,
2131                                                      xevent.xexpose.x, xevent.xexpose.y);
2132                                    }
2133                                    else
2134                                    {
2135                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2136                                            if (!sw)
2137                                                    break;
2138                                            XCopyArea(g_display, g_backstore,
2139                                                      xevent.xexpose.window, g_gc,
2140                                                      xevent.xexpose.x + sw->xoffset,
2141                                                      xevent.xexpose.y + sw->yoffset,
2142                                                      xevent.xexpose.width,
2143                                                      xevent.xexpose.height, xevent.xexpose.x,
2144                                                      xevent.xexpose.y);
2145                                    }
2146    
2147                                  break;                                  break;
2148    
2149                          case MappingNotify:                          case MappingNotify:
# Line 1598  xwin_process_events(void) Line 2172  xwin_process_events(void)
2172                                  break;                                  break;
2173                          case PropertyNotify:                          case PropertyNotify:
2174                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2175                                    if (xevent.xproperty.window == g_wnd)
2176                                            break;
2177                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2178                                            break;
2179    
2180                                    /* seamless */
2181                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2182                                    if (!sw)
2183                                            break;
2184    
2185                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2186                                        && (xevent.xproperty.state == PropertyNewValue))
2187                                    {
2188                                            sw->state = ewmh_get_window_state(sw->wnd);
2189                                            seamless_send_state(sw->id, sw->state, 0);
2190                                    }
2191    
2192                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2193                                        && (xevent.xproperty.state == PropertyNewValue))
2194                                    {
2195                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2196                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2197                                    }
2198    
2199                                  break;                                  break;
2200                          case MapNotify:                          case MapNotify:
2201                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2202                                            rdp_send_client_window_status(1);
2203                                  break;                                  break;
2204                          case UnmapNotify:                          case UnmapNotify:
2205                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2206                                            rdp_send_client_window_status(0);
2207                                    break;
2208                            case ConfigureNotify:
2209                                    if (!g_seamless_active)
2210                                            break;
2211    
2212                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2213                                    if (!sw)
2214                                            break;
2215    
2216                                    gettimeofday(sw->position_timer, NULL);
2217                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2218                                        1000000)
2219                                    {
2220                                            sw->position_timer->tv_usec +=
2221                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2222                                            sw->position_timer->tv_sec += 1;
2223                                    }
2224                                    else
2225                                    {
2226                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2227                                    }
2228    
2229                                    sw_handle_restack(sw);
2230                                  break;                                  break;
2231                  }                  }
2232          }          }
# Line 1628  ui_select(int rdp_socket) Line 2251  ui_select(int rdp_socket)
2251                          /* User quit */                          /* User quit */
2252                          return 0;                          return 0;
2253    
2254                    if (g_seamless_active)
2255                            sw_check_timers();
2256    
2257                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2258                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2259                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1647  ui_select(int rdp_socket) Line 2273  ui_select(int rdp_socket)
2273    
2274                  /* add redirection handles */                  /* add redirection handles */
2275                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2276                    seamless_select_timeout(&tv);
2277    
2278                  n++;                  n++;
2279    
# Line 1688  ui_create_bitmap(int width, int height, Line 2315  ui_create_bitmap(int width, int height,
2315          uint8 *tdata;          uint8 *tdata;
2316          int bitmap_pad;          int bitmap_pad;
2317    
2318          if (g_server_bpp == 8)          if (g_server_depth == 8)
2319          {          {
2320                  bitmap_pad = 8;                  bitmap_pad = 8;
2321          }          }
# Line 1720  ui_paint_bitmap(int x, int y, int cx, in Line 2347  ui_paint_bitmap(int x, int y, int cx, in
2347          uint8 *tdata;          uint8 *tdata;
2348          int bitmap_pad;          int bitmap_pad;
2349    
2350          if (g_server_bpp == 8)          if (g_server_depth == 8)
2351          {          {
2352                  bitmap_pad = 8;                  bitmap_pad = 8;
2353          }          }
# Line 1740  ui_paint_bitmap(int x, int y, int cx, in Line 2367  ui_paint_bitmap(int x, int y, int cx, in
2367          {          {
2368                  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);
2369                  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);
2370                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2371                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2372                                             x - sw->xoffset, y - sw->yoffset));
2373          }          }
2374          else          else
2375          {          {
2376                  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);
2377                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2378                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2379                                             x - sw->xoffset, y - sw->yoffset));
2380          }          }
2381    
2382          XFree(image);          XFree(image);
# Line 1864  ui_set_cursor(HCURSOR cursor) Line 2497  ui_set_cursor(HCURSOR cursor)
2497  {  {
2498          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2499          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2500            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2501  }  }
2502    
2503  void  void
# Line 2005  ui_set_colourmap(HCOLOURMAP map) Line 2639  ui_set_colourmap(HCOLOURMAP map)
2639                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2640          }          }
2641          else          else
2642            {
2643                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2644                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2645            }
2646  }  }
2647    
2648  void  void
2649  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2650  {  {
2651          XRectangle rect;          g_clip_rectangle.x = x;
2652            g_clip_rectangle.y = y;
2653          rect.x = x;          g_clip_rectangle.width = cx;
2654          rect.y = y;          g_clip_rectangle.height = cy;
2655          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);  
2656  }  }
2657    
2658  void  void
2659  ui_reset_clip(void)  ui_reset_clip(void)
2660  {  {
2661          XRectangle rect;          g_clip_rectangle.x = 0;
2662            g_clip_rectangle.y = 0;
2663          rect.x = 0;          g_clip_rectangle.width = g_width;
2664          rect.y = 0;          g_clip_rectangle.height = g_height;
2665          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);  
2666  }  }
2667    
2668  void  void
# Line 2110  ui_patblt(uint8 opcode, Line 2743  ui_patblt(uint8 opcode,
2743    
2744          if (g_ownbackstore)          if (g_ownbackstore)
2745                  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);
2746            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2747                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2748                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2749  }  }
2750    
2751  void  void
# Line 2120  ui_screenblt(uint8 opcode, Line 2756  ui_screenblt(uint8 opcode,
2756          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2757          if (g_ownbackstore)          if (g_ownbackstore)
2758          {          {
2759                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2760                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2761                          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);  
                 }  
2762          }          }
2763          else          else
2764          {          {
2765                  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);
2766          }          }
2767    
2768            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2769                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2770                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2771    
2772          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2773  }  }
2774    
# Line 2147  ui_memblt(uint8 opcode, Line 2779  ui_memblt(uint8 opcode,
2779  {  {
2780          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2781          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);
2782            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2783                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2784                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2785          if (g_ownbackstore)          if (g_ownbackstore)
2786                  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);
2787          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2193  ui_line(uint8 opcode, Line 2828  ui_line(uint8 opcode,
2828          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2829          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2830          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2831            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2832                                                startx - sw->xoffset, starty - sw->yoffset,
2833                                                endx - sw->xoffset, endy - sw->yoffset));
2834          if (g_ownbackstore)          if (g_ownbackstore)
2835                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2836          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2290  ui_polyline(uint8 opcode, Line 2928  ui_polyline(uint8 opcode,
2928          if (g_ownbackstore)          if (g_ownbackstore)
2929                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2930                             CoordModePrevious);                             CoordModePrevious);
2931    
2932            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2933                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2934    
2935          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2936  }  }
2937    
# Line 2445  ui_draw_text(uint8 font, uint8 flags, ui Line 3087  ui_draw_text(uint8 font, uint8 flags, ui
3087                  switch (text[i])                  switch (text[i])
3088                  {                  {
3089                          case 0xff:                          case 0xff:
3090                                    /* At least two bytes needs to follow */
3091                                  if (i + 3 > length)                                  if (i + 3 > length)
3092                                  {                                  {
3093                                          /* short command, skip */                                          warning("Skipping short 0xff command:");
3094                                            for (j = 0; j < length; j++)
3095                                                    fprintf(stderr, "%02x ", text[j]);
3096                                            fprintf(stderr, "\n");
3097                                          i = length = 0;                                          i = length = 0;
3098                                          break;                                          break;
3099                                  }                                  }
# Line 2460  ui_draw_text(uint8 font, uint8 flags, ui Line 3106  ui_draw_text(uint8 font, uint8 flags, ui
3106                                  break;                                  break;
3107    
3108                          case 0xfe:                          case 0xfe:
3109                                  if (i + 3 > length)                                  /* At least one byte needs to follow */
3110                                    if (i + 2 > length)
3111                                  {                                  {
3112                                          /* short command, skip */                                          warning("Skipping short 0xfe command:");
3113                                            for (j = 0; j < length; j++)
3114                                                    fprintf(stderr, "%02x ", text[j]);
3115                                            fprintf(stderr, "\n");
3116                                          i = length = 0;                                          i = length = 0;
3117                                          break;                                          break;
3118                                  }                                  }
3119                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3120                                  if (entry != NULL)                                  if (entry->data != NULL)
3121                                  {                                  {
3122                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3123                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3124                                          {                                          {
3125                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3126                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2480  ui_draw_text(uint8 font, uint8 flags, ui Line 3130  ui_draw_text(uint8 font, uint8 flags, ui
3130                                          for (j = 0; j < entry->size; j++)                                          for (j = 0; j < entry->size; j++)
3131                                                  DO_GLYPH(((uint8 *) (entry->data)), j);                                                  DO_GLYPH(((uint8 *) (entry->data)), j);
3132                                  }                                  }
3133                                  i += 3;                                  if (i + 2 < length)
3134                                            i += 3;
3135                                    else
3136                                            i += 2;
3137                                  length -= i;                                  length -= i;
3138                                  /* this will move pointer from start to first character after FE command */                                  /* this will move pointer from start to first character after FE command */
3139                                  text = &(text[i]);                                  text = &(text[i]);
# Line 2499  ui_draw_text(uint8 font, uint8 flags, ui Line 3152  ui_draw_text(uint8 font, uint8 flags, ui
3152          if (g_ownbackstore)          if (g_ownbackstore)
3153          {          {
3154                  if (boxcx > 1)                  if (boxcx > 1)
3155                    {
3156                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3157                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3158                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3159                                                    (g_display, g_backstore, sw->wnd, g_gc,
3160                                                     boxx, boxy,
3161                                                     boxcx, boxcy,
3162                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3163                    }
3164                  else                  else
3165                    {
3166                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3167                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3168                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3169                                                    (g_display, g_backstore, sw->wnd, g_gc,
3170                                                     clipx, clipy,
3171                                                     clipcx, clipcy, clipx - sw->xoffset,
3172                                                     clipy - sw->yoffset));
3173                    }
3174          }          }
3175  }  }
3176    
# Line 2549  ui_desktop_restore(uint32 offset, int x, Line 3216  ui_desktop_restore(uint32 offset, int x,
3216          {          {
3217                  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);
3218                  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);
3219                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3220                                            (g_display, g_backstore, sw->wnd, g_gc,
3221                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3222          }          }
3223          else          else
3224          {          {
3225                  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);
3226                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3227                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3228                                             x - sw->xoffset, y - sw->yoffset));
3229          }          }
3230    
3231          XFree(image);          XFree(image);
# Line 2568  void Line 3241  void
3241  ui_end_update(void)  ui_end_update(void)
3242  {  {
3243  }  }
3244    
3245    
3246    void
3247    ui_seamless_begin(BOOL hidden)
3248    {
3249            if (!g_seamless_rdp)
3250                    return;
3251    
3252            if (g_seamless_started)
3253                    return;
3254    
3255            g_seamless_started = True;
3256            g_seamless_hidden = hidden;
3257    
3258            if (!hidden)
3259                    ui_seamless_toggle();
3260    }
3261    
3262    
3263    void
3264    ui_seamless_hide_desktop()
3265    {
3266            if (!g_seamless_rdp)
3267                    return;
3268    
3269            if (!g_seamless_started)
3270                    return;
3271    
3272            if (g_seamless_active)
3273                    ui_seamless_toggle();
3274    
3275            g_seamless_hidden = True;
3276    }
3277    
3278    
3279    void
3280    ui_seamless_unhide_desktop()
3281    {
3282            if (!g_seamless_rdp)
3283                    return;
3284    
3285            if (!g_seamless_started)
3286                    return;
3287    
3288            g_seamless_hidden = False;
3289    
3290            ui_seamless_toggle();
3291    }
3292    
3293    
3294    void
3295    ui_seamless_toggle()
3296    {
3297            if (!g_seamless_rdp)
3298                    return;
3299    
3300            if (!g_seamless_started)
3301                    return;
3302    
3303            if (g_seamless_hidden)
3304                    return;
3305    
3306            if (g_seamless_active)
3307            {
3308                    /* Deactivate */
3309                    while (g_seamless_windows)
3310                    {
3311                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3312                            sw_remove_window(g_seamless_windows);
3313                    }
3314                    XMapWindow(g_display, g_wnd);
3315            }
3316            else
3317            {
3318                    /* Activate */
3319                    XUnmapWindow(g_display, g_wnd);
3320                    seamless_send_sync();
3321            }
3322    
3323            g_seamless_active = !g_seamless_active;
3324    }
3325    
3326    
3327    void
3328    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3329                              unsigned long flags)
3330    {
3331            Window wnd;
3332            XSetWindowAttributes attribs;
3333            XClassHint *classhints;
3334            XSizeHints *sizehints;
3335            XWMHints *wmhints;
3336            long input_mask;
3337            seamless_window *sw, *sw_parent;
3338    
3339            if (!g_seamless_active)
3340                    return;
3341    
3342            /* Ignore CREATEs for existing windows */
3343            sw = sw_get_window_by_id(id);
3344            if (sw)
3345                    return;
3346    
3347            get_window_attribs(&attribs);
3348            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3349                                InputOutput, g_visual,
3350                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3351    
3352            XStoreName(g_display, wnd, "SeamlessRDP");
3353            ewmh_set_wm_name(wnd, "SeamlessRDP");
3354    
3355            mwm_hide_decorations(wnd);
3356    
3357            classhints = XAllocClassHint();
3358            if (classhints != NULL)
3359            {
3360                    classhints->res_name = "rdesktop";
3361                    classhints->res_class = "SeamlessRDP";
3362                    XSetClassHint(g_display, wnd, classhints);
3363                    XFree(classhints);
3364            }
3365    
3366            /* WM_NORMAL_HINTS */
3367            sizehints = XAllocSizeHints();
3368            if (sizehints != NULL)
3369            {
3370                    sizehints->flags = USPosition;
3371                    XSetWMNormalHints(g_display, wnd, sizehints);
3372                    XFree(sizehints);
3373            }
3374    
3375            /* Parent-less transient windows */
3376            if (parent == 0xFFFFFFFF)
3377            {
3378                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3379                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3380                       using some other hints. */
3381                    ewmh_set_window_popup(wnd);
3382            }
3383            /* Normal transient windows */
3384            else if (parent != 0x00000000)
3385            {
3386                    sw_parent = sw_get_window_by_id(parent);
3387                    if (sw_parent)
3388                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3389                    else
3390                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3391            }
3392    
3393            if (flags & SEAMLESSRDP_CREATE_MODAL)
3394            {
3395                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3396                       somewhat at least */
3397                    if (parent == 0x00000000)
3398                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3399                    ewmh_set_window_modal(wnd);
3400            }
3401    
3402            /* FIXME: Support for Input Context:s */
3403    
3404            get_input_mask(&input_mask);
3405            input_mask |= PropertyChangeMask;
3406    
3407            XSelectInput(g_display, wnd, input_mask);
3408    
3409            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3410               seamless window, we could try to close the window on the
3411               serverside, instead of terminating rdesktop */
3412            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3413    
3414            sw = xmalloc(sizeof(seamless_window));
3415            sw->wnd = wnd;
3416            sw->id = id;
3417            sw->behind = 0;
3418            sw->group = sw_find_group(group, False);
3419            sw->group->refcnt++;
3420            sw->xoffset = 0;
3421            sw->yoffset = 0;
3422            sw->width = 0;
3423            sw->height = 0;
3424            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3425            sw->desktop = 0;
3426            sw->position_timer = xmalloc(sizeof(struct timeval));
3427            timerclear(sw->position_timer);
3428    
3429            sw->outstanding_position = False;
3430            sw->outpos_serial = 0;
3431            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3432            sw->outpos_width = sw->outpos_height = 0;
3433    
3434            sw->next = g_seamless_windows;
3435            g_seamless_windows = sw;
3436    
3437            /* WM_HINTS */
3438            wmhints = XAllocWMHints();
3439            if (wmhints)
3440            {
3441                    wmhints->flags = WindowGroupHint;
3442                    wmhints->window_group = sw->group->wnd;
3443                    XSetWMHints(g_display, sw->wnd, wmhints);
3444                    XFree(wmhints);
3445            }
3446    }
3447    
3448    
3449    void
3450    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3451    {
3452            seamless_window *sw;
3453    
3454            if (!g_seamless_active)
3455                    return;
3456    
3457            sw = sw_get_window_by_id(id);
3458            if (!sw)
3459            {
3460                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3461                    return;
3462            }
3463    
3464            XDestroyWindow(g_display, sw->wnd);
3465            sw_remove_window(sw);
3466    }
3467    
3468    
3469    void
3470    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3471    {
3472            seamless_window *sw;
3473    
3474            if (!g_seamless_active)
3475                    return;
3476    
3477            sw = sw_get_window_by_id(id);
3478            if (!sw)
3479            {
3480                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3481                    return;
3482            }
3483    
3484            /* We ignore server updates until it has handled our request. */
3485            if (sw->outstanding_position)
3486                    return;
3487    
3488            if (!width || !height)
3489                    /* X11 windows must be at least 1x1 */
3490                    return;
3491    
3492            sw->xoffset = x;
3493            sw->yoffset = y;
3494            sw->width = width;
3495            sw->height = height;
3496    
3497            /* If we move the window in a maximized state, then KDE won't
3498               accept restoration */
3499            switch (sw->state)
3500            {
3501                    case SEAMLESSRDP_MINIMIZED:
3502                    case SEAMLESSRDP_MAXIMIZED:
3503                            return;
3504            }
3505    
3506            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3507            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3508    }
3509    
3510    
3511    void
3512    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3513    {
3514            seamless_window *sw;
3515    
3516            if (!g_seamless_active)
3517                    return;
3518    
3519            sw = sw_get_window_by_id(id);
3520            if (!sw)
3521            {
3522                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3523                    return;
3524            }
3525    
3526            if (behind)
3527            {
3528                    seamless_window *sw_behind;
3529                    Window wnds[2];
3530    
3531                    sw_behind = sw_get_window_by_id(behind);
3532                    if (!sw_behind)
3533                    {
3534                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3535                                    behind);
3536                            return;
3537                    }
3538    
3539                    wnds[1] = sw_behind->wnd;
3540                    wnds[0] = sw->wnd;
3541    
3542                    XRestackWindows(g_display, wnds, 2);
3543            }
3544            else
3545            {
3546                    XRaiseWindow(g_display, sw->wnd);
3547            }
3548    
3549            sw_restack_window(sw, behind);
3550    }
3551    
3552    
3553    void
3554    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3555    {
3556            seamless_window *sw;
3557    
3558            if (!g_seamless_active)
3559                    return;
3560    
3561            sw = sw_get_window_by_id(id);
3562            if (!sw)
3563            {
3564                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3565                    return;
3566            }
3567    
3568            /* FIXME: Might want to convert the name for non-EWMH WMs */
3569            XStoreName(g_display, sw->wnd, title);
3570            ewmh_set_wm_name(sw->wnd, title);
3571    }
3572    
3573    
3574    void
3575    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3576    {
3577            seamless_window *sw;
3578    
3579            if (!g_seamless_active)
3580                    return;
3581    
3582            sw = sw_get_window_by_id(id);
3583            if (!sw)
3584            {
3585                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3586                    return;
3587            }
3588    
3589            switch (state)
3590            {
3591                    case SEAMLESSRDP_NORMAL:
3592                    case SEAMLESSRDP_MAXIMIZED:
3593                            ewmh_change_state(sw->wnd, state);
3594                            XMapWindow(g_display, sw->wnd);
3595                            break;
3596                    case SEAMLESSRDP_MINIMIZED:
3597                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3598                               the Window Manager should probably just ignore the request, since
3599                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3600                               such as minimization, rather than an independent state." Besides,
3601                               XIconifyWindow is easier. */
3602                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3603                            {
3604                                    XWMHints *hints;
3605                                    hints = XGetWMHints(g_display, sw->wnd);
3606                                    if (hints)
3607                                    {
3608                                            hints->flags |= StateHint;
3609                                            hints->initial_state = IconicState;
3610                                            XSetWMHints(g_display, sw->wnd, hints);
3611                                            XFree(hints);
3612                                    }
3613                                    XMapWindow(g_display, sw->wnd);
3614                            }
3615                            else
3616                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3617                            break;
3618                    default:
3619                            warning("SeamlessRDP: Invalid state %d\n", state);
3620                            break;
3621            }
3622    
3623            sw->state = state;
3624    }
3625    
3626    
3627    void
3628    ui_seamless_syncbegin(unsigned long flags)
3629    {
3630            if (!g_seamless_active)
3631                    return;
3632    
3633            /* Destroy all seamless windows */
3634            while (g_seamless_windows)
3635            {
3636                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3637                    sw_remove_window(g_seamless_windows);
3638            }
3639    }
3640    
3641    
3642    void
3643    ui_seamless_ack(unsigned int serial)
3644    {
3645            seamless_window *sw;
3646            for (sw = g_seamless_windows; sw; sw = sw->next)
3647            {
3648                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3649                    {
3650                            sw->xoffset = sw->outpos_xoffset;
3651                            sw->yoffset = sw->outpos_yoffset;
3652                            sw->width = sw->outpos_width;
3653                            sw->height = sw->outpos_height;
3654                            sw->outstanding_position = False;
3655    
3656                            /* Do a complete redraw of the window as part of the
3657                               completion of the move. This is to remove any
3658                               artifacts caused by our lack of synchronization. */
3659                            XCopyArea(g_display, g_backstore,
3660                                      sw->wnd, g_gc,
3661                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3662    
3663                            break;
3664                    }
3665            }
3666    }

Legend:
Removed from v.1029  
changed lines
  Added in v.1199

  ViewVC Help
Powered by ViewVC 1.1.26