/[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 823 by stargo, Mon Feb 28 23:30:00 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1168 by ossman_, Mon Mar 20 14:39:00 2006 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 32  extern int g_width; Line 32  extern int g_width;
32  extern int g_height;  extern int g_height;
33  extern int g_xpos;  extern int g_xpos;
34  extern int g_ypos;  extern int g_ypos;
35    extern int g_pos;
36  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
37  extern BOOL g_fullscreen;  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 45  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 60  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 78  static Pixmap g_backstore = 0; Line 133  static Pixmap g_backstore = 0;
133  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
134  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
135  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
136    static BOOL g_using_full_workarea = False;
137    
138  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
139  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 90  extern BOOL g_rdpsnd; Line 146  extern BOOL g_rdpsnd;
146  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
147  typedef struct  typedef struct
148  {  {
149          uint32 flags;          unsigned long flags;
150          uint32 functions;          unsigned long functions;
151          uint32 decorations;          unsigned long decorations;
152          sint32 inputMode;          long inputMode;
153          uint32 status;          unsigned long status;
154  }  }
155  PropMotifWmHints;  PropMotifWmHints;
156    
# Line 106  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 119  PixelColour; Line 210  PixelColour;
210          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
211  }  }
212    
213    #define FILL_POLYGON(p,np)\
214    { \
215            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
216            if (g_ownbackstore) \
217                    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)\
222    { \
223            switch (m) \
224            { \
225                    case 0: /* Outline */ \
226                            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) \
229                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
230                            break; \
231                    case 1: /* Filled */ \
232                            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) \
236                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
237                            break; \
238            } \
239    }
240    
241  /* colour maps */  /* colour maps */
242  extern BOOL g_owncolmap;  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 150  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    seamless_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    seamless_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    seamless_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
318    seamless_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    seamless_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    seamless_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                            seamless_update_position(sw);
373                    }
374            }
375    }
376    
377    
378    static void
379    seamless_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  static void
409  mwm_hide_decorations(void)  mwm_hide_decorations(Window wnd)
410  {  {
411          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
412          Atom hintsatom;          Atom hintsatom;
# Line 168  mwm_hide_decorations(void) Line 423  mwm_hide_decorations(void)
423                  return;                  return;
424          }          }
425    
426          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
427                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
428    
429  }  }
430    
431  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 203  mwm_hide_decorations(void) Line 459  mwm_hide_decorations(void)
459  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
460                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
461    
462    /* The following macros output the same octet sequences
463       on both BE and LE hosts: */
464    
465  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
466  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
467  #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 214  static uint32 Line 473  static uint32
473  translate_colour(uint32 colour)  translate_colour(uint32 colour)
474  {  {
475          PixelColour pc;          PixelColour pc;
476          switch (g_server_bpp)          switch (g_server_depth)
477          {          {
478                  case 15:                  case 15:
479                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 225  translate_colour(uint32 colour) Line 484  translate_colour(uint32 colour)
484                  case 24:                  case 24:
485                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
486                          break;                          break;
487                    default:
488                            /* Avoid warning */
489                            pc.red = 0;
490                            pc.green = 0;
491                            pc.blue = 0;
492                            break;
493          }          }
494          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
495  }  }
# Line 276  translate8to16(const uint8 * data, uint8 Line 541  translate8to16(const uint8 * data, uint8
541  {  {
542          uint16 value;          uint16 value;
543    
544          if (g_arch_match)          if (g_compatible_arch)
545          {          {
546                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
547                  REPEAT2                  REPEAT2
# Line 310  translate8to24(const uint8 * data, uint8 Line 575  translate8to24(const uint8 * data, uint8
575  {  {
576          uint32 value;          uint32 value;
577    
578          if (g_xserver_be)          if (g_compatible_arch)
579          {          {
580                  while (out < end)                  while (out < end)
581                  {                  {
# Line 333  translate8to32(const uint8 * data, uint8 Line 598  translate8to32(const uint8 * data, uint8
598  {  {
599          uint32 value;          uint32 value;
600    
601          if (g_arch_match)          if (g_compatible_arch)
602          {          {
603                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
604                  REPEAT4                  REPEAT4
# Line 405  translate15to24(const uint16 * data, uin Line 670  translate15to24(const uint16 * data, uin
670          uint16 pixel;          uint16 pixel;
671          PixelColour pc;          PixelColour pc;
672    
673          if (g_arch_match)          if (g_compatible_arch)
674          {          {
675                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
676                  REPEAT3                  REPEAT3
# Line 455  translate15to32(const uint16 * data, uin Line 720  translate15to32(const uint16 * data, uin
720          uint32 value;          uint32 value;
721          PixelColour pc;          PixelColour pc;
722    
723          if (g_arch_match)          if (g_compatible_arch)
724          {          {
725                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
726                  REPEAT4                  REPEAT4
# Line 563  translate16to24(const uint16 * data, uin Line 828  translate16to24(const uint16 * data, uin
828          uint16 pixel;          uint16 pixel;
829          PixelColour pc;          PixelColour pc;
830    
831          if (g_arch_match)          if (g_compatible_arch)
832          {          {
833                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
834                  REPEAT3                  REPEAT3
# Line 633  translate16to32(const uint16 * data, uin Line 898  translate16to32(const uint16 * data, uin
898          uint32 value;          uint32 value;
899          PixelColour pc;          PixelColour pc;
900    
901          if (g_arch_match)          if (g_compatible_arch)
902          {          {
903                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
904                  REPEAT4                  REPEAT4
# Line 762  translate24to32(const uint8 * data, uint Line 1027  translate24to32(const uint8 * data, uint
1027          uint32 value;          uint32 value;
1028          PixelColour pc;          PixelColour pc;
1029    
1030          if (g_arch_match)          if (g_compatible_arch)
1031          {          {
1032                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1033  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 776  translate24to32(const uint8 * data, uint Line 1041  translate24to32(const uint8 * data, uint
1041  #else  #else
1042                  REPEAT4                  REPEAT4
1043                  (                  (
1044                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1045                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1046                          data += 3;                   out += 4;
1047                     data += 3;
1048                  )                  )
1049  #endif  #endif
1050                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 816  translate_image(int width, int height, u Line 1082  translate_image(int width, int height, u
1082          uint8 *out;          uint8 *out;
1083          uint8 *end;          uint8 *end;
1084    
1085          /* if server and xserver bpp match, */          /*
1086          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1087          /* just return data */             and arch(endian) matches, no need to translate:
1088          if (g_arch_match)             just return data.
1089               Note: select_visual should've already ensured g_no_translate
1090               is only set for compatible depths, but the RDP depth might've
1091               changed during connection negotiations.
1092             */
1093            if (g_no_translate_image)
1094          {          {
1095                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1096                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1097                  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)  
1098                          return data;                          return data;
1099          }          }
1100    
# Line 833  translate_image(int width, int height, u Line 1102  translate_image(int width, int height, u
1102          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1103          end = out + size;          end = out + size;
1104    
1105          switch (g_server_bpp)          switch (g_server_depth)
1106          {          {
1107                  case 24:                  case 24:
1108                          switch (g_bpp)                          switch (g_bpp)
# Line 931  calculate_shifts(uint32 mask, int *shift Line 1200  calculate_shifts(uint32 mask, int *shift
1200          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1201  }  }
1202    
1203  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1204  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1205     */
1206    static unsigned
1207    calculate_mask_weight(uint32 mask)
1208    {
1209            unsigned weight = 0;
1210            do
1211            {
1212                    weight += (mask & 1);
1213            }
1214            while (mask >>= 1);
1215            return weight;
1216    }
1217    
1218    static BOOL
1219    select_visual()
1220  {  {
         XVisualInfo vi;  
1221          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1222          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1223          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1224          XVisualInfo template;          XVisualInfo template;
1225          Bool TrueColorVisual = False;          int i;
1226            unsigned red_weight, blue_weight, green_weight;
1227    
1228          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1229          if (g_display == NULL)  
1230            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1231            if (pfm == NULL)
1232          {          {
1233                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1234                    XCloseDisplay(g_display);
1235                  return False;                  return False;
1236          }          }
1237    
1238          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 */  
1239          template.class = TrueColor;          template.class = TrueColor;
1240          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1241            g_visual = NULL;
1242            g_no_translate_image = False;
1243            g_compatible_arch = False;
1244            if (vmatches != NULL)
1245            {
1246                    for (i = 0; i < visuals_count; ++i)
1247                    {
1248                            XVisualInfo *visual_info = &vmatches[i];
1249    
1250                            /* Try to find a no-translation visual that'll
1251                               allow us to use RDP bitmaps directly as ZPixmaps. */
1252                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1253                                                   /* R5G5B5 */
1254                                                   (visual_info->red_mask == 0x7c00) &&
1255                                                   (visual_info->green_mask == 0x3e0) &&
1256                                                   (visual_info->blue_mask == 0x1f)) ||
1257                                                  ((visual_info->depth == 16) &&
1258                                                   /* R5G6B5 */
1259                                                   (visual_info->red_mask == 0xf800) &&
1260                                                   (visual_info->green_mask == 0x7e0) &&
1261                                                   (visual_info->blue_mask == 0x1f)) ||
1262                                                  ((visual_info->depth == 24) &&
1263                                                   /* R8G8B8 */
1264                                                   (visual_info->red_mask == 0xff0000) &&
1265                                                   (visual_info->green_mask == 0xff00) &&
1266                                                   (visual_info->blue_mask == 0xff))))
1267                            {
1268                                    g_visual = visual_info->visual;
1269                                    g_depth = visual_info->depth;
1270                                    g_compatible_arch = !g_host_be;
1271                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1272                                    if (g_no_translate_image)
1273                                            /* We found the best visual */
1274                                            break;
1275                            }
1276                            else
1277                            {
1278                                    g_compatible_arch = False;
1279                            }
1280    
1281                            if (visual_info->depth > 24)
1282                            {
1283                                    /* Avoid 32-bit visuals and likes like the plague.
1284                                       They're either untested or proven to work bad
1285                                       (e.g. nvidia's Composite 32-bit visual).
1286                                       Most implementation offer a 24-bit visual anyway. */
1287                                    continue;
1288                            }
1289    
1290          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1291          while (nvisuals >= 0)                             we have a translateXtoY function. */
1292          {                          BOOL can_translate_to_bpp = False;
1293                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1294                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1295                          g_depth = (vmatches + nvisuals)->depth;                          {
1296                                    if (pfm[j].depth == visual_info->depth)
1297                                    {
1298                                            if ((pfm[j].bits_per_pixel == 16) ||
1299                                                (pfm[j].bits_per_pixel == 24) ||
1300                                                (pfm[j].bits_per_pixel == 32))
1301                                            {
1302                                                    can_translate_to_bpp = True;
1303                                            }
1304                                            break;
1305                                    }
1306                            }
1307    
1308                            /* Prefer formats which have the most colour depth.
1309                               We're being truly aristocratic here, minding each
1310                               weight on its own. */
1311                            if (can_translate_to_bpp)
1312                            {
1313                                    unsigned vis_red_weight =
1314                                            calculate_mask_weight(visual_info->red_mask);
1315                                    unsigned vis_green_weight =
1316                                            calculate_mask_weight(visual_info->green_mask);
1317                                    unsigned vis_blue_weight =
1318                                            calculate_mask_weight(visual_info->blue_mask);
1319                                    if ((vis_red_weight >= red_weight)
1320                                        && (vis_green_weight >= green_weight)
1321                                        && (vis_blue_weight >= blue_weight))
1322                                    {
1323                                            red_weight = vis_red_weight;
1324                                            green_weight = vis_green_weight;
1325                                            blue_weight = vis_blue_weight;
1326                                            g_visual = visual_info->visual;
1327                                            g_depth = visual_info->depth;
1328                                    }
1329                            }
1330                  }                  }
1331                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1332          }          }
1333    
1334          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)))  
1335          {          {
1336                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1337                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1338                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1339                    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;  
                 }  
1340          }          }
1341          else          else
1342          {          {
1343                  /* need a truecolour visual */                  template.class = PseudoColor;
1344                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1345                  {                  template.colormap_size = 256;
1346                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1347                            XGetVisualInfo(g_display,
1348                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1349                                           &template, &visuals_count);
1350                    if (vmatches == NULL)
1351                    {
1352                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1353                            XCloseDisplay(g_display);
1354                            XFree(pfm);
1355                          return False;                          return False;
1356                  }                  }
1357    
1358                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1359                  g_owncolmap = False;                  g_owncolmap = True;
1360                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1361                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1362                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1363    
1364                  /* if RGB video and everything is little endian */          g_bpp = 0;
1365                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1366                      !g_xserver_be && !g_host_be)          {
1367                    XPixmapFormatValues *pf = &pfm[i];
1368                    if (pf->depth == g_depth)
1369                  {                  {
1370                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1371                                                g_blue_shift_l == 0))  
1372                            if (g_no_translate_image)
1373                          {                          {
1374                                  g_arch_match = True;                                  switch (g_server_depth)
1375                                    {
1376                                            case 15:
1377                                            case 16:
1378                                                    if (g_bpp != 16)
1379                                                            g_no_translate_image = False;
1380                                                    break;
1381                                            case 24:
1382                                                    /* Yes, this will force image translation
1383                                                       on most modern servers which use 32 bits
1384                                                       for R8G8B8. */
1385                                                    if (g_bpp != 24)
1386                                                            g_no_translate_image = False;
1387                                                    break;
1388                                            default:
1389                                                    g_no_translate_image = False;
1390                                                    break;
1391                                    }
1392                          }                          }
                 }  
1393    
1394                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1395                  {                             there's just a single entry for every depth,
1396                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1397                            break;
1398                  }                  }
1399          }          }
1400            XFree(pfm);
1401            pfm = NULL;
1402            return True;
1403    }
1404    
1405    BOOL
1406    ui_init(void)
1407    {
1408            int screen_num;
1409    
1410          pfm = XListPixmapFormats(g_display, &i);          g_display = XOpenDisplay(NULL);
1411          if (pfm != NULL)          if (g_display == NULL)
1412          {          {
1413                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1414                     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);  
1415          }          }
1416    
         if (g_bpp < 8)  
1417          {          {
1418                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1419                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1420            }
1421    
1422            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1423            screen_num = DefaultScreen(g_display);
1424            g_x_socket = ConnectionNumber(g_display);
1425            g_screen = ScreenOfDisplay(g_display, screen_num);
1426            g_depth = DefaultDepthOfScreen(g_screen);
1427    
1428            if (!select_visual())
1429                  return False;                  return False;
1430    
1431            if (g_no_translate_image)
1432            {
1433                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1434          }          }
1435    
1436            if (g_server_depth > g_bpp)
1437            {
1438                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1439                            g_server_depth, g_bpp);
1440            }
1441    
1442            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1443                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1444    
1445          if (!g_owncolmap)          if (!g_owncolmap)
1446          {          {
1447                  g_xcolmap =                  g_xcolmap =
1448                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1449                                          AllocNone);                                          AllocNone);
1450                  if (g_depth <= 8)                  if (g_depth <= 8)
1451                          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);
1452          }          }
1453    
1454          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1455          {          {
1456                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1457                  g_ownbackstore = True;                  g_ownbackstore = True;
1458          }          }
1459    
# Line 1061  ui_init(void) Line 1464  ui_init(void)
1464          {          {
1465                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1466                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1467                    g_using_full_workarea = True;
1468          }          }
1469          else if (g_width < 0)          else if (g_width < 0)
1470          {          {
1471                  /* Percent of screen */                  /* Percent of screen */
1472                    if (-g_width >= 100)
1473                            g_using_full_workarea = True;
1474                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1475                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1476          }          }
# Line 1072  ui_init(void) Line 1478  ui_init(void)
1478          {          {
1479                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1480                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1481                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1482                  {                  {
1483                          g_width = cx;                          g_width = cx;
1484                          g_height = cy;                          g_height = cy;
1485                            g_using_full_workarea = True;
1486                  }                  }
1487                  else                  else
1488                  {                  {
1489                          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");
1490                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1491                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1492                  }                  }
1493          }          }
1494    
# Line 1097  ui_init(void) Line 1503  ui_init(void)
1503                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1504    
1505          xclip_init();          xclip_init();
1506            ewmh_init();
1507            if (g_seamless_rdp)
1508                    seamless_init();
1509    
1510          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));
1511    
1512          return True;          return True;
1513  }  }
# Line 1122  ui_deinit(void) Line 1531  ui_deinit(void)
1531          g_display = NULL;          g_display = NULL;
1532  }  }
1533    
1534    
1535    static void
1536    get_window_attribs(XSetWindowAttributes * attribs)
1537    {
1538            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1539            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1540            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1541            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1542            attribs->override_redirect = g_fullscreen;
1543            attribs->colormap = g_xcolmap;
1544    }
1545    
1546    static void
1547    get_input_mask(long *input_mask)
1548    {
1549            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1550                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1551    
1552            if (g_sendmotion)
1553                    *input_mask |= PointerMotionMask;
1554            if (g_ownbackstore)
1555                    *input_mask |= ExposureMask;
1556            if (g_fullscreen || g_grab_keyboard)
1557                    *input_mask |= EnterWindowMask;
1558            if (g_grab_keyboard)
1559                    *input_mask |= LeaveWindowMask;
1560    }
1561    
1562  BOOL  BOOL
1563  ui_create_window(void)  ui_create_window(void)
1564  {  {
# Line 1138  ui_create_window(void) Line 1575  ui_create_window(void)
1575          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1576          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1577    
1578          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1579          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1580          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1581          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1582          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1583    
1584            get_window_attribs(&attribs);
1585    
1586          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,
1587                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1150  ui_create_window(void) Line 1589  ui_create_window(void)
1589                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1590    
1591          if (g_gc == NULL)          if (g_gc == NULL)
1592            {
1593                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1594                    ui_reset_clip();
1595            }
1596    
1597          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1598                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1167  ui_create_window(void) Line 1609  ui_create_window(void)
1609          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1610    
1611          if (g_hide_decorations)          if (g_hide_decorations)
1612                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1613    
1614          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1615          if (classhints != NULL)          if (classhints != NULL)
# Line 1181  ui_create_window(void) Line 1623  ui_create_window(void)
1623          if (sizehints)          if (sizehints)
1624          {          {
1625                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1626                    if (g_pos)
1627                            sizehints->flags |= PPosition;
1628                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1629                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1630                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 1192  ui_create_window(void) Line 1636  ui_create_window(void)
1636                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1637          }          }
1638    
1639          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask;  
   
         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;  
1640    
1641          if (g_IM != NULL)          if (g_IM != NULL)
1642          {          {
# Line 1215  ui_create_window(void) Line 1649  ui_create_window(void)
1649          }          }
1650    
1651          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1652    
1653            XMapWindow(g_display, g_wnd);
1654          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1655          do          do
1656          {          {
# Line 1287  xwin_toggle_fullscreen(void) Line 1721  xwin_toggle_fullscreen(void)
1721  {  {
1722          Pixmap contents = 0;          Pixmap contents = 0;
1723    
1724            if (g_seamless_active)
1725                    /* Turn off SeamlessRDP mode */
1726                    ui_seamless_toggle();
1727    
1728          if (!g_ownbackstore)          if (!g_ownbackstore)
1729          {          {
1730                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1307  xwin_toggle_fullscreen(void) Line 1745  xwin_toggle_fullscreen(void)
1745          }          }
1746  }  }
1747    
1748  /* Process all events in Xlib queue  static void
1749    handle_button_event(XEvent xevent, BOOL down)
1750    {
1751            uint16 button, flags = 0;
1752            g_last_gesturetime = xevent.xbutton.time;
1753            button = xkeymap_translate_button(xevent.xbutton.button);
1754            if (button == 0)
1755                    return;
1756    
1757            if (down)
1758                    flags = MOUSE_FLAG_DOWN;
1759    
1760            /* Stop moving window when button is released, regardless of cursor position */
1761            if (g_moving_wnd && (xevent.type == ButtonRelease))
1762                    g_moving_wnd = False;
1763    
1764            /* If win_button_size is nonzero, enable single app mode */
1765            if (xevent.xbutton.y < g_win_button_size)
1766            {
1767                    /*  Check from right to left: */
1768                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1769                    {
1770                            /* The close button, continue */
1771                            ;
1772                    }
1773                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1774                    {
1775                            /* The maximize/restore button. Do not send to
1776                               server.  It might be a good idea to change the
1777                               cursor or give some other visible indication
1778                               that rdesktop inhibited this click */
1779                            if (xevent.type == ButtonPress)
1780                                    return;
1781                    }
1782                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1783                    {
1784                            /* The minimize button. Iconify window. */
1785                            if (xevent.type == ButtonRelease)
1786                            {
1787                                    /* Release the mouse button outside the minimize button, to prevent the
1788                                       actual minimazation to happen */
1789                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1790                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1791                                    return;
1792                            }
1793                    }
1794                    else if (xevent.xbutton.x <= g_win_button_size)
1795                    {
1796                            /* The system menu. Ignore. */
1797                            if (xevent.type == ButtonPress)
1798                                    return;
1799                    }
1800                    else
1801                    {
1802                            /* The title bar. */
1803                            if (xevent.type == ButtonPress)
1804                            {
1805                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1806                                    {
1807                                            g_moving_wnd = True;
1808                                            g_move_x_offset = xevent.xbutton.x;
1809                                            g_move_y_offset = xevent.xbutton.y;
1810                                    }
1811                                    return;
1812                            }
1813                    }
1814            }
1815    
1816            if (xevent.xmotion.window == g_wnd)
1817            {
1818                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1819                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1820            }
1821            else
1822            {
1823                    /* SeamlessRDP */
1824                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1825                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1826            }
1827    }
1828    
1829    static void
1830    ui_seamless_handle_restack(seamless_window * sw)
1831    {
1832            Status status;
1833            Window root, parent, *children;
1834            unsigned int nchildren, i;
1835            seamless_window *sw_below;
1836    
1837            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1838                                &root, &parent, &children, &nchildren);
1839            if (!status || !nchildren)
1840                    return;
1841    
1842            sw_below = NULL;
1843    
1844            i = 0;
1845            while (children[i] != sw->wnd)
1846            {
1847                    i++;
1848                    if (i >= nchildren)
1849                            return;
1850            }
1851    
1852            for (i++; i < nchildren; i++)
1853            {
1854                    sw_below = seamless_get_window_by_wnd(children[i]);
1855                    if (sw_below)
1856                            break;
1857            }
1858    
1859            if (!sw_below && !sw->behind)
1860                    return;
1861            if (sw_below && (sw_below->id == sw->behind))
1862                    return;
1863    
1864            if (sw_below)
1865            {
1866                    seamless_send_zchange(sw->id, sw_below->id, 0);
1867                    seamless_restack_window(sw, sw_below->id);
1868            }
1869            else
1870            {
1871                    seamless_send_zchange(sw->id, 0, 0);
1872                    seamless_restack_window(sw, 0);
1873            }
1874    }
1875    
1876    /* Process events in Xlib queue
1877     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1878  static int  static int
1879  xwin_process_events(void)  xwin_process_events(void)
1880  {  {
1881          XEvent xevent;          XEvent xevent;
1882          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1883          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1884          char str[256];          char str[256];
1885          Status status;          Status status;
1886            int events = 0;
1887            seamless_window *sw;
1888    
1889          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1890          {          {
1891                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1892    
# Line 1330  xwin_process_events(void) Line 1896  xwin_process_events(void)
1896                          continue;                          continue;
1897                  }                  }
1898    
                 flags = 0;  
   
1899                  switch (xevent.type)                  switch (xevent.type)
1900                  {                  {
1901                          case VisibilityNotify:                          case VisibilityNotify:
1902                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1903                                            g_Unobscured =
1904                                                    xevent.xvisibility.state == VisibilityUnobscured;
1905    
1906                                  break;                                  break;
1907                          case ClientMessage:                          case ClientMessage:
1908                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1368  xwin_process_events(void) Line 1935  xwin_process_events(void)
1935                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1936                                  }                                  }
1937    
1938                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1939                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1940    
1941                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1942                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1943                                          break;                                          break;
1944    
1945                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1946                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
1947                                  break;                                  break;
1948    
1949                          case KeyRelease:                          case KeyRelease:
# Line 1393  xwin_process_events(void) Line 1951  xwin_process_events(void)
1951                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1952                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1953    
1954                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1955                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1956    
1957                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1958                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1959                                          break;                                          break;
1960    
1961                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1962                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1963                                  break;                                  break;
1964    
1965                          case ButtonPress:                          case ButtonPress:
1966                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1967                                  /* fall through */                                  break;
1968    
1969                          case ButtonRelease:                          case ButtonRelease:
1970                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
1971                                  break;                                  break;
1972    
1973                          case MotionNotify:                          case MotionNotify:
# Line 1486  xwin_process_events(void) Line 1982  xwin_process_events(void)
1982                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1983                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1984                                                         CurrentTime);                                                         CurrentTime);
1985                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1986                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1987                                    {
1988                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1989                                                           xevent.xmotion.x, xevent.xmotion.y);
1990                                    }
1991                                    else
1992                                    {
1993                                            /* SeamlessRDP */
1994                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1995                                                           xevent.xmotion.x_root,
1996                                                           xevent.xmotion.y_root);
1997                                    }
1998                                  break;                                  break;
1999    
2000                          case FocusIn:                          case FocusIn:
# Line 1498  xwin_process_events(void) Line 2005  xwin_process_events(void)
2005                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2006                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2007                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2008    
2009                                    sw = seamless_get_window_by_wnd(xevent.xfocus.window);
2010                                    if (!sw)
2011                                            break;
2012    
2013                                    if (sw->id != g_seamless_focused)
2014                                    {
2015                                            seamless_send_focus(sw->id, 0);
2016                                            g_seamless_focused = sw->id;
2017                                    }
2018                                  break;                                  break;
2019    
2020                          case FocusOut:                          case FocusOut:
# Line 1530  xwin_process_events(void) Line 2047  xwin_process_events(void)
2047                                  break;                                  break;
2048    
2049                          case Expose:                          case Expose:
2050                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2051                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2052                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2053                                            xevent.xexpose.height,                                                    g_gc,
2054                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2055                                                      xevent.xexpose.width, xevent.xexpose.height,
2056                                                      xevent.xexpose.x, xevent.xexpose.y);
2057                                    }
2058                                    else
2059                                    {
2060                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
2061                                            if (sw)
2062                                                    XCopyArea(g_display, g_backstore,
2063                                                              xevent.xexpose.window, g_gc,
2064                                                              xevent.xexpose.x + sw->xoffset,
2065                                                              xevent.xexpose.y + sw->yoffset,
2066                                                              xevent.xexpose.width,
2067                                                              xevent.xexpose.height, xevent.xexpose.x,
2068                                                              xevent.xexpose.y);
2069                                            else
2070                                            {
2071                                                    error("Expose for unknown window 0x%lx\n",
2072                                                          xevent.xexpose.window);
2073                                            }
2074                                    }
2075    
2076                                  break;                                  break;
2077    
2078                          case MappingNotify:                          case MappingNotify:
# Line 1563  xwin_process_events(void) Line 2101  xwin_process_events(void)
2101                                  break;                                  break;
2102                          case PropertyNotify:                          case PropertyNotify:
2103                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2104                                    if (xevent.xproperty.window == g_wnd)
2105                                            break;
2106                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2107                                            break;
2108    
2109                                    /* seamless */
2110                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2111                                    if (!sw)
2112                                            break;
2113    
2114                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2115                                        && (xevent.xproperty.state == PropertyNewValue))
2116                                    {
2117                                            sw->state = ewmh_get_window_state(sw->wnd);
2118                                            seamless_send_state(sw->id, sw->state, 0);
2119                                    }
2120    
2121                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2122                                        && (xevent.xproperty.state == PropertyNewValue))
2123                                    {
2124                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2125                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
2126                                    }
2127    
2128                                    break;
2129                            case MapNotify:
2130                                    if (!g_seamless_active)
2131                                            rdp_send_client_window_status(1);
2132                                    break;
2133                            case UnmapNotify:
2134                                    if (!g_seamless_active)
2135                                            rdp_send_client_window_status(0);
2136                                    break;
2137                            case ConfigureNotify:
2138                                    if (!g_seamless_active)
2139                                            break;
2140    
2141                                    sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2142                                    if (!sw)
2143                                    {
2144                                            error("ConfigureNotify for unknown window 0x%lx\n",
2145                                                  xevent.xconfigure.window);
2146                                    }
2147    
2148                                    gettimeofday(sw->position_timer, NULL);
2149                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2150                                        1000000)
2151                                    {
2152                                            sw->position_timer->tv_usec +=
2153                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2154                                            sw->position_timer->tv_sec += 1;
2155                                    }
2156                                    else
2157                                    {
2158                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2159                                    }
2160    
2161                                    ui_seamless_handle_restack(sw);
2162                                  break;                                  break;
2163                  }                  }
2164          }          }
# Line 1587  ui_select(int rdp_socket) Line 2183  ui_select(int rdp_socket)
2183                          /* User quit */                          /* User quit */
2184                          return 0;                          return 0;
2185    
2186                    if (g_seamless_active)
2187                            seamless_check_timers();
2188    
2189                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2190                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2191                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1606  ui_select(int rdp_socket) Line 2205  ui_select(int rdp_socket)
2205    
2206                  /* add redirection handles */                  /* add redirection handles */
2207                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2208                    seamless_select_timeout(&tv);
2209    
2210                  n++;                  n++;
2211    
# Line 1647  ui_create_bitmap(int width, int height, Line 2247  ui_create_bitmap(int width, int height,
2247          uint8 *tdata;          uint8 *tdata;
2248          int bitmap_pad;          int bitmap_pad;
2249    
2250          if (g_server_bpp == 8)          if (g_server_depth == 8)
2251          {          {
2252                  bitmap_pad = 8;                  bitmap_pad = 8;
2253          }          }
# Line 1679  ui_paint_bitmap(int x, int y, int cx, in Line 2279  ui_paint_bitmap(int x, int y, int cx, in
2279          uint8 *tdata;          uint8 *tdata;
2280          int bitmap_pad;          int bitmap_pad;
2281    
2282          if (g_server_bpp == 8)          if (g_server_depth == 8)
2283          {          {
2284                  bitmap_pad = 8;                  bitmap_pad = 8;
2285          }          }
# Line 1699  ui_paint_bitmap(int x, int y, int cx, in Line 2299  ui_paint_bitmap(int x, int y, int cx, in
2299          {          {
2300                  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);
2301                  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);
2302                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2303                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2304                                             x - sw->xoffset, y - sw->yoffset));
2305          }          }
2306          else          else
2307          {          {
2308                  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);
2309                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2310                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2311                                             x - sw->xoffset, y - sw->yoffset));
2312          }          }
2313    
2314          XFree(image);          XFree(image);
# Line 1823  ui_set_cursor(HCURSOR cursor) Line 2429  ui_set_cursor(HCURSOR cursor)
2429  {  {
2430          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2431          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2432            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2433  }  }
2434    
2435  void  void
# Line 1964  ui_set_colourmap(HCOLOURMAP map) Line 2571  ui_set_colourmap(HCOLOURMAP map)
2571                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2572          }          }
2573          else          else
2574            {
2575                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2576                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2577            }
2578  }  }
2579    
2580  void  void
2581  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2582  {  {
2583          XRectangle rect;          g_clip_rectangle.x = x;
2584            g_clip_rectangle.y = y;
2585          rect.x = x;          g_clip_rectangle.width = cx;
2586          rect.y = y;          g_clip_rectangle.height = cy;
2587          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);  
2588  }  }
2589    
2590  void  void
2591  ui_reset_clip(void)  ui_reset_clip(void)
2592  {  {
2593          XRectangle rect;          g_clip_rectangle.x = 0;
2594            g_clip_rectangle.y = 0;
2595          rect.x = 0;          g_clip_rectangle.width = g_width;
2596          rect.y = 0;          g_clip_rectangle.height = g_height;
2597          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);  
2598  }  }
2599    
2600  void  void
# Line 2069  ui_patblt(uint8 opcode, Line 2675  ui_patblt(uint8 opcode,
2675    
2676          if (g_ownbackstore)          if (g_ownbackstore)
2677                  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);
2678            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2679                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2680                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2681  }  }
2682    
2683  void  void
# Line 2079  ui_screenblt(uint8 opcode, Line 2688  ui_screenblt(uint8 opcode,
2688          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2689          if (g_ownbackstore)          if (g_ownbackstore)
2690          {          {
2691                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2692                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2693                          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);  
                 }  
2694          }          }
2695          else          else
2696          {          {
2697                  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);
2698          }          }
2699    
2700            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2701                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2702                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2703    
2704          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2705  }  }
2706    
# Line 2106  ui_memblt(uint8 opcode, Line 2711  ui_memblt(uint8 opcode,
2711  {  {
2712          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2713          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);
2714            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2715                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2716                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2717          if (g_ownbackstore)          if (g_ownbackstore)
2718                  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);
2719          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2152  ui_line(uint8 opcode, Line 2760  ui_line(uint8 opcode,
2760          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2761          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2762          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2763            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2764                                                startx - sw->xoffset, starty - sw->yoffset,
2765                                                endx - sw->xoffset, endy - sw->yoffset));
2766          if (g_ownbackstore)          if (g_ownbackstore)
2767                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2768          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2166  ui_rect( Line 2777  ui_rect(
2777          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2778  }  }
2779    
2780    void
2781    ui_polygon(uint8 opcode,
2782               /* mode */ uint8 fillmode,
2783               /* dest */ POINT * point, int npoints,
2784               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2785    {
2786            uint8 style, i, ipattern[8];
2787            Pixmap fill;
2788    
2789            SET_FUNCTION(opcode);
2790    
2791            switch (fillmode)
2792            {
2793                    case ALTERNATE:
2794                            XSetFillRule(g_display, g_gc, EvenOddRule);
2795                            break;
2796                    case WINDING:
2797                            XSetFillRule(g_display, g_gc, WindingRule);
2798                            break;
2799                    default:
2800                            unimpl("fill mode %d\n", fillmode);
2801            }
2802    
2803            if (brush)
2804                    style = brush->style;
2805            else
2806                    style = 0;
2807    
2808            switch (style)
2809            {
2810                    case 0: /* Solid */
2811                            SET_FOREGROUND(fgcolour);
2812                            FILL_POLYGON((XPoint *) point, npoints);
2813                            break;
2814    
2815                    case 2: /* Hatch */
2816                            fill = (Pixmap) ui_create_glyph(8, 8,
2817                                                            hatch_patterns + brush->pattern[0] * 8);
2818                            SET_FOREGROUND(fgcolour);
2819                            SET_BACKGROUND(bgcolour);
2820                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2821                            XSetStipple(g_display, g_gc, fill);
2822                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2823                            FILL_POLYGON((XPoint *) point, npoints);
2824                            XSetFillStyle(g_display, g_gc, FillSolid);
2825                            XSetTSOrigin(g_display, g_gc, 0, 0);
2826                            ui_destroy_glyph((HGLYPH) fill);
2827                            break;
2828    
2829                    case 3: /* Pattern */
2830                            for (i = 0; i != 8; i++)
2831                                    ipattern[7 - i] = brush->pattern[i];
2832                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2833                            SET_FOREGROUND(bgcolour);
2834                            SET_BACKGROUND(fgcolour);
2835                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2836                            XSetStipple(g_display, g_gc, fill);
2837                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2838                            FILL_POLYGON((XPoint *) point, npoints);
2839                            XSetFillStyle(g_display, g_gc, FillSolid);
2840                            XSetTSOrigin(g_display, g_gc, 0, 0);
2841                            ui_destroy_glyph((HGLYPH) fill);
2842                            break;
2843    
2844                    default:
2845                            unimpl("brush %d\n", brush->style);
2846            }
2847    
2848            RESET_FUNCTION(opcode);
2849    }
2850    
2851    void
2852    ui_polyline(uint8 opcode,
2853                /* dest */ POINT * points, int npoints,
2854                /* pen */ PEN * pen)
2855    {
2856            /* TODO: set join style */
2857            SET_FUNCTION(opcode);
2858            SET_FOREGROUND(pen->colour);
2859            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2860            if (g_ownbackstore)
2861                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2862                               CoordModePrevious);
2863    
2864            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2865                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2866    
2867            RESET_FUNCTION(opcode);
2868    }
2869    
2870    void
2871    ui_ellipse(uint8 opcode,
2872               /* mode */ uint8 fillmode,
2873               /* dest */ int x, int y, int cx, int cy,
2874               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2875    {
2876            uint8 style, i, ipattern[8];
2877            Pixmap fill;
2878    
2879            SET_FUNCTION(opcode);
2880    
2881            if (brush)
2882                    style = brush->style;
2883            else
2884                    style = 0;
2885    
2886            switch (style)
2887            {
2888                    case 0: /* Solid */
2889                            SET_FOREGROUND(fgcolour);
2890                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2891                            break;
2892    
2893                    case 2: /* Hatch */
2894                            fill = (Pixmap) ui_create_glyph(8, 8,
2895                                                            hatch_patterns + brush->pattern[0] * 8);
2896                            SET_FOREGROUND(fgcolour);
2897                            SET_BACKGROUND(bgcolour);
2898                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2899                            XSetStipple(g_display, g_gc, fill);
2900                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2901                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2902                            XSetFillStyle(g_display, g_gc, FillSolid);
2903                            XSetTSOrigin(g_display, g_gc, 0, 0);
2904                            ui_destroy_glyph((HGLYPH) fill);
2905                            break;
2906    
2907                    case 3: /* Pattern */
2908                            for (i = 0; i != 8; i++)
2909                                    ipattern[7 - i] = brush->pattern[i];
2910                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2911                            SET_FOREGROUND(bgcolour);
2912                            SET_BACKGROUND(fgcolour);
2913                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2914                            XSetStipple(g_display, g_gc, fill);
2915                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2916                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2917                            XSetFillStyle(g_display, g_gc, FillSolid);
2918                            XSetTSOrigin(g_display, g_gc, 0, 0);
2919                            ui_destroy_glyph((HGLYPH) fill);
2920                            break;
2921    
2922                    default:
2923                            unimpl("brush %d\n", brush->style);
2924            }
2925    
2926            RESET_FUNCTION(opcode);
2927    }
2928    
2929  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
2930  void  void
2931  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 2221  ui_draw_glyph(int mixmode, Line 2981  ui_draw_glyph(int mixmode,
2981  }  }
2982    
2983  void  void
2984  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2985               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2986               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2987               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2988  {  {
2989            /* TODO: use brush appropriately */
2990    
2991          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2992          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
2993          DATABLOB *entry;          DATABLOB *entry;
# Line 2257  ui_draw_text(uint8 font, uint8 flags, in Line 3019  ui_draw_text(uint8 font, uint8 flags, in
3019                  switch (text[i])                  switch (text[i])
3020                  {                  {
3021                          case 0xff:                          case 0xff:
3022                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3023                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3024                                  {                                  {
3025                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3026                                          exit(1);                                          for (j = 0; j < length; j++)
3027                                                    fprintf(stderr, "%02x ", text[j]);
3028                                            fprintf(stderr, "\n");
3029                                            i = length = 0;
3030                                            break;
3031                                  }                                  }
3032                                    cache_put_text(text[i + 1], text, text[i + 2]);
3033                                    i += 3;
3034                                    length -= i;
3035                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3036                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3037                                  i = 0;                                  i = 0;
3038                                  break;                                  break;
3039    
3040                          case 0xfe:                          case 0xfe:
3041                                    /* At least one byte needs to follow */
3042                                    if (i + 2 > length)
3043                                    {
3044                                            warning("Skipping short 0xfe command:");
3045                                            for (j = 0; j < length; j++)
3046                                                    fprintf(stderr, "%02x ", text[j]);
3047                                            fprintf(stderr, "\n");
3048                                            i = length = 0;
3049                                            break;
3050                                    }
3051                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3052                                  if (entry != NULL)                                  if (entry->data != NULL)
3053                                  {                                  {
3054                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3055                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3056                                          {                                          {
3057                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3058                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2307  ui_draw_text(uint8 font, uint8 flags, in Line 3084  ui_draw_text(uint8 font, uint8 flags, in
3084          if (g_ownbackstore)          if (g_ownbackstore)
3085          {          {
3086                  if (boxcx > 1)                  if (boxcx > 1)
3087                    {
3088                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3089                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3090                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3091                                                    (g_display, g_backstore, sw->wnd, g_gc,
3092                                                     boxx, boxy,
3093                                                     boxcx, boxcy,
3094                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3095                    }
3096                  else                  else
3097                    {
3098                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3099                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3100                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3101                                                    (g_display, g_backstore, sw->wnd, g_gc,
3102                                                     clipx, clipy,
3103                                                     clipcx, clipcy, clipx - sw->xoffset,
3104                                                     clipy - sw->yoffset));
3105                    }
3106          }          }
3107  }  }
3108    
# Line 2357  ui_desktop_restore(uint32 offset, int x, Line 3148  ui_desktop_restore(uint32 offset, int x,
3148          {          {
3149                  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);
3150                  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);
3151                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3152                                            (g_display, g_backstore, sw->wnd, g_gc,
3153                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3154          }          }
3155          else          else
3156          {          {
3157                  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);
3158                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3159                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3160                                             x - sw->xoffset, y - sw->yoffset));
3161          }          }
3162    
3163          XFree(image);          XFree(image);
# Line 2376  void Line 3173  void
3173  ui_end_update(void)  ui_end_update(void)
3174  {  {
3175  }  }
3176    
3177    void
3178    ui_seamless_begin()
3179    {
3180            if (!g_seamless_rdp)
3181                    return;
3182    
3183            if (g_seamless_started)
3184                    return;
3185    
3186            g_seamless_started = True;
3187    
3188            ui_seamless_toggle();
3189    }
3190    
3191    void
3192    ui_seamless_toggle()
3193    {
3194            if (!g_seamless_rdp)
3195                    return;
3196    
3197            if (!g_seamless_started)
3198                    return;
3199    
3200            if (g_seamless_active)
3201            {
3202                    /* Deactivate */
3203                    while (g_seamless_windows)
3204                    {
3205                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3206                            seamless_remove_window(g_seamless_windows);
3207                    }
3208                    XMapWindow(g_display, g_wnd);
3209            }
3210            else
3211            {
3212                    /* Activate */
3213                    XUnmapWindow(g_display, g_wnd);
3214                    seamless_send_sync();
3215            }
3216    
3217            g_seamless_active = !g_seamless_active;
3218    }
3219    
3220    void
3221    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3222    {
3223            Window wnd;
3224            XSetWindowAttributes attribs;
3225            XClassHint *classhints;
3226            XSizeHints *sizehints;
3227            long input_mask;
3228            seamless_window *sw, *sw_parent;
3229    
3230            if (!g_seamless_active)
3231                    return;
3232    
3233            /* Ignore CREATEs for existing windows */
3234            sw = seamless_get_window_by_id(id);
3235            if (sw)
3236                    return;
3237    
3238            get_window_attribs(&attribs);
3239            attribs.override_redirect = False;
3240    
3241            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3242                                InputOutput, g_visual,
3243                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3244                                CWBorderPixel, &attribs);
3245    
3246            XStoreName(g_display, wnd, "SeamlessRDP");
3247            ewmh_set_wm_name(wnd, "SeamlessRDP");
3248    
3249            mwm_hide_decorations(wnd);
3250    
3251            classhints = XAllocClassHint();
3252            if (classhints != NULL)
3253            {
3254                    classhints->res_name = "rdesktop";
3255                    classhints->res_class = "SeamlessRDP";
3256                    XSetClassHint(g_display, wnd, classhints);
3257                    XFree(classhints);
3258            }
3259    
3260            /* WM_NORMAL_HINTS */
3261            sizehints = XAllocSizeHints();
3262            if (sizehints != NULL)
3263            {
3264                    sizehints->flags = USPosition;
3265                    XSetWMNormalHints(g_display, wnd, sizehints);
3266                    XFree(sizehints);
3267            }
3268    
3269            /* Handle popups without parents through some ewm hints */
3270            if (parent == 0xFFFFFFFF)
3271                    ewmh_set_window_popup(wnd);
3272            /* Set WM_TRANSIENT_FOR, if necessary */
3273            else if (parent != 0x00000000)
3274            {
3275                    sw_parent = seamless_get_window_by_id(parent);
3276                    if (sw_parent)
3277                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3278                    else
3279                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3280            }
3281    
3282    
3283            /* FIXME: Support for Input Context:s */
3284    
3285            get_input_mask(&input_mask);
3286            input_mask |= PropertyChangeMask;
3287    
3288            XSelectInput(g_display, wnd, input_mask);
3289    
3290            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3291               seamless window, we could try to close the window on the
3292               serverside, instead of terminating rdesktop */
3293            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3294    
3295            sw = xmalloc(sizeof(seamless_window));
3296            sw->wnd = wnd;
3297            sw->id = id;
3298            sw->behind = 0;
3299            sw->xoffset = 0;
3300            sw->yoffset = 0;
3301            sw->width = 0;
3302            sw->height = 0;
3303            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3304            sw->desktop = 0;
3305            sw->position_timer = xmalloc(sizeof(struct timeval));
3306            timerclear(sw->position_timer);
3307            sw->outstanding_position = False;
3308            sw->next = g_seamless_windows;
3309            g_seamless_windows = sw;
3310    }
3311    
3312    
3313    void
3314    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3315    {
3316            seamless_window *sw;
3317    
3318            if (!g_seamless_active)
3319                    return;
3320    
3321            sw = seamless_get_window_by_id(id);
3322            if (!sw)
3323            {
3324                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3325                    return;
3326            }
3327    
3328            XDestroyWindow(g_display, sw->wnd);
3329            seamless_remove_window(sw);
3330    }
3331    
3332    
3333    void
3334    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3335    {
3336            seamless_window *sw;
3337    
3338            if (!g_seamless_active)
3339                    return;
3340    
3341            sw = seamless_get_window_by_id(id);
3342            if (!sw)
3343            {
3344                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3345                    return;
3346            }
3347    
3348            /* We ignore server updates until it has handled our request. */
3349            if (sw->outstanding_position)
3350                    return;
3351    
3352            if (!width || !height)
3353                    /* X11 windows must be at least 1x1 */
3354                    return;
3355    
3356            sw->xoffset = x;
3357            sw->yoffset = y;
3358            sw->width = width;
3359            sw->height = height;
3360    
3361            /* If we move the window in a maximized state, then KDE won't
3362               accept restoration */
3363            switch (sw->state)
3364            {
3365                    case SEAMLESSRDP_MINIMIZED:
3366                    case SEAMLESSRDP_MAXIMIZED:
3367                            return;
3368            }
3369    
3370            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3371            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3372    }
3373    
3374    void
3375    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3376    {
3377            seamless_window *sw;
3378    
3379            if (!g_seamless_active)
3380                    return;
3381    
3382            sw = seamless_get_window_by_id(id);
3383            if (!sw)
3384            {
3385                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3386                    return;
3387            }
3388    
3389            if (behind)
3390            {
3391                    seamless_window *sw_behind;
3392                    Window wnds[2];
3393    
3394                    sw_behind = seamless_get_window_by_id(behind);
3395                    if (!sw_behind)
3396                    {
3397                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3398                                    behind);
3399                            return;
3400                    }
3401    
3402                    wnds[1] = sw_behind->wnd;
3403                    wnds[0] = sw->wnd;
3404    
3405                    XRestackWindows(g_display, wnds, 2);
3406            }
3407            else
3408            {
3409                    XRaiseWindow(g_display, sw->wnd);
3410            }
3411    
3412            seamless_restack_window(sw, behind);
3413    }
3414    
3415    void
3416    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3417    {
3418            seamless_window *sw;
3419    
3420            if (!g_seamless_active)
3421                    return;
3422    
3423            sw = seamless_get_window_by_id(id);
3424            if (!sw)
3425            {
3426                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3427                    return;
3428            }
3429    
3430            /* FIXME: Might want to convert the name for non-EWMH WMs */
3431            XStoreName(g_display, sw->wnd, title);
3432            ewmh_set_wm_name(sw->wnd, title);
3433    }
3434    
3435    
3436    void
3437    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3438    {
3439            seamless_window *sw;
3440    
3441            if (!g_seamless_active)
3442                    return;
3443    
3444            sw = seamless_get_window_by_id(id);
3445            if (!sw)
3446            {
3447                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3448                    return;
3449            }
3450    
3451            switch (state)
3452            {
3453                    case SEAMLESSRDP_NORMAL:
3454                    case SEAMLESSRDP_MAXIMIZED:
3455                            ewmh_change_state(sw->wnd, state);
3456                            XMapWindow(g_display, sw->wnd);
3457                            break;
3458                    case SEAMLESSRDP_MINIMIZED:
3459                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3460                               the Window Manager should probably just ignore the request, since
3461                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3462                               such as minimization, rather than an independent state." Besides,
3463                               XIconifyWindow is easier. */
3464                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3465                            {
3466                                    XWMHints *hints;
3467                                    hints = XAllocWMHints();
3468                                    hints->flags = StateHint;
3469                                    hints->initial_state = IconicState;
3470                                    XSetWMHints(g_display, sw->wnd, hints);
3471                                    XFree(hints);
3472                                    XMapWindow(g_display, sw->wnd);
3473                            }
3474                            else
3475                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3476                            break;
3477                    default:
3478                            warning("SeamlessRDP: Invalid state %d\n", state);
3479                            break;
3480            }
3481    
3482            sw->state = state;
3483    }
3484    
3485    
3486    void
3487    ui_seamless_syncbegin(unsigned long flags)
3488    {
3489            if (!g_seamless_active)
3490                    return;
3491    
3492            /* Destroy all seamless windows */
3493            while (g_seamless_windows)
3494            {
3495                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3496                    seamless_remove_window(g_seamless_windows);
3497            }
3498    }
3499    
3500    void
3501    ui_seamless_ack(unsigned int serial)
3502    {
3503            seamless_window *sw;
3504            for (sw = g_seamless_windows; sw; sw = sw->next)
3505            {
3506                    if (sw->outpos_serial == serial)
3507                    {
3508                            sw->xoffset = sw->outpos_xoffset;
3509                            sw->yoffset = sw->outpos_yoffset;
3510                            sw->width = sw->outpos_width;
3511                            sw->height = sw->outpos_height;
3512    
3513                            sw->outstanding_position = False;
3514    
3515                            break;
3516                    }
3517            }
3518    
3519            return;
3520    }

Legend:
Removed from v.823  
changed lines
  Added in v.1168

  ViewVC Help
Powered by ViewVC 1.1.26