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

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

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

sourceforge.net/trunk/rdesktop/xwin.c revision 1040 by astrand, Tue Jan 24 12:24:40 2006 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1170 by astrand, Mon Mar 20 15:43:15 2006 UTC
# Line 38  extern BOOL g_fullscreen; Line 38  extern BOOL g_fullscreen;
38  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
39  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
40  extern char g_title[];  extern char g_title[];
41  extern int g_server_bpp;  /* Color depth of the RDP session.
42       As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44  extern int g_win_button_size;  extern int g_win_button_size;
45    
46  Display *g_display;  Display *g_display;
# Line 46  Time g_last_gesturetime; Line 48  Time g_last_gesturetime;
48  static int g_x_socket;  static int g_x_socket;
49  static Screen *g_screen;  static Screen *g_screen;
50  Window g_wnd;  Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            unsigned long behind;
58            int xoffset, yoffset;
59            int width, height;
60            int state;              /* normal/minimized/maximized. */
61            unsigned int desktop;
62            struct timeval *position_timer;
63    
64            BOOL outstanding_position;
65            unsigned int outpos_serial;
66            int outpos_xoffset, outpos_yoffset;
67            int outpos_width, outpos_height;
68    
69            struct _seamless_window *next;
70    } seamless_window;
71    static seamless_window *g_seamless_windows = NULL;
72    static unsigned long g_seamless_focused = 0;
73    static BOOL g_seamless_started = False; /* Server end is up and running */
74    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
75    extern BOOL g_seamless_rdp;
76    
77  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
78  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
79  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
80  static GC g_gc = NULL;  static GC g_gc = NULL;
81  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
82  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
83    static XRectangle g_clip_rectangle;
84  static Visual *g_visual;  static Visual *g_visual;
85    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
86       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
87       as far as we're concerned. */
88  static int g_depth;  static int g_depth;
89    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
90       This may be larger than g_depth, in which case some of the bits would
91       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
92  static int g_bpp;  static int g_bpp;
93  static XIM g_IM;  static XIM g_IM;
94  static XIC g_IC;  static XIC g_IC;
# Line 61  static XModifierKeymap *g_mod_map; Line 96  static XModifierKeymap *g_mod_map;
96  static Cursor g_current_cursor;  static Cursor g_current_cursor;
97  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
98  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
99    extern Atom g_net_wm_state_atom;
100    extern Atom g_net_wm_desktop_atom;
101  static BOOL g_focused;  static BOOL g_focused;
102  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
103  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
104       1) visual has 15, 16 or 24 depth and the same color channel masks
105          as its RDP equivalent (implies X server is LE),
106       2) host is LE
107       This will trigger an optimization whose real value is questionable.
108    */
109    static BOOL g_compatible_arch;
110    /* Indicates whether RDP's bitmaps and our XImages have the same
111       binary format. If so, we can avoid an expensive translation.
112       Note that this can be true when g_compatible_arch is false,
113       e.g.:
114      
115         RDP(LE) <-> host(BE) <-> X-Server(LE)
116        
117       ('host' is the machine running rdesktop; the host simply memcpy's
118        so its endianess doesn't matter)
119     */
120    static BOOL g_no_translate_image = False;
121    
122  /* endianness */  /* endianness */
123  static BOOL g_host_be;  static BOOL g_host_be;
# Line 108  typedef struct Line 162  typedef struct
162  }  }
163  PixelColour;  PixelColour;
164    
165    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
166            do { \
167                    seamless_window *sw; \
168                    XRectangle rect; \
169                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
170                        rect.x = g_clip_rectangle.x - sw->xoffset; \
171                        rect.y = g_clip_rectangle.y - sw->yoffset; \
172                        rect.width = g_clip_rectangle.width; \
173                        rect.height = g_clip_rectangle.height; \
174                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
175                        func args; \
176                    } \
177                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
178            } while (0)
179    
180    static void
181    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
182    {
183            points[0].x -= xoffset;
184            points[0].y -= yoffset;
185            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
186            points[0].x += xoffset;
187            points[0].y += yoffset;
188    }
189    
190    static void
191    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
192    {
193            points[0].x -= xoffset;
194            points[0].y -= yoffset;
195            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
196            points[0].x += xoffset;
197            points[0].y += yoffset;
198    }
199    
200  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
201  { \  { \
202          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
203            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
204          if (g_ownbackstore) \          if (g_ownbackstore) \
205                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
206  }  }
# Line 126  PixelColour; Line 215  PixelColour;
215          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
216          if (g_ownbackstore) \          if (g_ownbackstore) \
217                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
218            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
219  }  }
220    
221  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 134  PixelColour; Line 224  PixelColour;
224          { \          { \
225                  case 0: /* Outline */ \                  case 0: /* Outline */ \
226                          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); \
227                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
228                          if (g_ownbackstore) \                          if (g_ownbackstore) \
229                                  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); \
230                          break; \                          break; \
231                  case 1: /* Filled */ \                  case 1: /* Filled */ \
232                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
233                                     cx, cy, 0, 360*64); \
234                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
235                          if (g_ownbackstore) \                          if (g_ownbackstore) \
236                                  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); \
237                          break; \                          break; \
# Line 150  extern BOOL g_owncolmap; Line 243  extern BOOL g_owncolmap;
243  static Colormap g_xcolmap;  static Colormap g_xcolmap;
244  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
245    
246  #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] )
247  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
248  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
249    
# Line 176  static int rop2_map[] = { Line 269  static int rop2_map[] = {
269  #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]); }
270  #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); }
271    
272    static seamless_window *
273    sw_get_window_by_id(unsigned long id)
274    {
275            seamless_window *sw;
276            for (sw = g_seamless_windows; sw; sw = sw->next)
277            {
278                    if (sw->id == id)
279                            return sw;
280            }
281            return NULL;
282    }
283    
284    
285    static seamless_window *
286    sw_get_window_by_wnd(Window wnd)
287    {
288            seamless_window *sw;
289            for (sw = g_seamless_windows; sw; sw = sw->next)
290            {
291                    if (sw->wnd == wnd)
292                            return sw;
293            }
294            return NULL;
295    }
296    
297    
298    static void
299    sw_remove_window(seamless_window * win)
300    {
301            seamless_window *sw, **prevnext = &g_seamless_windows;
302            for (sw = g_seamless_windows; sw; sw = sw->next)
303            {
304                    if (sw == win)
305                    {
306                            *prevnext = sw->next;
307                            xfree(sw);
308                            return;
309                    }
310                    prevnext = &sw->next;
311            }
312            return;
313    }
314    
315    
316    /* Move all windows except wnd to new desktop */
317  static void  static void
318  mwm_hide_decorations(void)  sw_all_to_desktop(Window wnd, unsigned int desktop)
319    {
320            seamless_window *sw;
321            for (sw = g_seamless_windows; sw; sw = sw->next)
322            {
323                    if (sw->wnd == wnd)
324                            continue;
325                    if (sw->desktop != desktop)
326                    {
327                            ewmh_move_to_desktop(sw->wnd, desktop);
328                            sw->desktop = desktop;
329                    }
330            }
331    }
332    
333    
334    /* Send our position */
335    static void
336    sw_update_position(seamless_window * sw)
337    {
338            XWindowAttributes wa;
339            int x, y;
340            Window child_return;
341            unsigned int serial;
342    
343            XGetWindowAttributes(g_display, sw->wnd, &wa);
344            XTranslateCoordinates(g_display, sw->wnd, wa.root,
345                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
346    
347            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
348    
349            sw->outstanding_position = True;
350            sw->outpos_serial = serial;
351    
352            sw->outpos_xoffset = x;
353            sw->outpos_yoffset = y;
354            sw->outpos_width = wa.width;
355            sw->outpos_height = wa.height;
356    }
357    
358    
359    /* Check if it's time to send our position */
360    static void
361    sw_check_timers()
362    {
363            seamless_window *sw;
364            struct timeval now;
365    
366            gettimeofday(&now, NULL);
367            for (sw = g_seamless_windows; sw; sw = sw->next)
368            {
369                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
370                    {
371                            timerclear(sw->position_timer);
372                            sw_update_position(sw);
373                    }
374            }
375    }
376    
377    
378    static void
379    sw_restack_window(seamless_window * sw, unsigned long behind)
380    {
381            seamless_window *sw_above;
382    
383            /* Remove window from stack */
384            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
385            {
386                    if (sw_above->behind == sw->id)
387                            break;
388            }
389    
390            if (sw_above)
391                    sw_above->behind = sw->behind;
392    
393            /* And then add it at the new position */
394    
395            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
396            {
397                    if (sw_above->behind == behind)
398                            break;
399            }
400    
401            if (sw_above)
402                    sw_above->behind = sw->id;
403    
404            sw->behind = behind;
405    }
406    
407    
408    static void
409    sw_handle_restack(seamless_window * sw)
410    {
411            Status status;
412            Window root, parent, *children;
413            unsigned int nchildren, i;
414            seamless_window *sw_below;
415    
416            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
417                                &root, &parent, &children, &nchildren);
418            if (!status || !nchildren)
419                    return;
420    
421            sw_below = NULL;
422    
423            i = 0;
424            while (children[i] != sw->wnd)
425            {
426                    i++;
427                    if (i >= nchildren)
428                            return;
429            }
430    
431            for (i++; i < nchildren; i++)
432            {
433                    sw_below = sw_get_window_by_wnd(children[i]);
434                    if (sw_below)
435                            break;
436            }
437    
438            if (!sw_below && !sw->behind)
439                    return;
440            if (sw_below && (sw_below->id == sw->behind))
441                    return;
442    
443            if (sw_below)
444            {
445                    seamless_send_zchange(sw->id, sw_below->id, 0);
446                    sw_restack_window(sw, sw_below->id);
447            }
448            else
449            {
450                    seamless_send_zchange(sw->id, 0, 0);
451                    sw_restack_window(sw, 0);
452            }
453    }
454    
455    
456    static void
457    mwm_hide_decorations(Window wnd)
458  {  {
459          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
460          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 471  mwm_hide_decorations(void)
471                  return;                  return;
472          }          }
473    
474          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
475                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
476    
477  }  }
478    
479  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 507  mwm_hide_decorations(void)
507  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
508                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
509    
510    /* The following macros output the same octet sequences
511       on both BE and LE hosts: */
512    
513  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
514  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
515  #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 521  static uint32
521  translate_colour(uint32 colour)  translate_colour(uint32 colour)
522  {  {
523          PixelColour pc;          PixelColour pc;
524          switch (g_server_bpp)          switch (g_server_depth)
525          {          {
526                  case 15:                  case 15:
527                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 251  translate_colour(uint32 colour) Line 532  translate_colour(uint32 colour)
532                  case 24:                  case 24:
533                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
534                          break;                          break;
535                    default:
536                            /* Avoid warning */
537                            pc.red = 0;
538                            pc.green = 0;
539                            pc.blue = 0;
540                            break;
541          }          }
542          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
543  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 589  translate8to16(const uint8 * data, uint8
589  {  {
590          uint16 value;          uint16 value;
591    
592          if (g_arch_match)          if (g_compatible_arch)
593          {          {
594                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
595                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 623  translate8to24(const uint8 * data, uint8
623  {  {
624          uint32 value;          uint32 value;
625    
626          if (g_xserver_be)          if (g_compatible_arch)
627          {          {
628                  while (out < end)                  while (out < end)
629                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 646  translate8to32(const uint8 * data, uint8
646  {  {
647          uint32 value;          uint32 value;
648    
649          if (g_arch_match)          if (g_compatible_arch)
650          {          {
651                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
652                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 718  translate15to24(const uint16 * data, uin
718          uint16 pixel;          uint16 pixel;
719          PixelColour pc;          PixelColour pc;
720    
721          if (g_arch_match)          if (g_compatible_arch)
722          {          {
723                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
724                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 768  translate15to32(const uint16 * data, uin
768          uint32 value;          uint32 value;
769          PixelColour pc;          PixelColour pc;
770    
771          if (g_arch_match)          if (g_compatible_arch)
772          {          {
773                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
774                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 876  translate16to24(const uint16 * data, uin
876          uint16 pixel;          uint16 pixel;
877          PixelColour pc;          PixelColour pc;
878    
879          if (g_arch_match)          if (g_compatible_arch)
880          {          {
881                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
882                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 946  translate16to32(const uint16 * data, uin
946          uint32 value;          uint32 value;
947          PixelColour pc;          PixelColour pc;
948    
949          if (g_arch_match)          if (g_compatible_arch)
950          {          {
951                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
952                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 1075  translate24to32(const uint8 * data, uint
1075          uint32 value;          uint32 value;
1076          PixelColour pc;          PixelColour pc;
1077    
1078          if (g_arch_match)          if (g_compatible_arch)
1079          {          {
1080                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1081  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 1089  translate24to32(const uint8 * data, uint
1089  #else  #else
1090                  REPEAT4                  REPEAT4
1091                  (                  (
1092                   /* Only read 3 bytes. Reading 4 bytes means reading beyound buffer. */                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1093                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1094                   out += 4;                   out += 4;
1095                   data += 3;                   data += 3;
# Line 843  translate_image(int width, int height, u Line 1130  translate_image(int width, int height, u
1130          uint8 *out;          uint8 *out;
1131          uint8 *end;          uint8 *end;
1132    
1133          /* if server and xserver bpp match, */          /*
1134          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1135          /* just return data */             and arch(endian) matches, no need to translate:
1136          if (g_arch_match)             just return data.
1137               Note: select_visual should've already ensured g_no_translate
1138               is only set for compatible depths, but the RDP depth might've
1139               changed during connection negotiations.
1140             */
1141            if (g_no_translate_image)
1142          {          {
1143                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1144                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1145                  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)  
1146                          return data;                          return data;
1147          }          }
1148    
# Line 860  translate_image(int width, int height, u Line 1150  translate_image(int width, int height, u
1150          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1151          end = out + size;          end = out + size;
1152    
1153          switch (g_server_bpp)          switch (g_server_depth)
1154          {          {
1155                  case 24:                  case 24:
1156                          switch (g_bpp)                          switch (g_bpp)
# Line 958  calculate_shifts(uint32 mask, int *shift Line 1248  calculate_shifts(uint32 mask, int *shift
1248          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1249  }  }
1250    
1251  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1252  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1253     */
1254    static unsigned
1255    calculate_mask_weight(uint32 mask)
1256    {
1257            unsigned weight = 0;
1258            do
1259            {
1260                    weight += (mask & 1);
1261            }
1262            while (mask >>= 1);
1263            return weight;
1264    }
1265    
1266    static BOOL
1267    select_visual()
1268  {  {
         XVisualInfo vi;  
1269          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1270          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1271          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1272          XVisualInfo template;          XVisualInfo template;
1273          Bool TrueColorVisual = False;          int i;
1274            unsigned red_weight, blue_weight, green_weight;
1275    
1276          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1277          if (g_display == NULL)  
1278            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1279            if (pfm == NULL)
1280          {          {
1281                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1282                    XCloseDisplay(g_display);
1283                  return False;                  return False;
1284          }          }
1285    
1286          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 */  
1287          template.class = TrueColor;          template.class = TrueColor;
1288          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1289            g_visual = NULL;
1290            g_no_translate_image = False;
1291            g_compatible_arch = False;
1292            if (vmatches != NULL)
1293            {
1294                    for (i = 0; i < visuals_count; ++i)
1295                    {
1296                            XVisualInfo *visual_info = &vmatches[i];
1297    
1298                            /* Try to find a no-translation visual that'll
1299                               allow us to use RDP bitmaps directly as ZPixmaps. */
1300                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1301                                                   /* R5G5B5 */
1302                                                   (visual_info->red_mask == 0x7c00) &&
1303                                                   (visual_info->green_mask == 0x3e0) &&
1304                                                   (visual_info->blue_mask == 0x1f)) ||
1305                                                  ((visual_info->depth == 16) &&
1306                                                   /* R5G6B5 */
1307                                                   (visual_info->red_mask == 0xf800) &&
1308                                                   (visual_info->green_mask == 0x7e0) &&
1309                                                   (visual_info->blue_mask == 0x1f)) ||
1310                                                  ((visual_info->depth == 24) &&
1311                                                   /* R8G8B8 */
1312                                                   (visual_info->red_mask == 0xff0000) &&
1313                                                   (visual_info->green_mask == 0xff00) &&
1314                                                   (visual_info->blue_mask == 0xff))))
1315                            {
1316                                    g_visual = visual_info->visual;
1317                                    g_depth = visual_info->depth;
1318                                    g_compatible_arch = !g_host_be;
1319                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1320                                    if (g_no_translate_image)
1321                                            /* We found the best visual */
1322                                            break;
1323                            }
1324                            else
1325                            {
1326                                    g_compatible_arch = False;
1327                            }
1328    
1329                            if (visual_info->depth > 24)
1330                            {
1331                                    /* Avoid 32-bit visuals and likes like the plague.
1332                                       They're either untested or proven to work bad
1333                                       (e.g. nvidia's Composite 32-bit visual).
1334                                       Most implementation offer a 24-bit visual anyway. */
1335                                    continue;
1336                            }
1337    
1338          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1339          while (nvisuals >= 0)                             we have a translateXtoY function. */
1340          {                          BOOL can_translate_to_bpp = False;
1341                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1342                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1343                          g_depth = (vmatches + nvisuals)->depth;                          {
1344                                    if (pfm[j].depth == visual_info->depth)
1345                                    {
1346                                            if ((pfm[j].bits_per_pixel == 16) ||
1347                                                (pfm[j].bits_per_pixel == 24) ||
1348                                                (pfm[j].bits_per_pixel == 32))
1349                                            {
1350                                                    can_translate_to_bpp = True;
1351                                            }
1352                                            break;
1353                                    }
1354                            }
1355    
1356                            /* Prefer formats which have the most colour depth.
1357                               We're being truly aristocratic here, minding each
1358                               weight on its own. */
1359                            if (can_translate_to_bpp)
1360                            {
1361                                    unsigned vis_red_weight =
1362                                            calculate_mask_weight(visual_info->red_mask);
1363                                    unsigned vis_green_weight =
1364                                            calculate_mask_weight(visual_info->green_mask);
1365                                    unsigned vis_blue_weight =
1366                                            calculate_mask_weight(visual_info->blue_mask);
1367                                    if ((vis_red_weight >= red_weight)
1368                                        && (vis_green_weight >= green_weight)
1369                                        && (vis_blue_weight >= blue_weight))
1370                                    {
1371                                            red_weight = vis_red_weight;
1372                                            green_weight = vis_green_weight;
1373                                            blue_weight = vis_blue_weight;
1374                                            g_visual = visual_info->visual;
1375                                            g_depth = visual_info->depth;
1376                                    }
1377                            }
1378                  }                  }
1379                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1380          }          }
1381    
1382          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)))  
1383          {          {
1384                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1385                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1386                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1387                    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;  
                 }  
1388          }          }
1389          else          else
1390          {          {
1391                  /* need a truecolour visual */                  template.class = PseudoColor;
1392                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1393                  {                  template.colormap_size = 256;
1394                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1395                            XGetVisualInfo(g_display,
1396                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1397                                           &template, &visuals_count);
1398                    if (vmatches == NULL)
1399                    {
1400                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1401                            XCloseDisplay(g_display);
1402                            XFree(pfm);
1403                          return False;                          return False;
1404                  }                  }
1405    
1406                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1407                  g_owncolmap = False;                  g_owncolmap = True;
1408                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1409                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1410                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1411    
1412                  /* if RGB video and everything is little endian */          g_bpp = 0;
1413                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1414                      !g_xserver_be && !g_host_be)          {
1415                    XPixmapFormatValues *pf = &pfm[i];
1416                    if (pf->depth == g_depth)
1417                  {                  {
1418                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1419                                                g_blue_shift_l == 0))  
1420                            if (g_no_translate_image)
1421                          {                          {
1422                                  g_arch_match = True;                                  switch (g_server_depth)
1423                                    {
1424                                            case 15:
1425                                            case 16:
1426                                                    if (g_bpp != 16)
1427                                                            g_no_translate_image = False;
1428                                                    break;
1429                                            case 24:
1430                                                    /* Yes, this will force image translation
1431                                                       on most modern servers which use 32 bits
1432                                                       for R8G8B8. */
1433                                                    if (g_bpp != 24)
1434                                                            g_no_translate_image = False;
1435                                                    break;
1436                                            default:
1437                                                    g_no_translate_image = False;
1438                                                    break;
1439                                    }
1440                          }                          }
                 }  
1441    
1442                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1443                  {                             there's just a single entry for every depth,
1444                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1445                            break;
1446                  }                  }
1447          }          }
1448            XFree(pfm);
1449            pfm = NULL;
1450            return True;
1451    }
1452    
1453          pfm = XListPixmapFormats(g_display, &i);  BOOL
1454          if (pfm != NULL)  ui_init(void)
1455    {
1456            int screen_num;
1457    
1458            g_display = XOpenDisplay(NULL);
1459            if (g_display == NULL)
1460          {          {
1461                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1462                     desirable, e.g. 24 bits->32 bits. */                  return False;
                 while (i--)  
                 {  
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1463          }          }
1464    
         if (g_bpp < 8)  
1465          {          {
1466                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1467                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1468            }
1469    
1470            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1471            screen_num = DefaultScreen(g_display);
1472            g_x_socket = ConnectionNumber(g_display);
1473            g_screen = ScreenOfDisplay(g_display, screen_num);
1474            g_depth = DefaultDepthOfScreen(g_screen);
1475    
1476            if (!select_visual())
1477                  return False;                  return False;
1478    
1479            if (g_no_translate_image)
1480            {
1481                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1482          }          }
1483    
1484            if (g_server_depth > g_bpp)
1485            {
1486                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1487                            g_server_depth, g_bpp);
1488            }
1489    
1490            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1491                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1492    
1493          if (!g_owncolmap)          if (!g_owncolmap)
1494          {          {
1495                  g_xcolmap =                  g_xcolmap =
1496                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1497                                          AllocNone);                                          AllocNone);
1498                  if (g_depth <= 8)                  if (g_depth <= 8)
1499                          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);
1500          }          }
1501    
1502          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1503          {          {
1504                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1505                  g_ownbackstore = True;                  g_ownbackstore = True;
1506          }          }
1507    
# Line 1088  ui_init(void) Line 1512  ui_init(void)
1512          {          {
1513                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1514                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1515                    g_using_full_workarea = True;
1516          }          }
1517          else if (g_width < 0)          else if (g_width < 0)
1518          {          {
# Line 1101  ui_init(void) Line 1526  ui_init(void)
1526          {          {
1527                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1528                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
                 g_using_full_workarea = True;  
   
1529                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1530                  {                  {
1531                          g_width = cx;                          g_width = cx;
1532                          g_height = cy;                          g_height = cy;
1533                            g_using_full_workarea = True;
1534                  }                  }
1535                  else                  else
1536                  {                  {
1537                          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");
1538                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1539                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1540                  }                  }
1541          }          }
1542    
# Line 1127  ui_init(void) Line 1551  ui_init(void)
1551                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1552    
1553          xclip_init();          xclip_init();
1554            ewmh_init();
1555            if (g_seamless_rdp)
1556                    seamless_init();
1557    
1558          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));
1559    
1560          return True;          return True;
1561  }  }
# Line 1152  ui_deinit(void) Line 1579  ui_deinit(void)
1579          g_display = NULL;          g_display = NULL;
1580  }  }
1581    
1582    
1583    static void
1584    get_window_attribs(XSetWindowAttributes * attribs)
1585    {
1586            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1587            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1588            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1589            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1590            attribs->override_redirect = g_fullscreen;
1591            attribs->colormap = g_xcolmap;
1592    }
1593    
1594    static void
1595    get_input_mask(long *input_mask)
1596    {
1597            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1598                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1599    
1600            if (g_sendmotion)
1601                    *input_mask |= PointerMotionMask;
1602            if (g_ownbackstore)
1603                    *input_mask |= ExposureMask;
1604            if (g_fullscreen || g_grab_keyboard)
1605                    *input_mask |= EnterWindowMask;
1606            if (g_grab_keyboard)
1607                    *input_mask |= LeaveWindowMask;
1608    }
1609    
1610  BOOL  BOOL
1611  ui_create_window(void)  ui_create_window(void)
1612  {  {
# Line 1174  ui_create_window(void) Line 1629  ui_create_window(void)
1629          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1630                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1631    
1632          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;  
1633    
1634          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,
1635                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1186  ui_create_window(void) Line 1637  ui_create_window(void)
1637                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1638    
1639          if (g_gc == NULL)          if (g_gc == NULL)
1640            {
1641                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1642                    ui_reset_clip();
1643            }
1644    
1645          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1646                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1203  ui_create_window(void) Line 1657  ui_create_window(void)
1657          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1658    
1659          if (g_hide_decorations)          if (g_hide_decorations)
1660                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1661    
1662          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1663          if (classhints != NULL)          if (classhints != NULL)
# Line 1230  ui_create_window(void) Line 1684  ui_create_window(void)
1684                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1685          }          }
1686    
1687          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;  
1688    
1689          if (g_IM != NULL)          if (g_IM != NULL)
1690          {          {
# Line 1253  ui_create_window(void) Line 1697  ui_create_window(void)
1697          }          }
1698    
1699          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1700    
1701            XMapWindow(g_display, g_wnd);
1702          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1703          do          do
1704          {          {
# Line 1325  xwin_toggle_fullscreen(void) Line 1769  xwin_toggle_fullscreen(void)
1769  {  {
1770          Pixmap contents = 0;          Pixmap contents = 0;
1771    
1772            if (g_seamless_active)
1773                    /* Turn off SeamlessRDP mode */
1774                    ui_seamless_toggle();
1775    
1776          if (!g_ownbackstore)          if (!g_ownbackstore)
1777          {          {
1778                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1413  handle_button_event(XEvent xevent, BOOL Line 1861  handle_button_event(XEvent xevent, BOOL
1861                  }                  }
1862          }          }
1863    
1864          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
1865                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
1866                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1867                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1868            }
1869            else
1870            {
1871                    /* SeamlessRDP */
1872                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1873                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1874            }
1875  }  }
1876    
1877    
1878  /* Process events in Xlib queue  /* Process events in Xlib queue
1879     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1880  static int  static int
# Line 1428  xwin_process_events(void) Line 1886  xwin_process_events(void)
1886          char str[256];          char str[256];
1887          Status status;          Status status;
1888          int events = 0;          int events = 0;
1889            seamless_window *sw;
1890    
1891          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1892          {          {
# Line 1442  xwin_process_events(void) Line 1901  xwin_process_events(void)
1901                  switch (xevent.type)                  switch (xevent.type)
1902                  {                  {
1903                          case VisibilityNotify:                          case VisibilityNotify:
1904                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1905                                            g_Unobscured =
1906                                                    xevent.xvisibility.state == VisibilityUnobscured;
1907    
1908                                  break;                                  break;
1909                          case ClientMessage:                          case ClientMessage:
1910                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1522  xwin_process_events(void) Line 1984  xwin_process_events(void)
1984                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1985                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1986                                                         CurrentTime);                                                         CurrentTime);
1987                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1988                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1989                                    {
1990                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1991                                                           xevent.xmotion.x, xevent.xmotion.y);
1992                                    }
1993                                    else
1994                                    {
1995                                            /* SeamlessRDP */
1996                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1997                                                           xevent.xmotion.x_root,
1998                                                           xevent.xmotion.y_root);
1999                                    }
2000                                  break;                                  break;
2001    
2002                          case FocusIn:                          case FocusIn:
# Line 1534  xwin_process_events(void) Line 2007  xwin_process_events(void)
2007                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2008                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2009                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2010    
2011                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2012                                    if (!sw)
2013                                            break;
2014    
2015                                    if (sw->id != g_seamless_focused)
2016                                    {
2017                                            seamless_send_focus(sw->id, 0);
2018                                            g_seamless_focused = sw->id;
2019                                    }
2020                                  break;                                  break;
2021    
2022                          case FocusOut:                          case FocusOut:
# Line 1566  xwin_process_events(void) Line 2049  xwin_process_events(void)
2049                                  break;                                  break;
2050    
2051                          case Expose:                          case Expose:
2052                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2053                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2054                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2055                                            xevent.xexpose.height,                                                    g_gc,
2056                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2057                                                      xevent.xexpose.width, xevent.xexpose.height,
2058                                                      xevent.xexpose.x, xevent.xexpose.y);
2059                                    }
2060                                    else
2061                                    {
2062                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2063                                            if (sw)
2064                                                    XCopyArea(g_display, g_backstore,
2065                                                              xevent.xexpose.window, g_gc,
2066                                                              xevent.xexpose.x + sw->xoffset,
2067                                                              xevent.xexpose.y + sw->yoffset,
2068                                                              xevent.xexpose.width,
2069                                                              xevent.xexpose.height, xevent.xexpose.x,
2070                                                              xevent.xexpose.y);
2071                                            else
2072                                            {
2073                                                    error("Expose for unknown window 0x%lx\n",
2074                                                          xevent.xexpose.window);
2075                                            }
2076                                    }
2077    
2078                                  break;                                  break;
2079    
2080                          case MappingNotify:                          case MappingNotify:
# Line 1599  xwin_process_events(void) Line 2103  xwin_process_events(void)
2103                                  break;                                  break;
2104                          case PropertyNotify:                          case PropertyNotify:
2105                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2106                                    if (xevent.xproperty.window == g_wnd)
2107                                            break;
2108                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2109                                            break;
2110    
2111                                    /* seamless */
2112                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2113                                    if (!sw)
2114                                            break;
2115    
2116                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2117                                        && (xevent.xproperty.state == PropertyNewValue))
2118                                    {
2119                                            sw->state = ewmh_get_window_state(sw->wnd);
2120                                            seamless_send_state(sw->id, sw->state, 0);
2121                                    }
2122    
2123                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2124                                        && (xevent.xproperty.state == PropertyNewValue))
2125                                    {
2126                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2127                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2128                                    }
2129    
2130                                  break;                                  break;
2131                          case MapNotify:                          case MapNotify:
2132                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2133                                            rdp_send_client_window_status(1);
2134                                  break;                                  break;
2135                          case UnmapNotify:                          case UnmapNotify:
2136                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2137                                            rdp_send_client_window_status(0);
2138                                    break;
2139                            case ConfigureNotify:
2140                                    if (!g_seamless_active)
2141                                            break;
2142    
2143                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2144                                    if (!sw)
2145                                    {
2146                                            error("ConfigureNotify for unknown window 0x%lx\n",
2147                                                  xevent.xconfigure.window);
2148                                    }
2149    
2150                                    gettimeofday(sw->position_timer, NULL);
2151                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2152                                        1000000)
2153                                    {
2154                                            sw->position_timer->tv_usec +=
2155                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2156                                            sw->position_timer->tv_sec += 1;
2157                                    }
2158                                    else
2159                                    {
2160                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2161                                    }
2162    
2163                                    sw_handle_restack(sw);
2164                                  break;                                  break;
2165                  }                  }
2166          }          }
# Line 1629  ui_select(int rdp_socket) Line 2185  ui_select(int rdp_socket)
2185                          /* User quit */                          /* User quit */
2186                          return 0;                          return 0;
2187    
2188                    if (g_seamless_active)
2189                            sw_check_timers();
2190    
2191                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2192                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2193                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1648  ui_select(int rdp_socket) Line 2207  ui_select(int rdp_socket)
2207    
2208                  /* add redirection handles */                  /* add redirection handles */
2209                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2210                    seamless_select_timeout(&tv);
2211    
2212                  n++;                  n++;
2213    
# Line 1689  ui_create_bitmap(int width, int height, Line 2249  ui_create_bitmap(int width, int height,
2249          uint8 *tdata;          uint8 *tdata;
2250          int bitmap_pad;          int bitmap_pad;
2251    
2252          if (g_server_bpp == 8)          if (g_server_depth == 8)
2253          {          {
2254                  bitmap_pad = 8;                  bitmap_pad = 8;
2255          }          }
# Line 1721  ui_paint_bitmap(int x, int y, int cx, in Line 2281  ui_paint_bitmap(int x, int y, int cx, in
2281          uint8 *tdata;          uint8 *tdata;
2282          int bitmap_pad;          int bitmap_pad;
2283    
2284          if (g_server_bpp == 8)          if (g_server_depth == 8)
2285          {          {
2286                  bitmap_pad = 8;                  bitmap_pad = 8;
2287          }          }
# Line 1741  ui_paint_bitmap(int x, int y, int cx, in Line 2301  ui_paint_bitmap(int x, int y, int cx, in
2301          {          {
2302                  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);
2303                  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);
2304                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2305                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2306                                             x - sw->xoffset, y - sw->yoffset));
2307          }          }
2308          else          else
2309          {          {
2310                  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);
2311                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2312                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2313                                             x - sw->xoffset, y - sw->yoffset));
2314          }          }
2315    
2316          XFree(image);          XFree(image);
# Line 1865  ui_set_cursor(HCURSOR cursor) Line 2431  ui_set_cursor(HCURSOR cursor)
2431  {  {
2432          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2433          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2434            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2435  }  }
2436    
2437  void  void
# Line 2006  ui_set_colourmap(HCOLOURMAP map) Line 2573  ui_set_colourmap(HCOLOURMAP map)
2573                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2574          }          }
2575          else          else
2576            {
2577                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2578                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2579            }
2580  }  }
2581    
2582  void  void
2583  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2584  {  {
2585          XRectangle rect;          g_clip_rectangle.x = x;
2586            g_clip_rectangle.y = y;
2587          rect.x = x;          g_clip_rectangle.width = cx;
2588          rect.y = y;          g_clip_rectangle.height = cy;
2589          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);  
2590  }  }
2591    
2592  void  void
2593  ui_reset_clip(void)  ui_reset_clip(void)
2594  {  {
2595          XRectangle rect;          g_clip_rectangle.x = 0;
2596            g_clip_rectangle.y = 0;
2597          rect.x = 0;          g_clip_rectangle.width = g_width;
2598          rect.y = 0;          g_clip_rectangle.height = g_height;
2599          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);  
2600  }  }
2601    
2602  void  void
# Line 2111  ui_patblt(uint8 opcode, Line 2677  ui_patblt(uint8 opcode,
2677    
2678          if (g_ownbackstore)          if (g_ownbackstore)
2679                  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);
2680            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2681                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2682                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2683  }  }
2684    
2685  void  void
# Line 2121  ui_screenblt(uint8 opcode, Line 2690  ui_screenblt(uint8 opcode,
2690          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2691          if (g_ownbackstore)          if (g_ownbackstore)
2692          {          {
2693                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2694                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2695                          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);  
                 }  
2696          }          }
2697          else          else
2698          {          {
2699                  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);
2700          }          }
2701    
2702            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2703                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2704                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2705    
2706          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2707  }  }
2708    
# Line 2148  ui_memblt(uint8 opcode, Line 2713  ui_memblt(uint8 opcode,
2713  {  {
2714          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2715          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);
2716            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2717                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2718                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2719          if (g_ownbackstore)          if (g_ownbackstore)
2720                  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);
2721          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2194  ui_line(uint8 opcode, Line 2762  ui_line(uint8 opcode,
2762          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2763          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2764          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2765            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2766                                                startx - sw->xoffset, starty - sw->yoffset,
2767                                                endx - sw->xoffset, endy - sw->yoffset));
2768          if (g_ownbackstore)          if (g_ownbackstore)
2769                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2770          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2291  ui_polyline(uint8 opcode, Line 2862  ui_polyline(uint8 opcode,
2862          if (g_ownbackstore)          if (g_ownbackstore)
2863                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2864                             CoordModePrevious);                             CoordModePrevious);
2865    
2866            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2867                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2868    
2869          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2870  }  }
2871    
# Line 2511  ui_draw_text(uint8 font, uint8 flags, ui Line 3086  ui_draw_text(uint8 font, uint8 flags, ui
3086          if (g_ownbackstore)          if (g_ownbackstore)
3087          {          {
3088                  if (boxcx > 1)                  if (boxcx > 1)
3089                    {
3090                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3091                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3092                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3093                                                    (g_display, g_backstore, sw->wnd, g_gc,
3094                                                     boxx, boxy,
3095                                                     boxcx, boxcy,
3096                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3097                    }
3098                  else                  else
3099                    {
3100                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3101                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3102                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3103                                                    (g_display, g_backstore, sw->wnd, g_gc,
3104                                                     clipx, clipy,
3105                                                     clipcx, clipcy, clipx - sw->xoffset,
3106                                                     clipy - sw->yoffset));
3107                    }
3108          }          }
3109  }  }
3110    
# Line 2561  ui_desktop_restore(uint32 offset, int x, Line 3150  ui_desktop_restore(uint32 offset, int x,
3150          {          {
3151                  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);
3152                  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);
3153                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3154                                            (g_display, g_backstore, sw->wnd, g_gc,
3155                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3156          }          }
3157          else          else
3158          {          {
3159                  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);
3160                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3161                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3162                                             x - sw->xoffset, y - sw->yoffset));
3163          }          }
3164    
3165          XFree(image);          XFree(image);
# Line 2580  void Line 3175  void
3175  ui_end_update(void)  ui_end_update(void)
3176  {  {
3177  }  }
3178    
3179    
3180    void
3181    ui_seamless_begin()
3182    {
3183            if (!g_seamless_rdp)
3184                    return;
3185    
3186            if (g_seamless_started)
3187                    return;
3188    
3189            g_seamless_started = True;
3190            ui_seamless_toggle();
3191    }
3192    
3193    
3194    void
3195    ui_seamless_toggle()
3196    {
3197            if (!g_seamless_rdp)
3198                    return;
3199    
3200            if (!g_seamless_started)
3201                    return;
3202    
3203            if (g_seamless_active)
3204            {
3205                    /* Deactivate */
3206                    while (g_seamless_windows)
3207                    {
3208                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3209                            sw_remove_window(g_seamless_windows);
3210                    }
3211                    XMapWindow(g_display, g_wnd);
3212            }
3213            else
3214            {
3215                    /* Activate */
3216                    XUnmapWindow(g_display, g_wnd);
3217                    seamless_send_sync();
3218            }
3219    
3220            g_seamless_active = !g_seamless_active;
3221    }
3222    
3223    
3224    void
3225    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3226    {
3227            Window wnd;
3228            XSetWindowAttributes attribs;
3229            XClassHint *classhints;
3230            XSizeHints *sizehints;
3231            long input_mask;
3232            seamless_window *sw, *sw_parent;
3233    
3234            if (!g_seamless_active)
3235                    return;
3236    
3237            /* Ignore CREATEs for existing windows */
3238            sw = sw_get_window_by_id(id);
3239            if (sw)
3240                    return;
3241    
3242            get_window_attribs(&attribs);
3243            attribs.override_redirect = False;
3244    
3245            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3246                                InputOutput, g_visual,
3247                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3248                                CWBorderPixel, &attribs);
3249    
3250            XStoreName(g_display, wnd, "SeamlessRDP");
3251            ewmh_set_wm_name(wnd, "SeamlessRDP");
3252    
3253            mwm_hide_decorations(wnd);
3254    
3255            classhints = XAllocClassHint();
3256            if (classhints != NULL)
3257            {
3258                    classhints->res_name = "rdesktop";
3259                    classhints->res_class = "SeamlessRDP";
3260                    XSetClassHint(g_display, wnd, classhints);
3261                    XFree(classhints);
3262            }
3263    
3264            /* WM_NORMAL_HINTS */
3265            sizehints = XAllocSizeHints();
3266            if (sizehints != NULL)
3267            {
3268                    sizehints->flags = USPosition;
3269                    XSetWMNormalHints(g_display, wnd, sizehints);
3270                    XFree(sizehints);
3271            }
3272    
3273            /* Handle popups without parents through some ewm hints */
3274            if (parent == 0xFFFFFFFF)
3275                    ewmh_set_window_popup(wnd);
3276            /* Set WM_TRANSIENT_FOR, if necessary */
3277            else if (parent != 0x00000000)
3278            {
3279                    sw_parent = sw_get_window_by_id(parent);
3280                    if (sw_parent)
3281                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3282                    else
3283                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3284            }
3285    
3286    
3287            /* FIXME: Support for Input Context:s */
3288    
3289            get_input_mask(&input_mask);
3290            input_mask |= PropertyChangeMask;
3291    
3292            XSelectInput(g_display, wnd, input_mask);
3293    
3294            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3295               seamless window, we could try to close the window on the
3296               serverside, instead of terminating rdesktop */
3297            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3298    
3299            sw = xmalloc(sizeof(seamless_window));
3300            sw->wnd = wnd;
3301            sw->id = id;
3302            sw->behind = 0;
3303            sw->xoffset = 0;
3304            sw->yoffset = 0;
3305            sw->width = 0;
3306            sw->height = 0;
3307            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3308            sw->desktop = 0;
3309            sw->position_timer = xmalloc(sizeof(struct timeval));
3310            timerclear(sw->position_timer);
3311            sw->outstanding_position = False;
3312            sw->next = g_seamless_windows;
3313            g_seamless_windows = sw;
3314    }
3315    
3316    
3317    void
3318    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3319    {
3320            seamless_window *sw;
3321    
3322            if (!g_seamless_active)
3323                    return;
3324    
3325            sw = sw_get_window_by_id(id);
3326            if (!sw)
3327            {
3328                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3329                    return;
3330            }
3331    
3332            XDestroyWindow(g_display, sw->wnd);
3333            sw_remove_window(sw);
3334    }
3335    
3336    
3337    void
3338    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3339    {
3340            seamless_window *sw;
3341    
3342            if (!g_seamless_active)
3343                    return;
3344    
3345            sw = sw_get_window_by_id(id);
3346            if (!sw)
3347            {
3348                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3349                    return;
3350            }
3351    
3352            /* We ignore server updates until it has handled our request. */
3353            if (sw->outstanding_position)
3354                    return;
3355    
3356            if (!width || !height)
3357                    /* X11 windows must be at least 1x1 */
3358                    return;
3359    
3360            sw->xoffset = x;
3361            sw->yoffset = y;
3362            sw->width = width;
3363            sw->height = height;
3364    
3365            /* If we move the window in a maximized state, then KDE won't
3366               accept restoration */
3367            switch (sw->state)
3368            {
3369                    case SEAMLESSRDP_MINIMIZED:
3370                    case SEAMLESSRDP_MAXIMIZED:
3371                            return;
3372            }
3373    
3374            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3375            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3376    }
3377    
3378    
3379    void
3380    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3381    {
3382            seamless_window *sw;
3383    
3384            if (!g_seamless_active)
3385                    return;
3386    
3387            sw = sw_get_window_by_id(id);
3388            if (!sw)
3389            {
3390                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3391                    return;
3392            }
3393    
3394            if (behind)
3395            {
3396                    seamless_window *sw_behind;
3397                    Window wnds[2];
3398    
3399                    sw_behind = sw_get_window_by_id(behind);
3400                    if (!sw_behind)
3401                    {
3402                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3403                                    behind);
3404                            return;
3405                    }
3406    
3407                    wnds[1] = sw_behind->wnd;
3408                    wnds[0] = sw->wnd;
3409    
3410                    XRestackWindows(g_display, wnds, 2);
3411            }
3412            else
3413            {
3414                    XRaiseWindow(g_display, sw->wnd);
3415            }
3416    
3417            sw_restack_window(sw, behind);
3418    }
3419    
3420    
3421    void
3422    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3423    {
3424            seamless_window *sw;
3425    
3426            if (!g_seamless_active)
3427                    return;
3428    
3429            sw = sw_get_window_by_id(id);
3430            if (!sw)
3431            {
3432                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3433                    return;
3434            }
3435    
3436            /* FIXME: Might want to convert the name for non-EWMH WMs */
3437            XStoreName(g_display, sw->wnd, title);
3438            ewmh_set_wm_name(sw->wnd, title);
3439    }
3440    
3441    
3442    void
3443    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3444    {
3445            seamless_window *sw;
3446    
3447            if (!g_seamless_active)
3448                    return;
3449    
3450            sw = sw_get_window_by_id(id);
3451            if (!sw)
3452            {
3453                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3454                    return;
3455            }
3456    
3457            switch (state)
3458            {
3459                    case SEAMLESSRDP_NORMAL:
3460                    case SEAMLESSRDP_MAXIMIZED:
3461                            ewmh_change_state(sw->wnd, state);
3462                            XMapWindow(g_display, sw->wnd);
3463                            break;
3464                    case SEAMLESSRDP_MINIMIZED:
3465                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3466                               the Window Manager should probably just ignore the request, since
3467                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3468                               such as minimization, rather than an independent state." Besides,
3469                               XIconifyWindow is easier. */
3470                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3471                            {
3472                                    XWMHints *hints;
3473                                    hints = XAllocWMHints();
3474                                    hints->flags = StateHint;
3475                                    hints->initial_state = IconicState;
3476                                    XSetWMHints(g_display, sw->wnd, hints);
3477                                    XFree(hints);
3478                                    XMapWindow(g_display, sw->wnd);
3479                            }
3480                            else
3481                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3482                            break;
3483                    default:
3484                            warning("SeamlessRDP: Invalid state %d\n", state);
3485                            break;
3486            }
3487    
3488            sw->state = state;
3489    }
3490    
3491    
3492    void
3493    ui_seamless_syncbegin(unsigned long flags)
3494    {
3495            if (!g_seamless_active)
3496                    return;
3497    
3498            /* Destroy all seamless windows */
3499            while (g_seamless_windows)
3500            {
3501                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3502                    sw_remove_window(g_seamless_windows);
3503            }
3504    }
3505    
3506    
3507    void
3508    ui_seamless_ack(unsigned int serial)
3509    {
3510            seamless_window *sw;
3511            for (sw = g_seamless_windows; sw; sw = sw->next)
3512            {
3513                    if (sw->outpos_serial == serial)
3514                    {
3515                            sw->xoffset = sw->outpos_xoffset;
3516                            sw->yoffset = sw->outpos_yoffset;
3517                            sw->width = sw->outpos_width;
3518                            sw->height = sw->outpos_height;
3519                            sw->outstanding_position = False;
3520                            break;
3521                    }
3522            }
3523    
3524            return;
3525    }

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

  ViewVC Help
Powered by ViewVC 1.1.26