/[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 976 by astrand, Thu Aug 4 13:39:57 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1155 by ossman_, Fri Mar 17 10:48:11 2006 UTC
# Line 38  extern BOOL g_fullscreen; Line 38  extern BOOL g_fullscreen;
38  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
39  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
40  extern char g_title[];  extern char g_title[];
41  extern int g_server_bpp;  /* Color depth of the RDP session.
42       As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44  extern int g_win_button_size;  extern int g_win_button_size;
45    
46  Display *g_display;  Display *g_display;
# Line 46  Time g_last_gesturetime; Line 48  Time g_last_gesturetime;
48  static int g_x_socket;  static int g_x_socket;
49  static Screen *g_screen;  static Screen *g_screen;
50  Window g_wnd;  Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            unsigned long parent;
58            unsigned long behind;
59            int xoffset, yoffset;
60            int width, height;
61            int state;              /* normal/minimized/maximized. */
62            unsigned int desktop;
63            struct _seamless_window *next;
64    } seamless_window;
65    static seamless_window *g_seamless_windows = NULL;
66    static unsigned long g_seamless_focused = 0;
67    static BOOL g_seamless_started = False; /* Server end is up and running */
68    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
69    extern BOOL g_seamless_rdp;
70    
71  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
72  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
73  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
74  static GC g_gc = NULL;  static GC g_gc = NULL;
75  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
76  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
77    static XRectangle g_clip_rectangle;
78  static Visual *g_visual;  static Visual *g_visual;
79    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
80       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
81       as far as we're concerned. */
82  static int g_depth;  static int g_depth;
83    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
84       This may be larger than g_depth, in which case some of the bits would
85       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
86  static int g_bpp;  static int g_bpp;
87  static XIM g_IM;  static XIM g_IM;
88  static XIC g_IC;  static XIC g_IC;
# Line 61  static XModifierKeymap *g_mod_map; Line 90  static XModifierKeymap *g_mod_map;
90  static Cursor g_current_cursor;  static Cursor g_current_cursor;
91  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
92  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
93    extern Atom g_net_wm_state_atom;
94    extern Atom g_net_wm_desktop_atom;
95  static BOOL g_focused;  static BOOL g_focused;
96  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
97  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
98       1) visual has 15, 16 or 24 depth and the same color channel masks
99          as its RDP equivalent (implies X server is LE),
100       2) host is LE
101       This will trigger an optimization whose real value is questionable.
102    */
103    static BOOL g_compatible_arch;
104    /* Indicates whether RDP's bitmaps and our XImages have the same
105       binary format. If so, we can avoid an expensive translation.
106       Note that this can be true when g_compatible_arch is false,
107       e.g.:
108      
109         RDP(LE) <-> host(BE) <-> X-Server(LE)
110        
111       ('host' is the machine running rdesktop; the host simply memcpy's
112        so its endianess doesn't matter)
113     */
114    static BOOL g_no_translate_image = False;
115    
116  /* endianness */  /* endianness */
117  static BOOL g_host_be;  static BOOL g_host_be;
# Line 79  static Pixmap g_backstore = 0; Line 127  static Pixmap g_backstore = 0;
127  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
128  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
129  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
130    static BOOL g_using_full_workarea = False;
131    
132  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
133  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 91  extern BOOL g_rdpsnd; Line 140  extern BOOL g_rdpsnd;
140  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
141  typedef struct  typedef struct
142  {  {
143          uint32 flags;          unsigned long flags;
144          uint32 functions;          unsigned long functions;
145          uint32 decorations;          unsigned long decorations;
146          sint32 inputMode;          long inputMode;
147          uint32 status;          unsigned long status;
148  }  }
149  PropMotifWmHints;  PropMotifWmHints;
150    
# Line 107  typedef struct Line 156  typedef struct
156  }  }
157  PixelColour;  PixelColour;
158    
159    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
160            do { \
161                    seamless_window *sw; \
162                    XRectangle rect; \
163                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
164                        rect.x = g_clip_rectangle.x - sw->xoffset; \
165                        rect.y = g_clip_rectangle.y - sw->yoffset; \
166                        rect.width = g_clip_rectangle.width; \
167                        rect.height = g_clip_rectangle.height; \
168                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
169                        func args; \
170                    } \
171                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
172            } while (0)
173    
174    static void
175    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
176    {
177            points[0].x -= xoffset;
178            points[0].y -= yoffset;
179            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
180            points[0].x += xoffset;
181            points[0].y += yoffset;
182    }
183    
184    static void
185    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
186    {
187            points[0].x -= xoffset;
188            points[0].y -= yoffset;
189            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
190            points[0].x += xoffset;
191            points[0].y += yoffset;
192    }
193    
194  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
195  { \  { \
196          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
197            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
198          if (g_ownbackstore) \          if (g_ownbackstore) \
199                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
200  }  }
# Line 125  PixelColour; Line 209  PixelColour;
209          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
210          if (g_ownbackstore) \          if (g_ownbackstore) \
211                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
212            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
213  }  }
214    
215  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 133  PixelColour; Line 218  PixelColour;
218          { \          { \
219                  case 0: /* Outline */ \                  case 0: /* Outline */ \
220                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
221                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
222                          if (g_ownbackstore) \                          if (g_ownbackstore) \
223                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
224                          break; \                          break; \
225                  case 1: /* Filled */ \                  case 1: /* Filled */ \
226                          XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
227                                   cx, cy, 0, 360*64); \                                   cx, cy, 0, 360*64); \
228                            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)); \
229                          if (g_ownbackstore) \                          if (g_ownbackstore) \
230                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \                                  XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
231                          break; \                          break; \
232          } \          } \
233  }  }
# Line 150  extern BOOL g_owncolmap; Line 237  extern BOOL g_owncolmap;
237  static Colormap g_xcolmap;  static Colormap g_xcolmap;
238  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
239    
240  #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] )
241  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
242  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
243    
# Line 176  static int rop2_map[] = { Line 263  static int rop2_map[] = {
263  #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]); }
264  #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); }
265    
266    static seamless_window *
267    seamless_get_window_by_id(unsigned long id)
268    {
269            seamless_window *sw;
270            for (sw = g_seamless_windows; sw; sw = sw->next)
271            {
272                    if (sw->id == id)
273                            return sw;
274            }
275            return NULL;
276    }
277    
278    
279    static seamless_window *
280    seamless_get_window_by_wnd(Window wnd)
281    {
282            seamless_window *sw;
283            for (sw = g_seamless_windows; sw; sw = sw->next)
284            {
285                    if (sw->wnd == wnd)
286                            return sw;
287            }
288            return NULL;
289    }
290    
291    
292    static void
293    seamless_remove_window(seamless_window * win)
294    {
295            seamless_window *sw, **prevnext = &g_seamless_windows;
296            for (sw = g_seamless_windows; sw; sw = sw->next)
297            {
298                    if (sw == win)
299                    {
300                            *prevnext = sw->next;
301                            xfree(sw);
302                            return;
303                    }
304                    prevnext = &sw->next;
305            }
306            return;
307    }
308    
309    
310    /* Move all windows except wnd to new desktop */
311    static void
312    seamless_all_to_desktop(Window wnd, unsigned int desktop)
313    {
314            seamless_window *sw;
315            for (sw = g_seamless_windows; sw; sw = sw->next)
316            {
317                    if (sw->wnd == wnd)
318                            continue;
319                    if (sw->desktop != desktop)
320                    {
321                            ewmh_move_to_desktop(sw->wnd, desktop);
322                            sw->desktop = desktop;
323                    }
324            }
325    }
326    
327    
328    static void
329    seamless_restack_window(seamless_window * sw, unsigned long behind)
330    {
331            seamless_window *sw_above;
332    
333            /* Remove window from stack */
334            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
335            {
336                    if (sw_above->behind == sw->id)
337                            break;
338            }
339    
340            if (sw_above)
341                    sw_above->behind = sw->behind;
342    
343            /* And then add it at the new position */
344    
345            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
346            {
347                    if (sw_above->behind == behind)
348                            break;
349            }
350    
351            if (sw_above)
352                    sw_above->behind = sw->id;
353    
354            sw->behind = behind;
355    }
356    
357    
358  static void  static void
359  mwm_hide_decorations(void)  mwm_hide_decorations(Window wnd)
360  {  {
361          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
362          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 373  mwm_hide_decorations(void)
373                  return;                  return;
374          }          }
375    
376          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
377                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
378    
379  }  }
380    
381  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 409  mwm_hide_decorations(void)
409  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
410                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
411    
412    /* The following macros output the same octet sequences
413       on both BE and LE hosts: */
414    
415  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
416  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
417  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
# Line 240  static uint32 Line 423  static uint32
423  translate_colour(uint32 colour)  translate_colour(uint32 colour)
424  {  {
425          PixelColour pc;          PixelColour pc;
426          switch (g_server_bpp)          switch (g_server_depth)
427          {          {
428                  case 15:                  case 15:
429                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 251  translate_colour(uint32 colour) Line 434  translate_colour(uint32 colour)
434                  case 24:                  case 24:
435                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
436                          break;                          break;
437                    default:
438                            /* Avoid warning */
439                            pc.red = 0;
440                            pc.green = 0;
441                            pc.blue = 0;
442                            break;
443          }          }
444          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
445  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 491  translate8to16(const uint8 * data, uint8
491  {  {
492          uint16 value;          uint16 value;
493    
494          if (g_arch_match)          if (g_compatible_arch)
495          {          {
496                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
497                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 525  translate8to24(const uint8 * data, uint8
525  {  {
526          uint32 value;          uint32 value;
527    
528          if (g_xserver_be)          if (g_compatible_arch)
529          {          {
530                  while (out < end)                  while (out < end)
531                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 548  translate8to32(const uint8 * data, uint8
548  {  {
549          uint32 value;          uint32 value;
550    
551          if (g_arch_match)          if (g_compatible_arch)
552          {          {
553                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
554                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 620  translate15to24(const uint16 * data, uin
620          uint16 pixel;          uint16 pixel;
621          PixelColour pc;          PixelColour pc;
622    
623          if (g_arch_match)          if (g_compatible_arch)
624          {          {
625                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
626                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 670  translate15to32(const uint16 * data, uin
670          uint32 value;          uint32 value;
671          PixelColour pc;          PixelColour pc;
672    
673          if (g_arch_match)          if (g_compatible_arch)
674          {          {
675                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
676                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 778  translate16to24(const uint16 * data, uin
778          uint16 pixel;          uint16 pixel;
779          PixelColour pc;          PixelColour pc;
780    
781          if (g_arch_match)          if (g_compatible_arch)
782          {          {
783                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
784                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 848  translate16to32(const uint16 * data, uin
848          uint32 value;          uint32 value;
849          PixelColour pc;          PixelColour pc;
850    
851          if (g_arch_match)          if (g_compatible_arch)
852          {          {
853                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
854                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 977  translate24to32(const uint8 * data, uint
977          uint32 value;          uint32 value;
978          PixelColour pc;          PixelColour pc;
979    
980          if (g_arch_match)          if (g_compatible_arch)
981          {          {
982                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
983  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 991  translate24to32(const uint8 * data, uint
991  #else  #else
992                  REPEAT4                  REPEAT4
993                  (                  (
994                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
995                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
996                          data += 3;                   out += 4;
997                     data += 3;
998                  )                  )
999  #endif  #endif
1000                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 842  translate_image(int width, int height, u Line 1032  translate_image(int width, int height, u
1032          uint8 *out;          uint8 *out;
1033          uint8 *end;          uint8 *end;
1034    
1035          /* if server and xserver bpp match, */          /*
1036          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1037          /* just return data */             and arch(endian) matches, no need to translate:
1038          if (g_arch_match)             just return data.
1039               Note: select_visual should've already ensured g_no_translate
1040               is only set for compatible depths, but the RDP depth might've
1041               changed during connection negotiations.
1042             */
1043            if (g_no_translate_image)
1044          {          {
1045                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1046                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1047                  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)  
1048                          return data;                          return data;
1049          }          }
1050    
# Line 859  translate_image(int width, int height, u Line 1052  translate_image(int width, int height, u
1052          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1053          end = out + size;          end = out + size;
1054    
1055          switch (g_server_bpp)          switch (g_server_depth)
1056          {          {
1057                  case 24:                  case 24:
1058                          switch (g_bpp)                          switch (g_bpp)
# Line 957  calculate_shifts(uint32 mask, int *shift Line 1150  calculate_shifts(uint32 mask, int *shift
1150          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1151  }  }
1152    
1153  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1154  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1155     */
1156    static unsigned
1157    calculate_mask_weight(uint32 mask)
1158    {
1159            unsigned weight = 0;
1160            do
1161            {
1162                    weight += (mask & 1);
1163            }
1164            while (mask >>= 1);
1165            return weight;
1166    }
1167    
1168    static BOOL
1169    select_visual()
1170  {  {
         XVisualInfo vi;  
1171          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1172          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1173          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1174          XVisualInfo template;          XVisualInfo template;
1175          Bool TrueColorVisual = False;          int i;
1176            unsigned red_weight, blue_weight, green_weight;
1177    
1178          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1179          if (g_display == NULL)  
1180            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1181            if (pfm == NULL)
1182          {          {
1183                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1184                    XCloseDisplay(g_display);
1185                  return False;                  return False;
1186          }          }
1187    
1188          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 */  
1189          template.class = TrueColor;          template.class = TrueColor;
1190          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1191            g_visual = NULL;
1192            g_no_translate_image = False;
1193            g_compatible_arch = False;
1194            if (vmatches != NULL)
1195            {
1196                    for (i = 0; i < visuals_count; ++i)
1197                    {
1198                            XVisualInfo *visual_info = &vmatches[i];
1199    
1200                            /* Try to find a no-translation visual that'll
1201                               allow us to use RDP bitmaps directly as ZPixmaps. */
1202                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1203                                                   /* R5G5B5 */
1204                                                   (visual_info->red_mask == 0x7c00) &&
1205                                                   (visual_info->green_mask == 0x3e0) &&
1206                                                   (visual_info->blue_mask == 0x1f)) ||
1207                                                  ((visual_info->depth == 16) &&
1208                                                   /* R5G6B5 */
1209                                                   (visual_info->red_mask == 0xf800) &&
1210                                                   (visual_info->green_mask == 0x7e0) &&
1211                                                   (visual_info->blue_mask == 0x1f)) ||
1212                                                  ((visual_info->depth == 24) &&
1213                                                   /* R8G8B8 */
1214                                                   (visual_info->red_mask == 0xff0000) &&
1215                                                   (visual_info->green_mask == 0xff00) &&
1216                                                   (visual_info->blue_mask == 0xff))))
1217                            {
1218                                    g_visual = visual_info->visual;
1219                                    g_depth = visual_info->depth;
1220                                    g_compatible_arch = !g_host_be;
1221                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1222                                    if (g_no_translate_image)
1223                                            /* We found the best visual */
1224                                            break;
1225                            }
1226                            else
1227                            {
1228                                    g_compatible_arch = False;
1229                            }
1230    
1231          nvisuals--;                          if (visual_info->depth > 24)
1232          while (nvisuals >= 0)                          {
1233          {                                  /* Avoid 32-bit visuals and likes like the plague.
1234                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1235                  {                                     (e.g. nvidia's Composite 32-bit visual).
1236                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1237                                    continue;
1238                            }
1239    
1240                            /* Only care for visuals, for whose BPPs (not depths!)
1241                               we have a translateXtoY function. */
1242                            BOOL can_translate_to_bpp = False;
1243                            int j;
1244                            for (j = 0; j < pixmap_formats_count; ++j)
1245                            {
1246                                    if (pfm[j].depth == visual_info->depth)
1247                                    {
1248                                            if ((pfm[j].bits_per_pixel == 16) ||
1249                                                (pfm[j].bits_per_pixel == 24) ||
1250                                                (pfm[j].bits_per_pixel == 32))
1251                                            {
1252                                                    can_translate_to_bpp = True;
1253                                            }
1254                                            break;
1255                                    }
1256                            }
1257    
1258                            /* Prefer formats which have the most colour depth.
1259                               We're being truly aristocratic here, minding each
1260                               weight on its own. */
1261                            if (can_translate_to_bpp)
1262                            {
1263                                    unsigned vis_red_weight =
1264                                            calculate_mask_weight(visual_info->red_mask);
1265                                    unsigned vis_green_weight =
1266                                            calculate_mask_weight(visual_info->green_mask);
1267                                    unsigned vis_blue_weight =
1268                                            calculate_mask_weight(visual_info->blue_mask);
1269                                    if ((vis_red_weight >= red_weight)
1270                                        && (vis_green_weight >= green_weight)
1271                                        && (vis_blue_weight >= blue_weight))
1272                                    {
1273                                            red_weight = vis_red_weight;
1274                                            green_weight = vis_green_weight;
1275                                            blue_weight = vis_blue_weight;
1276                                            g_visual = visual_info->visual;
1277                                            g_depth = visual_info->depth;
1278                                    }
1279                            }
1280                  }                  }
1281                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1282          }          }
1283    
1284          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)))  
1285          {          {
1286                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1287                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1288                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1289                    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;  
                 }  
1290          }          }
1291          else          else
1292          {          {
1293                  /* need a truecolour visual */                  template.class = PseudoColor;
1294                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1295                  {                  template.colormap_size = 256;
1296                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1297                            XGetVisualInfo(g_display,
1298                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1299                                           &template, &visuals_count);
1300                    if (vmatches == NULL)
1301                    {
1302                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1303                            XCloseDisplay(g_display);
1304                            XFree(pfm);
1305                          return False;                          return False;
1306                  }                  }
1307    
1308                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1309                  g_owncolmap = False;                  g_owncolmap = True;
1310                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1311                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1312                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1313    
1314                  /* if RGB video and everything is little endian */          g_bpp = 0;
1315                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1316                      !g_xserver_be && !g_host_be)          {
1317                    XPixmapFormatValues *pf = &pfm[i];
1318                    if (pf->depth == g_depth)
1319                  {                  {
1320                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1321                                                g_blue_shift_l == 0))  
1322                            if (g_no_translate_image)
1323                          {                          {
1324                                  g_arch_match = True;                                  switch (g_server_depth)
1325                                    {
1326                                            case 15:
1327                                            case 16:
1328                                                    if (g_bpp != 16)
1329                                                            g_no_translate_image = False;
1330                                                    break;
1331                                            case 24:
1332                                                    /* Yes, this will force image translation
1333                                                       on most modern servers which use 32 bits
1334                                                       for R8G8B8. */
1335                                                    if (g_bpp != 24)
1336                                                            g_no_translate_image = False;
1337                                                    break;
1338                                            default:
1339                                                    g_no_translate_image = False;
1340                                                    break;
1341                                    }
1342                          }                          }
                 }  
1343    
1344                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1345                  {                             there's just a single entry for every depth,
1346                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1347                            break;
1348                  }                  }
1349          }          }
1350            XFree(pfm);
1351            pfm = NULL;
1352            return True;
1353    }
1354    
1355    BOOL
1356    ui_init(void)
1357    {
1358            int screen_num;
1359    
1360          pfm = XListPixmapFormats(g_display, &i);          g_display = XOpenDisplay(NULL);
1361          if (pfm != NULL)          if (g_display == NULL)
1362          {          {
1363                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1364                     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);  
1365          }          }
1366    
         if (g_bpp < 8)  
1367          {          {
1368                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1369                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1370            }
1371    
1372            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1373            screen_num = DefaultScreen(g_display);
1374            g_x_socket = ConnectionNumber(g_display);
1375            g_screen = ScreenOfDisplay(g_display, screen_num);
1376            g_depth = DefaultDepthOfScreen(g_screen);
1377    
1378            if (!select_visual())
1379                  return False;                  return False;
1380    
1381            if (g_no_translate_image)
1382            {
1383                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1384          }          }
1385    
1386            if (g_server_depth > g_bpp)
1387            {
1388                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1389                            g_server_depth, g_bpp);
1390            }
1391    
1392            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1393                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1394    
1395          if (!g_owncolmap)          if (!g_owncolmap)
1396          {          {
1397                  g_xcolmap =                  g_xcolmap =
1398                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1399                                          AllocNone);                                          AllocNone);
1400                  if (g_depth <= 8)                  if (g_depth <= 8)
1401                          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);
1402          }          }
1403    
1404          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1405          {          {
1406                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1407                  g_ownbackstore = True;                  g_ownbackstore = True;
1408          }          }
1409    
# Line 1087  ui_init(void) Line 1414  ui_init(void)
1414          {          {
1415                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1416                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1417                    g_using_full_workarea = True;
1418          }          }
1419          else if (g_width < 0)          else if (g_width < 0)
1420          {          {
1421                  /* Percent of screen */                  /* Percent of screen */
1422                    if (-g_width >= 100)
1423                            g_using_full_workarea = True;
1424                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1425                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1426          }          }
# Line 1098  ui_init(void) Line 1428  ui_init(void)
1428          {          {
1429                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1430                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1431                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1432                  {                  {
1433                          g_width = cx;                          g_width = cx;
1434                          g_height = cy;                          g_height = cy;
1435                            g_using_full_workarea = True;
1436                  }                  }
1437                  else                  else
1438                  {                  {
1439                          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");
1440                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1441                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1442                  }                  }
1443          }          }
1444    
# Line 1123  ui_init(void) Line 1453  ui_init(void)
1453                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1454    
1455          xclip_init();          xclip_init();
1456            ewmh_init();
1457            if (g_seamless_rdp)
1458                    seamless_init();
1459    
1460          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));
1461    
1462          return True;          return True;
1463  }  }
# Line 1148  ui_deinit(void) Line 1481  ui_deinit(void)
1481          g_display = NULL;          g_display = NULL;
1482  }  }
1483    
1484    
1485    static void
1486    get_window_attribs(XSetWindowAttributes * attribs)
1487    {
1488            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1489            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1490            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1491            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1492            attribs->override_redirect = g_fullscreen;
1493            attribs->colormap = g_xcolmap;
1494    }
1495    
1496    static void
1497    get_input_mask(long *input_mask)
1498    {
1499            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1500                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1501    
1502            if (g_sendmotion)
1503                    *input_mask |= PointerMotionMask;
1504            if (g_ownbackstore)
1505                    *input_mask |= ExposureMask;
1506            if (g_fullscreen || g_grab_keyboard)
1507                    *input_mask |= EnterWindowMask;
1508            if (g_grab_keyboard)
1509                    *input_mask |= LeaveWindowMask;
1510    }
1511    
1512  BOOL  BOOL
1513  ui_create_window(void)  ui_create_window(void)
1514  {  {
# Line 1170  ui_create_window(void) Line 1531  ui_create_window(void)
1531          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1532                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1533    
1534          attribs.background_pixel = BlackPixelOfScreen(g_screen);          get_window_attribs(&attribs);
         attribs.border_pixel = WhitePixelOfScreen(g_screen);  
         attribs.backing_store = g_ownbackstore ? NotUseful : Always;  
         attribs.override_redirect = g_fullscreen;  
         attribs.colormap = g_xcolmap;  
1535    
1536          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,
1537                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1182  ui_create_window(void) Line 1539  ui_create_window(void)
1539                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1540    
1541          if (g_gc == NULL)          if (g_gc == NULL)
1542            {
1543                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1544                    ui_reset_clip();
1545            }
1546    
1547          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1548                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1199  ui_create_window(void) Line 1559  ui_create_window(void)
1559          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1560    
1561          if (g_hide_decorations)          if (g_hide_decorations)
1562                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1563    
1564          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1565          if (classhints != NULL)          if (classhints != NULL)
# Line 1226  ui_create_window(void) Line 1586  ui_create_window(void)
1586                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1587          }          }
1588    
1589          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;  
   
         if (g_sendmotion)  
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
1590    
1591          if (g_IM != NULL)          if (g_IM != NULL)
1592          {          {
# Line 1249  ui_create_window(void) Line 1599  ui_create_window(void)
1599          }          }
1600    
1601          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1602    
1603            XMapWindow(g_display, g_wnd);
1604          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1605          do          do
1606          {          {
# Line 1321  xwin_toggle_fullscreen(void) Line 1671  xwin_toggle_fullscreen(void)
1671  {  {
1672          Pixmap contents = 0;          Pixmap contents = 0;
1673    
1674            if (g_seamless_active)
1675                    /* Turn off SeamlessRDP mode */
1676                    ui_seamless_toggle();
1677    
1678          if (!g_ownbackstore)          if (!g_ownbackstore)
1679          {          {
1680                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1341  xwin_toggle_fullscreen(void) Line 1695  xwin_toggle_fullscreen(void)
1695          }          }
1696  }  }
1697    
1698    static void
1699    handle_button_event(XEvent xevent, BOOL down)
1700    {
1701            uint16 button, flags = 0;
1702            g_last_gesturetime = xevent.xbutton.time;
1703            button = xkeymap_translate_button(xevent.xbutton.button);
1704            if (button == 0)
1705                    return;
1706    
1707            if (down)
1708                    flags = MOUSE_FLAG_DOWN;
1709    
1710            /* Stop moving window when button is released, regardless of cursor position */
1711            if (g_moving_wnd && (xevent.type == ButtonRelease))
1712                    g_moving_wnd = False;
1713    
1714            /* If win_button_size is nonzero, enable single app mode */
1715            if (xevent.xbutton.y < g_win_button_size)
1716            {
1717                    /*  Check from right to left: */
1718                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1719                    {
1720                            /* The close button, continue */
1721                            ;
1722                    }
1723                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1724                    {
1725                            /* The maximize/restore button. Do not send to
1726                               server.  It might be a good idea to change the
1727                               cursor or give some other visible indication
1728                               that rdesktop inhibited this click */
1729                            if (xevent.type == ButtonPress)
1730                                    return;
1731                    }
1732                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1733                    {
1734                            /* The minimize button. Iconify window. */
1735                            if (xevent.type == ButtonRelease)
1736                            {
1737                                    /* Release the mouse button outside the minimize button, to prevent the
1738                                       actual minimazation to happen */
1739                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1740                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1741                                    return;
1742                            }
1743                    }
1744                    else if (xevent.xbutton.x <= g_win_button_size)
1745                    {
1746                            /* The system menu. Ignore. */
1747                            if (xevent.type == ButtonPress)
1748                                    return;
1749                    }
1750                    else
1751                    {
1752                            /* The title bar. */
1753                            if (xevent.type == ButtonPress)
1754                            {
1755                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1756                                    {
1757                                            g_moving_wnd = True;
1758                                            g_move_x_offset = xevent.xbutton.x;
1759                                            g_move_y_offset = xevent.xbutton.y;
1760                                    }
1761                                    return;
1762                            }
1763                    }
1764            }
1765    
1766            if (xevent.xmotion.window == g_wnd)
1767            {
1768                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1769                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1770            }
1771            else
1772            {
1773                    /* SeamlessRDP */
1774                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1775                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1776            }
1777    }
1778    
1779    static void
1780    ui_seamless_handle_restack(seamless_window * sw)
1781    {
1782            Status status;
1783            Window root, parent, *children;
1784            unsigned int nchildren, i;
1785            seamless_window *sw_below;
1786    
1787            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1788                                &root, &parent, &children, &nchildren);
1789            if (!status || !nchildren)
1790                    return;
1791    
1792            sw_below = NULL;
1793    
1794            i = 0;
1795            while (children[i] != sw->wnd)
1796            {
1797                    i++;
1798                    if (i >= nchildren)
1799                            return;
1800            }
1801    
1802            for (i++; i < nchildren; i++)
1803            {
1804                    sw_below = seamless_get_window_by_wnd(children[i]);
1805                    if (sw_below)
1806                            break;
1807            }
1808    
1809            if (!sw_below && !sw->behind)
1810                    return;
1811            if (sw_below && (sw_below->id == sw->behind))
1812                    return;
1813    
1814            if (sw_below)
1815            {
1816                    seamless_send_zchange(sw->id, sw_below->id, 0);
1817                    seamless_restack_window(sw, sw_below->id);
1818            }
1819            else
1820            {
1821                    seamless_send_zchange(sw->id, 0, 0);
1822                    seamless_restack_window(sw, 0);
1823            }
1824    }
1825    
1826  /* Process events in Xlib queue  /* Process events in Xlib queue
1827     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1828  static int  static int
# Line 1348  xwin_process_events(void) Line 1830  xwin_process_events(void)
1830  {  {
1831          XEvent xevent;          XEvent xevent;
1832          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1833          uint32 ev_time;          uint32 ev_time;
1834          char str[256];          char str[256];
1835          Status status;          Status status;
1836          int events = 0;          int events = 0;
1837            seamless_window *sw;
1838    
1839          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1840          {          {
# Line 1364  xwin_process_events(void) Line 1846  xwin_process_events(void)
1846                          continue;                          continue;
1847                  }                  }
1848    
                 flags = 0;  
   
1849                  switch (xevent.type)                  switch (xevent.type)
1850                  {                  {
1851                          case VisibilityNotify:                          case VisibilityNotify:
1852                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1853                                            g_Unobscured =
1854                                                    xevent.xvisibility.state == VisibilityUnobscured;
1855    
1856                                  break;                                  break;
1857                          case ClientMessage:                          case ClientMessage:
1858                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1430  xwin_process_events(void) Line 1913  xwin_process_events(void)
1913                                  break;                                  break;
1914    
1915                          case ButtonPress:                          case ButtonPress:
1916                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1917                                  /* fall through */                                  break;
1918    
1919                          case ButtonRelease:                          case ButtonRelease:
1920                                  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);  
1921                                  break;                                  break;
1922    
1923                          case MotionNotify:                          case MotionNotify:
# Line 1506  xwin_process_events(void) Line 1932  xwin_process_events(void)
1932                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1933                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1934                                                         CurrentTime);                                                         CurrentTime);
1935                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1936                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1937                                    {
1938                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1939                                                           xevent.xmotion.x, xevent.xmotion.y);
1940                                    }
1941                                    else
1942                                    {
1943                                            /* SeamlessRDP */
1944                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1945                                                           xevent.xmotion.x_root,
1946                                                           xevent.xmotion.y_root);
1947                                    }
1948                                  break;                                  break;
1949    
1950                          case FocusIn:                          case FocusIn:
# Line 1518  xwin_process_events(void) Line 1955  xwin_process_events(void)
1955                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
1956                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
1957                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
1958    
1959                                    sw = seamless_get_window_by_wnd(xevent.xfocus.window);
1960                                    if (!sw)
1961                                            break;
1962    
1963                                    if (sw->id != g_seamless_focused)
1964                                    {
1965                                            seamless_send_focus(sw->id, 0);
1966                                            g_seamless_focused = sw->id;
1967                                    }
1968                                  break;                                  break;
1969    
1970                          case FocusOut:                          case FocusOut:
# Line 1550  xwin_process_events(void) Line 1997  xwin_process_events(void)
1997                                  break;                                  break;
1998    
1999                          case Expose:                          case Expose:
2000                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2001                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2002                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2003                                            xevent.xexpose.height,                                                    g_gc,
2004                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2005                                                      xevent.xexpose.width, xevent.xexpose.height,
2006                                                      xevent.xexpose.x, xevent.xexpose.y);
2007                                    }
2008                                    else
2009                                    {
2010                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
2011                                            if (sw)
2012                                                    XCopyArea(g_display, g_backstore,
2013                                                              xevent.xexpose.window, g_gc,
2014                                                              xevent.xexpose.x + sw->xoffset,
2015                                                              xevent.xexpose.y + sw->yoffset,
2016                                                              xevent.xexpose.width,
2017                                                              xevent.xexpose.height, xevent.xexpose.x,
2018                                                              xevent.xexpose.y);
2019                                            else
2020                                            {
2021                                                    error("Expose for unknown window 0x%lx\n",
2022                                                          xevent.xexpose.window);
2023                                            }
2024                                    }
2025    
2026                                  break;                                  break;
2027    
2028                          case MappingNotify:                          case MappingNotify:
# Line 1583  xwin_process_events(void) Line 2051  xwin_process_events(void)
2051                                  break;                                  break;
2052                          case PropertyNotify:                          case PropertyNotify:
2053                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2054                                    if (xevent.xproperty.window == g_wnd)
2055                                            break;
2056                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2057                                            break;
2058    
2059                                    /* seamless */
2060                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2061                                    if (!sw)
2062                                            break;
2063    
2064                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2065                                        && (xevent.xproperty.state == PropertyNewValue))
2066                                    {
2067                                            sw->state = ewmh_get_window_state(sw->wnd);
2068                                            seamless_send_state(sw->id, sw->state, 0);
2069                                    }
2070    
2071                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2072                                        && (xevent.xproperty.state == PropertyNewValue))
2073                                    {
2074                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2075                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
2076                                    }
2077    
2078                                  break;                                  break;
2079                          case MapNotify:                          case MapNotify:
2080                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2081                                            rdp_send_client_window_status(1);
2082                                  break;                                  break;
2083                          case UnmapNotify:                          case UnmapNotify:
2084                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2085                                            rdp_send_client_window_status(0);
2086                                  break;                                  break;
2087                            case ConfigureNotify:
2088                                    /* seamless */
2089                                    sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2090                                    if (!sw)
2091                                            break;
2092    
2093                                    ui_seamless_handle_restack(sw);
2094                  }                  }
2095          }          }
2096          /* Keep going */          /* Keep going */
# Line 1673  ui_create_bitmap(int width, int height, Line 2174  ui_create_bitmap(int width, int height,
2174          uint8 *tdata;          uint8 *tdata;
2175          int bitmap_pad;          int bitmap_pad;
2176    
2177          if (g_server_bpp == 8)          if (g_server_depth == 8)
2178          {          {
2179                  bitmap_pad = 8;                  bitmap_pad = 8;
2180          }          }
# Line 1705  ui_paint_bitmap(int x, int y, int cx, in Line 2206  ui_paint_bitmap(int x, int y, int cx, in
2206          uint8 *tdata;          uint8 *tdata;
2207          int bitmap_pad;          int bitmap_pad;
2208    
2209          if (g_server_bpp == 8)          if (g_server_depth == 8)
2210          {          {
2211                  bitmap_pad = 8;                  bitmap_pad = 8;
2212          }          }
# Line 1725  ui_paint_bitmap(int x, int y, int cx, in Line 2226  ui_paint_bitmap(int x, int y, int cx, in
2226          {          {
2227                  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);
2228                  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);
2229                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2230                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2231                                             x - sw->xoffset, y - sw->yoffset));
2232          }          }
2233          else          else
2234          {          {
2235                  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);
2236                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2237                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2238                                             x - sw->xoffset, y - sw->yoffset));
2239          }          }
2240    
2241          XFree(image);          XFree(image);
# Line 1849  ui_set_cursor(HCURSOR cursor) Line 2356  ui_set_cursor(HCURSOR cursor)
2356  {  {
2357          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2358          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2359            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2360  }  }
2361    
2362  void  void
# Line 1990  ui_set_colourmap(HCOLOURMAP map) Line 2498  ui_set_colourmap(HCOLOURMAP map)
2498                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2499          }          }
2500          else          else
2501            {
2502                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2503                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2504            }
2505  }  }
2506    
2507  void  void
2508  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2509  {  {
2510          XRectangle rect;          g_clip_rectangle.x = x;
2511            g_clip_rectangle.y = y;
2512          rect.x = x;          g_clip_rectangle.width = cx;
2513          rect.y = y;          g_clip_rectangle.height = cy;
2514          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);  
2515  }  }
2516    
2517  void  void
2518  ui_reset_clip(void)  ui_reset_clip(void)
2519  {  {
2520          XRectangle rect;          g_clip_rectangle.x = 0;
2521            g_clip_rectangle.y = 0;
2522          rect.x = 0;          g_clip_rectangle.width = g_width;
2523          rect.y = 0;          g_clip_rectangle.height = g_height;
2524          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);  
2525  }  }
2526    
2527  void  void
# Line 2095  ui_patblt(uint8 opcode, Line 2602  ui_patblt(uint8 opcode,
2602    
2603          if (g_ownbackstore)          if (g_ownbackstore)
2604                  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);
2605            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2606                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2607                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2608  }  }
2609    
2610  void  void
# Line 2105  ui_screenblt(uint8 opcode, Line 2615  ui_screenblt(uint8 opcode,
2615          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2616          if (g_ownbackstore)          if (g_ownbackstore)
2617          {          {
2618                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2619                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2620                          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);  
                 }  
2621          }          }
2622          else          else
2623          {          {
2624                  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);
2625          }          }
2626    
2627            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2628                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2629                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2630    
2631          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2632  }  }
2633    
# Line 2132  ui_memblt(uint8 opcode, Line 2638  ui_memblt(uint8 opcode,
2638  {  {
2639          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2640          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);
2641            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2642                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2643                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2644          if (g_ownbackstore)          if (g_ownbackstore)
2645                  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);
2646          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2178  ui_line(uint8 opcode, Line 2687  ui_line(uint8 opcode,
2687          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2688          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2689          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2690            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2691                                                startx - sw->xoffset, starty - sw->yoffset,
2692                                                endx - sw->xoffset, endy - sw->yoffset));
2693          if (g_ownbackstore)          if (g_ownbackstore)
2694                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2695          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2275  ui_polyline(uint8 opcode, Line 2787  ui_polyline(uint8 opcode,
2787          if (g_ownbackstore)          if (g_ownbackstore)
2788                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2789                             CoordModePrevious);                             CoordModePrevious);
2790    
2791            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2792                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2793    
2794          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2795  }  }
2796    
# Line 2430  ui_draw_text(uint8 font, uint8 flags, ui Line 2946  ui_draw_text(uint8 font, uint8 flags, ui
2946                  switch (text[i])                  switch (text[i])
2947                  {                  {
2948                          case 0xff:                          case 0xff:
2949                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2950                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
2951                                  {                                  {
2952                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2953                                          exit(1);                                          for (j = 0; j < length; j++)
2954                                                    fprintf(stderr, "%02x ", text[j]);
2955                                            fprintf(stderr, "\n");
2956                                            i = length = 0;
2957                                            break;
2958                                  }                                  }
2959                                    cache_put_text(text[i + 1], text, text[i + 2]);
2960                                    i += 3;
2961                                    length -= i;
2962                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2963                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2964                                  i = 0;                                  i = 0;
2965                                  break;                                  break;
2966    
2967                          case 0xfe:                          case 0xfe:
2968                                    /* At least one byte needs to follow */
2969                                    if (i + 2 > length)
2970                                    {
2971                                            warning("Skipping short 0xfe command:");
2972                                            for (j = 0; j < length; j++)
2973                                                    fprintf(stderr, "%02x ", text[j]);
2974                                            fprintf(stderr, "\n");
2975                                            i = length = 0;
2976                                            break;
2977                                    }
2978                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2979                                  if (entry != NULL)                                  if (entry->data != NULL)
2980                                  {                                  {
2981                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2982                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2983                                          {                                          {
2984                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2985                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2480  ui_draw_text(uint8 font, uint8 flags, ui Line 3011  ui_draw_text(uint8 font, uint8 flags, ui
3011          if (g_ownbackstore)          if (g_ownbackstore)
3012          {          {
3013                  if (boxcx > 1)                  if (boxcx > 1)
3014                    {
3015                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3016                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3017                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3018                                                    (g_display, g_backstore, sw->wnd, g_gc,
3019                                                     boxx, boxy,
3020                                                     boxcx, boxcy,
3021                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3022                    }
3023                  else                  else
3024                    {
3025                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3026                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3027                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3028                                                    (g_display, g_backstore, sw->wnd, g_gc,
3029                                                     clipx, clipy,
3030                                                     clipcx, clipcy, clipx - sw->xoffset,
3031                                                     clipy - sw->yoffset));
3032                    }
3033          }          }
3034  }  }
3035    
# Line 2530  ui_desktop_restore(uint32 offset, int x, Line 3075  ui_desktop_restore(uint32 offset, int x,
3075          {          {
3076                  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);
3077                  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);
3078                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3079                                            (g_display, g_backstore, sw->wnd, g_gc,
3080                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3081          }          }
3082          else          else
3083          {          {
3084                  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);
3085                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3086                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3087                                             x - sw->xoffset, y - sw->yoffset));
3088          }          }
3089    
3090          XFree(image);          XFree(image);
# Line 2549  void Line 3100  void
3100  ui_end_update(void)  ui_end_update(void)
3101  {  {
3102  }  }
3103    
3104    void
3105    ui_seamless_begin()
3106    {
3107            if (!g_seamless_rdp)
3108                    return;
3109    
3110            if (g_seamless_started)
3111                    return;
3112    
3113            g_seamless_started = True;
3114    
3115            ui_seamless_toggle();
3116    }
3117    
3118    void
3119    ui_seamless_toggle()
3120    {
3121            if (!g_seamless_rdp)
3122                    return;
3123    
3124            if (!g_seamless_started)
3125                    return;
3126    
3127            if (g_seamless_active)
3128            {
3129                    /* Deactivate */
3130                    while (g_seamless_windows)
3131                    {
3132                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3133                            seamless_remove_window(g_seamless_windows);
3134                    }
3135                    XMapWindow(g_display, g_wnd);
3136            }
3137            else
3138            {
3139                    /* Activate */
3140                    XUnmapWindow(g_display, g_wnd);
3141                    seamless_send_sync();
3142            }
3143    
3144            g_seamless_active = !g_seamless_active;
3145    }
3146    
3147    void
3148    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3149    {
3150            Window wnd;
3151            XSetWindowAttributes attribs;
3152            XClassHint *classhints;
3153            XSizeHints *sizehints;
3154            long input_mask;
3155            seamless_window *sw, *sw_parent;
3156    
3157            if (!g_seamless_active)
3158                    return;
3159    
3160            /* Ignore CREATEs for existing windows */
3161            sw = seamless_get_window_by_id(id);
3162            if (sw)
3163                    return;
3164    
3165            get_window_attribs(&attribs);
3166            attribs.override_redirect = False;
3167    
3168            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3169                                InputOutput, g_visual,
3170                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3171                                CWBorderPixel, &attribs);
3172    
3173            XStoreName(g_display, wnd, "SeamlessRDP");
3174            ewmh_set_wm_name(wnd, "SeamlessRDP");
3175    
3176            mwm_hide_decorations(wnd);
3177    
3178            classhints = XAllocClassHint();
3179            if (classhints != NULL)
3180            {
3181                    classhints->res_name = "rdesktop";
3182                    classhints->res_class = "SeamlessRDP";
3183                    XSetClassHint(g_display, wnd, classhints);
3184                    XFree(classhints);
3185            }
3186    
3187            /* WM_NORMAL_HINTS */
3188            sizehints = XAllocSizeHints();
3189            if (sizehints != NULL)
3190            {
3191                    sizehints->flags = USPosition;
3192                    XSetWMNormalHints(g_display, wnd, sizehints);
3193                    XFree(sizehints);
3194            }
3195    
3196            /* Set WM_TRANSIENT_FOR, if necessary */
3197            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3198            {
3199                    sw_parent = seamless_get_window_by_id(parent);
3200                    if (sw_parent)
3201                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3202                    else
3203                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3204            }
3205    
3206    
3207            /* FIXME: Support for Input Context:s */
3208    
3209            get_input_mask(&input_mask);
3210            input_mask |= PropertyChangeMask;
3211    
3212            XSelectInput(g_display, wnd, input_mask);
3213    
3214            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3215               seamless window, we could try to close the window on the
3216               serverside, instead of terminating rdesktop */
3217            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3218    
3219            sw = malloc(sizeof(seamless_window));
3220            sw->wnd = wnd;
3221            sw->id = id;
3222            sw->parent = parent;
3223            sw->behind = 0;
3224            sw->xoffset = 0;
3225            sw->yoffset = 0;
3226            sw->width = 0;
3227            sw->height = 0;
3228            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3229            sw->desktop = 0;
3230            sw->next = g_seamless_windows;
3231            g_seamless_windows = sw;
3232    }
3233    
3234    
3235    void
3236    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3237    {
3238            seamless_window *sw;
3239    
3240            if (!g_seamless_active)
3241                    return;
3242    
3243            sw = seamless_get_window_by_id(id);
3244            if (!sw)
3245            {
3246                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3247                    return;
3248            }
3249    
3250            XDestroyWindow(g_display, sw->wnd);
3251            seamless_remove_window(sw);
3252    }
3253    
3254    
3255    void
3256    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3257    {
3258            seamless_window *sw;
3259    
3260            if (!g_seamless_active)
3261                    return;
3262    
3263            sw = seamless_get_window_by_id(id);
3264            if (!sw)
3265            {
3266                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3267                    return;
3268            }
3269    
3270            if (!width || !height)
3271                    /* X11 windows must be at least 1x1 */
3272                    return;
3273    
3274            /* About MAX and MIN: Windows allows moving a window outside
3275               the desktop. This happens, for example, when maximizing an
3276               application. In this case, the position is set to something
3277               like -4,-4,1288,1032. Many WMs does not allow windows
3278               outside the desktop, however. Therefore, clip the window
3279               ourselves. */
3280            sw->xoffset = MAX(0, x);
3281            sw->yoffset = MAX(0, y);
3282            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3283            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3284    
3285            /* If we move the window in a maximized state, then KDE won't
3286               accept restoration */
3287            switch (sw->state)
3288            {
3289                    case SEAMLESSRDP_MINIMIZED:
3290                    case SEAMLESSRDP_MAXIMIZED:
3291                            return;
3292            }
3293    
3294            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3295            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3296    }
3297    
3298    void
3299    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3300    {
3301            seamless_window *sw;
3302    
3303            if (!g_seamless_active)
3304                    return;
3305    
3306            sw = seamless_get_window_by_id(id);
3307            if (!sw)
3308            {
3309                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3310                    return;
3311            }
3312    
3313            if (behind)
3314            {
3315                    seamless_window *sw_behind;
3316                    Window wnds[2];
3317    
3318                    sw_behind = seamless_get_window_by_id(behind);
3319                    if (!sw_behind)
3320                    {
3321                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3322                                    behind);
3323                            return;
3324                    }
3325    
3326                    wnds[1] = sw_behind->wnd;
3327                    wnds[0] = sw->wnd;
3328    
3329                    XRestackWindows(g_display, wnds, 2);
3330            }
3331            else
3332            {
3333                    XRaiseWindow(g_display, sw->wnd);
3334            }
3335    
3336            seamless_restack_window(sw, behind);
3337    }
3338    
3339    void
3340    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3341    {
3342            seamless_window *sw;
3343    
3344            if (!g_seamless_active)
3345                    return;
3346    
3347            sw = seamless_get_window_by_id(id);
3348            if (!sw)
3349            {
3350                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3351                    return;
3352            }
3353    
3354            /* FIXME: Might want to convert the name for non-EWMH WMs */
3355            XStoreName(g_display, sw->wnd, title);
3356            ewmh_set_wm_name(sw->wnd, title);
3357    }
3358    
3359    
3360    void
3361    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3362    {
3363            seamless_window *sw;
3364    
3365            if (!g_seamless_active)
3366                    return;
3367    
3368            sw = seamless_get_window_by_id(id);
3369            if (!sw)
3370            {
3371                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3372                    return;
3373            }
3374    
3375            switch (state)
3376            {
3377                    case SEAMLESSRDP_NORMAL:
3378                    case SEAMLESSRDP_MAXIMIZED:
3379                            ewmh_change_state(sw->wnd, state);
3380                            XMapWindow(g_display, sw->wnd);
3381                            break;
3382                    case SEAMLESSRDP_MINIMIZED:
3383                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3384                               the Window Manager should probably just ignore the request, since
3385                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3386                               such as minimization, rather than an independent state." Besides,
3387                               XIconifyWindow is easier. */
3388                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3389                            {
3390                                    XWMHints *hints;
3391                                    hints = XAllocWMHints();
3392                                    hints->flags = StateHint;
3393                                    hints->initial_state = IconicState;
3394                                    XSetWMHints(g_display, sw->wnd, hints);
3395                                    XFree(hints);
3396                                    XMapWindow(g_display, sw->wnd);
3397                            }
3398                            else
3399                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3400                            break;
3401                    default:
3402                            warning("SeamlessRDP: Invalid state %d\n", state);
3403                            break;
3404            }
3405    
3406            /* Handle popups without parents through some ewm hints */
3407            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3408                    ewmh_set_window_popup(sw->wnd);
3409    
3410            sw->state = state;
3411    }
3412    
3413    
3414    void
3415    ui_seamless_syncbegin(unsigned long flags)
3416    {
3417            if (!g_seamless_active)
3418                    return;
3419    
3420            /* Destroy all seamless windows */
3421            while (g_seamless_windows)
3422            {
3423                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3424                    seamless_remove_window(g_seamless_windows);
3425            }
3426    }

Legend:
Removed from v.976  
changed lines
  Added in v.1155

  ViewVC Help
Powered by ViewVC 1.1.26