/[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 843 by jdmeijer, Thu Mar 10 22:40:20 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1157 by astrand, Fri Mar 17 12:39:09 2006 UTC
# Line 32  extern int g_width; Line 32  extern int g_width;
32  extern int g_height;  extern int g_height;
33  extern int g_xpos;  extern int g_xpos;
34  extern int g_ypos;  extern int g_ypos;
35    extern int g_pos;
36  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
37  extern BOOL g_fullscreen;  extern BOOL g_fullscreen;
38  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
39  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
40  extern char g_title[];  extern char g_title[];
41  extern int g_server_bpp;  /* Color depth of the RDP session.
42       As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44  extern int g_win_button_size;  extern int g_win_button_size;
45    
46  Display *g_display;  Display *g_display;
# Line 45  Time g_last_gesturetime; Line 48  Time g_last_gesturetime;
48  static int g_x_socket;  static int g_x_socket;
49  static Screen *g_screen;  static Screen *g_screen;
50  Window g_wnd;  Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            unsigned long 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 timeval *position_timer;
64            struct _seamless_window *next;
65    } seamless_window;
66    static seamless_window *g_seamless_windows = NULL;
67    static unsigned long g_seamless_focused = 0;
68    static BOOL g_seamless_started = False; /* Server end is up and running */
69    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
70    extern BOOL g_seamless_rdp;
71    
72  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
73  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
74  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
75  static GC g_gc = NULL;  static GC g_gc = NULL;
76  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
77  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
78    static XRectangle g_clip_rectangle;
79  static Visual *g_visual;  static Visual *g_visual;
80    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
81       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
82       as far as we're concerned. */
83  static int g_depth;  static int g_depth;
84    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
85       This may be larger than g_depth, in which case some of the bits would
86       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
87  static int g_bpp;  static int g_bpp;
88  static XIM g_IM;  static XIM g_IM;
89  static XIC g_IC;  static XIC g_IC;
# Line 60  static XModifierKeymap *g_mod_map; Line 91  static XModifierKeymap *g_mod_map;
91  static Cursor g_current_cursor;  static Cursor g_current_cursor;
92  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
93  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
94    extern Atom g_net_wm_state_atom;
95    extern Atom g_net_wm_desktop_atom;
96  static BOOL g_focused;  static BOOL g_focused;
97  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
98  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
99       1) visual has 15, 16 or 24 depth and the same color channel masks
100          as its RDP equivalent (implies X server is LE),
101       2) host is LE
102       This will trigger an optimization whose real value is questionable.
103    */
104    static BOOL g_compatible_arch;
105    /* Indicates whether RDP's bitmaps and our XImages have the same
106       binary format. If so, we can avoid an expensive translation.
107       Note that this can be true when g_compatible_arch is false,
108       e.g.:
109      
110         RDP(LE) <-> host(BE) <-> X-Server(LE)
111        
112       ('host' is the machine running rdesktop; the host simply memcpy's
113        so its endianess doesn't matter)
114     */
115    static BOOL g_no_translate_image = False;
116    
117  /* endianness */  /* endianness */
118  static BOOL g_host_be;  static BOOL g_host_be;
# Line 78  static Pixmap g_backstore = 0; Line 128  static Pixmap g_backstore = 0;
128  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
129  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
130  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
131    static BOOL g_using_full_workarea = False;
132    
133  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
134  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 90  extern BOOL g_rdpsnd; Line 141  extern BOOL g_rdpsnd;
141  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
142  typedef struct  typedef struct
143  {  {
144          uint32 flags;          unsigned long flags;
145          uint32 functions;          unsigned long functions;
146          uint32 decorations;          unsigned long decorations;
147          sint32 inputMode;          long inputMode;
148          uint32 status;          unsigned long status;
149  }  }
150  PropMotifWmHints;  PropMotifWmHints;
151    
# Line 106  typedef struct Line 157  typedef struct
157  }  }
158  PixelColour;  PixelColour;
159    
160    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
161            do { \
162                    seamless_window *sw; \
163                    XRectangle rect; \
164                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
165                        rect.x = g_clip_rectangle.x - sw->xoffset; \
166                        rect.y = g_clip_rectangle.y - sw->yoffset; \
167                        rect.width = g_clip_rectangle.width; \
168                        rect.height = g_clip_rectangle.height; \
169                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
170                        func args; \
171                    } \
172                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
173            } while (0)
174    
175    static void
176    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
177    {
178            points[0].x -= xoffset;
179            points[0].y -= yoffset;
180            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
181            points[0].x += xoffset;
182            points[0].y += yoffset;
183    }
184    
185    static void
186    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
187    {
188            points[0].x -= xoffset;
189            points[0].y -= yoffset;
190            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
191            points[0].x += xoffset;
192            points[0].y += yoffset;
193    }
194    
195  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
196  { \  { \
197          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
198            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
199          if (g_ownbackstore) \          if (g_ownbackstore) \
200                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
201  }  }
# Line 124  PixelColour; Line 210  PixelColour;
210          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
211          if (g_ownbackstore) \          if (g_ownbackstore) \
212                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
213            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
214  }  }
215    
216  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 132  PixelColour; Line 219  PixelColour;
219          { \          { \
220                  case 0: /* Outline */ \                  case 0: /* Outline */ \
221                          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); \
222                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
223                          if (g_ownbackstore) \                          if (g_ownbackstore) \
224                                  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); \
225                          break; \                          break; \
226                  case 1: /* Filled */ \                  case 1: /* Filled */ \
227                          XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
228                                   cx, cy, 0, 360*64); \                                   cx, cy, 0, 360*64); \
229                            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)); \
230                          if (g_ownbackstore) \                          if (g_ownbackstore) \
231                                  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); \
232                          break; \                          break; \
233          } \          } \
234  }  }
# Line 149  extern BOOL g_owncolmap; Line 238  extern BOOL g_owncolmap;
238  static Colormap g_xcolmap;  static Colormap g_xcolmap;
239  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
240    
241  #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] )
242  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
243  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
244    
# Line 175  static int rop2_map[] = { Line 264  static int rop2_map[] = {
264  #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]); }
265  #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); }
266    
267    static seamless_window *
268    seamless_get_window_by_id(unsigned long id)
269    {
270            seamless_window *sw;
271            for (sw = g_seamless_windows; sw; sw = sw->next)
272            {
273                    if (sw->id == id)
274                            return sw;
275            }
276            return NULL;
277    }
278    
279    
280    static seamless_window *
281    seamless_get_window_by_wnd(Window wnd)
282    {
283            seamless_window *sw;
284            for (sw = g_seamless_windows; sw; sw = sw->next)
285            {
286                    if (sw->wnd == wnd)
287                            return sw;
288            }
289            return NULL;
290    }
291    
292    
293    static void
294    seamless_remove_window(seamless_window * win)
295    {
296            seamless_window *sw, **prevnext = &g_seamless_windows;
297            for (sw = g_seamless_windows; sw; sw = sw->next)
298            {
299                    if (sw == win)
300                    {
301                            *prevnext = sw->next;
302                            xfree(sw);
303                            return;
304                    }
305                    prevnext = &sw->next;
306            }
307            return;
308    }
309    
310    
311    /* Move all windows except wnd to new desktop */
312  static void  static void
313  mwm_hide_decorations(void)  seamless_all_to_desktop(Window wnd, unsigned int desktop)
314    {
315            seamless_window *sw;
316            for (sw = g_seamless_windows; sw; sw = sw->next)
317            {
318                    if (sw->wnd == wnd)
319                            continue;
320                    if (sw->desktop != desktop)
321                    {
322                            ewmh_move_to_desktop(sw->wnd, desktop);
323                            sw->desktop = desktop;
324                    }
325            }
326    }
327    
328    
329    /* Send our position */
330    static void
331    seamless_update_position(seamless_window * sw)
332    {
333            XWindowAttributes wa;
334            int x, y;
335            Window child_return;
336    
337            XGetWindowAttributes(g_display, sw->wnd, &wa);
338            XTranslateCoordinates(g_display, sw->wnd, wa.root,
339                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
340    
341            seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
342            sw->xoffset = x;
343            sw->yoffset = y;
344            sw->width = wa.width;
345            sw->height = wa.height;
346    }
347    
348    
349    /* Check if it's time to send our position */
350    static void
351    seamless_check_timers()
352    {
353            seamless_window *sw;
354            struct timeval now;
355    
356            gettimeofday(&now, NULL);
357            for (sw = g_seamless_windows; sw; sw = sw->next)
358            {
359                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
360                    {
361                            timerclear(sw->position_timer);
362                            seamless_update_position(sw);
363                    }
364            }
365    }
366    
367    
368    static void
369    seamless_restack_window(seamless_window * sw, unsigned long behind)
370    {
371            seamless_window *sw_above;
372    
373            /* Remove window from stack */
374            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
375            {
376                    if (sw_above->behind == sw->id)
377                            break;
378            }
379    
380            if (sw_above)
381                    sw_above->behind = sw->behind;
382    
383            /* And then add it at the new position */
384    
385            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
386            {
387                    if (sw_above->behind == behind)
388                            break;
389            }
390    
391            if (sw_above)
392                    sw_above->behind = sw->id;
393    
394            sw->behind = behind;
395    }
396    
397    
398    static void
399    mwm_hide_decorations(Window wnd)
400  {  {
401          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
402          Atom hintsatom;          Atom hintsatom;
# Line 193  mwm_hide_decorations(void) Line 413  mwm_hide_decorations(void)
413                  return;                  return;
414          }          }
415    
416          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
417                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
418    
419  }  }
420    
421  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 228  mwm_hide_decorations(void) Line 449  mwm_hide_decorations(void)
449  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
450                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
451    
452    /* The following macros output the same octet sequences
453       on both BE and LE hosts: */
454    
455  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
456  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
457  #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 239  static uint32 Line 463  static uint32
463  translate_colour(uint32 colour)  translate_colour(uint32 colour)
464  {  {
465          PixelColour pc;          PixelColour pc;
466          switch (g_server_bpp)          switch (g_server_depth)
467          {          {
468                  case 15:                  case 15:
469                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 250  translate_colour(uint32 colour) Line 474  translate_colour(uint32 colour)
474                  case 24:                  case 24:
475                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
476                          break;                          break;
477                    default:
478                            /* Avoid warning */
479                            pc.red = 0;
480                            pc.green = 0;
481                            pc.blue = 0;
482                            break;
483          }          }
484          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
485  }  }
# Line 301  translate8to16(const uint8 * data, uint8 Line 531  translate8to16(const uint8 * data, uint8
531  {  {
532          uint16 value;          uint16 value;
533    
534          if (g_arch_match)          if (g_compatible_arch)
535          {          {
536                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
537                  REPEAT2                  REPEAT2
# Line 335  translate8to24(const uint8 * data, uint8 Line 565  translate8to24(const uint8 * data, uint8
565  {  {
566          uint32 value;          uint32 value;
567    
568          if (g_xserver_be)          if (g_compatible_arch)
569          {          {
570                  while (out < end)                  while (out < end)
571                  {                  {
# Line 358  translate8to32(const uint8 * data, uint8 Line 588  translate8to32(const uint8 * data, uint8
588  {  {
589          uint32 value;          uint32 value;
590    
591          if (g_arch_match)          if (g_compatible_arch)
592          {          {
593                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
594                  REPEAT4                  REPEAT4
# Line 430  translate15to24(const uint16 * data, uin Line 660  translate15to24(const uint16 * data, uin
660          uint16 pixel;          uint16 pixel;
661          PixelColour pc;          PixelColour pc;
662    
663          if (g_arch_match)          if (g_compatible_arch)
664          {          {
665                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
666                  REPEAT3                  REPEAT3
# Line 480  translate15to32(const uint16 * data, uin Line 710  translate15to32(const uint16 * data, uin
710          uint32 value;          uint32 value;
711          PixelColour pc;          PixelColour pc;
712    
713          if (g_arch_match)          if (g_compatible_arch)
714          {          {
715                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
716                  REPEAT4                  REPEAT4
# Line 588  translate16to24(const uint16 * data, uin Line 818  translate16to24(const uint16 * data, uin
818          uint16 pixel;          uint16 pixel;
819          PixelColour pc;          PixelColour pc;
820    
821          if (g_arch_match)          if (g_compatible_arch)
822          {          {
823                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
824                  REPEAT3                  REPEAT3
# Line 658  translate16to32(const uint16 * data, uin Line 888  translate16to32(const uint16 * data, uin
888          uint32 value;          uint32 value;
889          PixelColour pc;          PixelColour pc;
890    
891          if (g_arch_match)          if (g_compatible_arch)
892          {          {
893                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
894                  REPEAT4                  REPEAT4
# Line 787  translate24to32(const uint8 * data, uint Line 1017  translate24to32(const uint8 * data, uint
1017          uint32 value;          uint32 value;
1018          PixelColour pc;          PixelColour pc;
1019    
1020          if (g_arch_match)          if (g_compatible_arch)
1021          {          {
1022                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1023  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 801  translate24to32(const uint8 * data, uint Line 1031  translate24to32(const uint8 * data, uint
1031  #else  #else
1032                  REPEAT4                  REPEAT4
1033                  (                  (
1034                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1035                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1036                          data += 3;                   out += 4;
1037                     data += 3;
1038                  )                  )
1039  #endif  #endif
1040                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 841  translate_image(int width, int height, u Line 1072  translate_image(int width, int height, u
1072          uint8 *out;          uint8 *out;
1073          uint8 *end;          uint8 *end;
1074    
1075          /* if server and xserver bpp match, */          /*
1076          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1077          /* just return data */             and arch(endian) matches, no need to translate:
1078          if (g_arch_match)             just return data.
1079               Note: select_visual should've already ensured g_no_translate
1080               is only set for compatible depths, but the RDP depth might've
1081               changed during connection negotiations.
1082             */
1083            if (g_no_translate_image)
1084          {          {
1085                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1086                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1087                  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)  
1088                          return data;                          return data;
1089          }          }
1090    
# Line 858  translate_image(int width, int height, u Line 1092  translate_image(int width, int height, u
1092          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1093          end = out + size;          end = out + size;
1094    
1095          switch (g_server_bpp)          switch (g_server_depth)
1096          {          {
1097                  case 24:                  case 24:
1098                          switch (g_bpp)                          switch (g_bpp)
# Line 956  calculate_shifts(uint32 mask, int *shift Line 1190  calculate_shifts(uint32 mask, int *shift
1190          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1191  }  }
1192    
1193  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1194  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1195     */
1196    static unsigned
1197    calculate_mask_weight(uint32 mask)
1198    {
1199            unsigned weight = 0;
1200            do
1201            {
1202                    weight += (mask & 1);
1203            }
1204            while (mask >>= 1);
1205            return weight;
1206    }
1207    
1208    static BOOL
1209    select_visual()
1210  {  {
         XVisualInfo vi;  
1211          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1212          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1213          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1214          XVisualInfo template;          XVisualInfo template;
1215          Bool TrueColorVisual = False;          int i;
1216            unsigned red_weight, blue_weight, green_weight;
1217    
1218          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1219          if (g_display == NULL)  
1220            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1221            if (pfm == NULL)
1222          {          {
1223                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1224                    XCloseDisplay(g_display);
1225                  return False;                  return False;
1226          }          }
1227    
1228          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 */  
1229          template.class = TrueColor;          template.class = TrueColor;
1230          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1231            g_visual = NULL;
1232            g_no_translate_image = False;
1233            g_compatible_arch = False;
1234            if (vmatches != NULL)
1235            {
1236                    for (i = 0; i < visuals_count; ++i)
1237                    {
1238                            XVisualInfo *visual_info = &vmatches[i];
1239    
1240                            /* Try to find a no-translation visual that'll
1241                               allow us to use RDP bitmaps directly as ZPixmaps. */
1242                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1243                                                   /* R5G5B5 */
1244                                                   (visual_info->red_mask == 0x7c00) &&
1245                                                   (visual_info->green_mask == 0x3e0) &&
1246                                                   (visual_info->blue_mask == 0x1f)) ||
1247                                                  ((visual_info->depth == 16) &&
1248                                                   /* R5G6B5 */
1249                                                   (visual_info->red_mask == 0xf800) &&
1250                                                   (visual_info->green_mask == 0x7e0) &&
1251                                                   (visual_info->blue_mask == 0x1f)) ||
1252                                                  ((visual_info->depth == 24) &&
1253                                                   /* R8G8B8 */
1254                                                   (visual_info->red_mask == 0xff0000) &&
1255                                                   (visual_info->green_mask == 0xff00) &&
1256                                                   (visual_info->blue_mask == 0xff))))
1257                            {
1258                                    g_visual = visual_info->visual;
1259                                    g_depth = visual_info->depth;
1260                                    g_compatible_arch = !g_host_be;
1261                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1262                                    if (g_no_translate_image)
1263                                            /* We found the best visual */
1264                                            break;
1265                            }
1266                            else
1267                            {
1268                                    g_compatible_arch = False;
1269                            }
1270    
1271                            if (visual_info->depth > 24)
1272                            {
1273                                    /* Avoid 32-bit visuals and likes like the plague.
1274                                       They're either untested or proven to work bad
1275                                       (e.g. nvidia's Composite 32-bit visual).
1276                                       Most implementation offer a 24-bit visual anyway. */
1277                                    continue;
1278                            }
1279    
1280          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1281          while (nvisuals >= 0)                             we have a translateXtoY function. */
1282          {                          BOOL can_translate_to_bpp = False;
1283                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1284                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1285                          g_depth = (vmatches + nvisuals)->depth;                          {
1286                                    if (pfm[j].depth == visual_info->depth)
1287                                    {
1288                                            if ((pfm[j].bits_per_pixel == 16) ||
1289                                                (pfm[j].bits_per_pixel == 24) ||
1290                                                (pfm[j].bits_per_pixel == 32))
1291                                            {
1292                                                    can_translate_to_bpp = True;
1293                                            }
1294                                            break;
1295                                    }
1296                            }
1297    
1298                            /* Prefer formats which have the most colour depth.
1299                               We're being truly aristocratic here, minding each
1300                               weight on its own. */
1301                            if (can_translate_to_bpp)
1302                            {
1303                                    unsigned vis_red_weight =
1304                                            calculate_mask_weight(visual_info->red_mask);
1305                                    unsigned vis_green_weight =
1306                                            calculate_mask_weight(visual_info->green_mask);
1307                                    unsigned vis_blue_weight =
1308                                            calculate_mask_weight(visual_info->blue_mask);
1309                                    if ((vis_red_weight >= red_weight)
1310                                        && (vis_green_weight >= green_weight)
1311                                        && (vis_blue_weight >= blue_weight))
1312                                    {
1313                                            red_weight = vis_red_weight;
1314                                            green_weight = vis_green_weight;
1315                                            blue_weight = vis_blue_weight;
1316                                            g_visual = visual_info->visual;
1317                                            g_depth = visual_info->depth;
1318                                    }
1319                            }
1320                  }                  }
1321                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1322          }          }
1323    
1324          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)))  
1325          {          {
1326                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1327                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1328                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1329                    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;  
                 }  
1330          }          }
1331          else          else
1332          {          {
1333                  /* need a truecolour visual */                  template.class = PseudoColor;
1334                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1335                  {                  template.colormap_size = 256;
1336                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1337                            XGetVisualInfo(g_display,
1338                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1339                                           &template, &visuals_count);
1340                    if (vmatches == NULL)
1341                    {
1342                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1343                            XCloseDisplay(g_display);
1344                            XFree(pfm);
1345                          return False;                          return False;
1346                  }                  }
1347    
1348                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1349                  g_owncolmap = False;                  g_owncolmap = True;
1350                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1351                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1352                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1353    
1354                  /* if RGB video and everything is little endian */          g_bpp = 0;
1355                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1356                      !g_xserver_be && !g_host_be)          {
1357                    XPixmapFormatValues *pf = &pfm[i];
1358                    if (pf->depth == g_depth)
1359                  {                  {
1360                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1361                                                g_blue_shift_l == 0))  
1362                            if (g_no_translate_image)
1363                          {                          {
1364                                  g_arch_match = True;                                  switch (g_server_depth)
1365                                    {
1366                                            case 15:
1367                                            case 16:
1368                                                    if (g_bpp != 16)
1369                                                            g_no_translate_image = False;
1370                                                    break;
1371                                            case 24:
1372                                                    /* Yes, this will force image translation
1373                                                       on most modern servers which use 32 bits
1374                                                       for R8G8B8. */
1375                                                    if (g_bpp != 24)
1376                                                            g_no_translate_image = False;
1377                                                    break;
1378                                            default:
1379                                                    g_no_translate_image = False;
1380                                                    break;
1381                                    }
1382                          }                          }
                 }  
1383    
1384                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1385                  {                             there's just a single entry for every depth,
1386                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1387                            break;
1388                  }                  }
1389          }          }
1390            XFree(pfm);
1391            pfm = NULL;
1392            return True;
1393    }
1394    
1395    BOOL
1396    ui_init(void)
1397    {
1398            int screen_num;
1399    
1400          pfm = XListPixmapFormats(g_display, &i);          g_display = XOpenDisplay(NULL);
1401          if (pfm != NULL)          if (g_display == NULL)
1402          {          {
1403                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1404                     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);  
1405          }          }
1406    
         if (g_bpp < 8)  
1407          {          {
1408                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1409                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1410            }
1411    
1412            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1413            screen_num = DefaultScreen(g_display);
1414            g_x_socket = ConnectionNumber(g_display);
1415            g_screen = ScreenOfDisplay(g_display, screen_num);
1416            g_depth = DefaultDepthOfScreen(g_screen);
1417    
1418            if (!select_visual())
1419                  return False;                  return False;
1420    
1421            if (g_no_translate_image)
1422            {
1423                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1424            }
1425    
1426            if (g_server_depth > g_bpp)
1427            {
1428                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1429                            g_server_depth, g_bpp);
1430          }          }
1431    
1432            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1433                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1434    
1435          if (!g_owncolmap)          if (!g_owncolmap)
1436          {          {
1437                  g_xcolmap =                  g_xcolmap =
1438                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1439                                          AllocNone);                                          AllocNone);
1440                  if (g_depth <= 8)                  if (g_depth <= 8)
1441                          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);
1442          }          }
1443    
1444          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1445          {          {
1446                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1447                  g_ownbackstore = True;                  g_ownbackstore = True;
1448          }          }
1449    
# Line 1086  ui_init(void) Line 1454  ui_init(void)
1454          {          {
1455                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1456                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1457                    g_using_full_workarea = True;
1458          }          }
1459          else if (g_width < 0)          else if (g_width < 0)
1460          {          {
1461                  /* Percent of screen */                  /* Percent of screen */
1462                    if (-g_width >= 100)
1463                            g_using_full_workarea = True;
1464                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1465                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1466          }          }
# Line 1097  ui_init(void) Line 1468  ui_init(void)
1468          {          {
1469                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1470                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1471                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1472                  {                  {
1473                          g_width = cx;                          g_width = cx;
1474                          g_height = cy;                          g_height = cy;
1475                            g_using_full_workarea = True;
1476                  }                  }
1477                  else                  else
1478                  {                  {
1479                          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");
1480                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1481                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1482                  }                  }
1483          }          }
1484    
# Line 1122  ui_init(void) Line 1493  ui_init(void)
1493                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1494    
1495          xclip_init();          xclip_init();
1496            ewmh_init();
1497            if (g_seamless_rdp)
1498                    seamless_init();
1499    
1500          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));
1501    
1502          return True;          return True;
1503  }  }
# Line 1147  ui_deinit(void) Line 1521  ui_deinit(void)
1521          g_display = NULL;          g_display = NULL;
1522  }  }
1523    
1524    
1525    static void
1526    get_window_attribs(XSetWindowAttributes * attribs)
1527    {
1528            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1529            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1530            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1531            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1532            attribs->override_redirect = g_fullscreen;
1533            attribs->colormap = g_xcolmap;
1534    }
1535    
1536    static void
1537    get_input_mask(long *input_mask)
1538    {
1539            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1540                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1541    
1542            if (g_sendmotion)
1543                    *input_mask |= PointerMotionMask;
1544            if (g_ownbackstore)
1545                    *input_mask |= ExposureMask;
1546            if (g_fullscreen || g_grab_keyboard)
1547                    *input_mask |= EnterWindowMask;
1548            if (g_grab_keyboard)
1549                    *input_mask |= LeaveWindowMask;
1550    }
1551    
1552  BOOL  BOOL
1553  ui_create_window(void)  ui_create_window(void)
1554  {  {
# Line 1163  ui_create_window(void) Line 1565  ui_create_window(void)
1565          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1566          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1567    
1568          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1569          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1570          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1571          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1572          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1573    
1574            get_window_attribs(&attribs);
1575    
1576          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,
1577                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1175  ui_create_window(void) Line 1579  ui_create_window(void)
1579                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1580    
1581          if (g_gc == NULL)          if (g_gc == NULL)
1582            {
1583                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1584                    ui_reset_clip();
1585            }
1586    
1587          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1588                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1192  ui_create_window(void) Line 1599  ui_create_window(void)
1599          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1600    
1601          if (g_hide_decorations)          if (g_hide_decorations)
1602                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1603    
1604          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1605          if (classhints != NULL)          if (classhints != NULL)
# Line 1206  ui_create_window(void) Line 1613  ui_create_window(void)
1613          if (sizehints)          if (sizehints)
1614          {          {
1615                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1616                    if (g_pos)
1617                            sizehints->flags |= PPosition;
1618                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1619                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1620                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 1217  ui_create_window(void) Line 1626  ui_create_window(void)
1626                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1627          }          }
1628    
1629          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask;  
   
         if (g_sendmotion)  
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
1630    
1631          if (g_IM != NULL)          if (g_IM != NULL)
1632          {          {
# Line 1240  ui_create_window(void) Line 1639  ui_create_window(void)
1639          }          }
1640    
1641          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1642    
1643            XMapWindow(g_display, g_wnd);
1644          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1645          do          do
1646          {          {
# Line 1312  xwin_toggle_fullscreen(void) Line 1711  xwin_toggle_fullscreen(void)
1711  {  {
1712          Pixmap contents = 0;          Pixmap contents = 0;
1713    
1714            if (g_seamless_active)
1715                    /* Turn off SeamlessRDP mode */
1716                    ui_seamless_toggle();
1717    
1718          if (!g_ownbackstore)          if (!g_ownbackstore)
1719          {          {
1720                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1332  xwin_toggle_fullscreen(void) Line 1735  xwin_toggle_fullscreen(void)
1735          }          }
1736  }  }
1737    
1738  /* Process all events in Xlib queue  static void
1739    handle_button_event(XEvent xevent, BOOL down)
1740    {
1741            uint16 button, flags = 0;
1742            g_last_gesturetime = xevent.xbutton.time;
1743            button = xkeymap_translate_button(xevent.xbutton.button);
1744            if (button == 0)
1745                    return;
1746    
1747            if (down)
1748                    flags = MOUSE_FLAG_DOWN;
1749    
1750            /* Stop moving window when button is released, regardless of cursor position */
1751            if (g_moving_wnd && (xevent.type == ButtonRelease))
1752                    g_moving_wnd = False;
1753    
1754            /* If win_button_size is nonzero, enable single app mode */
1755            if (xevent.xbutton.y < g_win_button_size)
1756            {
1757                    /*  Check from right to left: */
1758                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1759                    {
1760                            /* The close button, continue */
1761                            ;
1762                    }
1763                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1764                    {
1765                            /* The maximize/restore button. Do not send to
1766                               server.  It might be a good idea to change the
1767                               cursor or give some other visible indication
1768                               that rdesktop inhibited this click */
1769                            if (xevent.type == ButtonPress)
1770                                    return;
1771                    }
1772                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1773                    {
1774                            /* The minimize button. Iconify window. */
1775                            if (xevent.type == ButtonRelease)
1776                            {
1777                                    /* Release the mouse button outside the minimize button, to prevent the
1778                                       actual minimazation to happen */
1779                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1780                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1781                                    return;
1782                            }
1783                    }
1784                    else if (xevent.xbutton.x <= g_win_button_size)
1785                    {
1786                            /* The system menu. Ignore. */
1787                            if (xevent.type == ButtonPress)
1788                                    return;
1789                    }
1790                    else
1791                    {
1792                            /* The title bar. */
1793                            if (xevent.type == ButtonPress)
1794                            {
1795                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1796                                    {
1797                                            g_moving_wnd = True;
1798                                            g_move_x_offset = xevent.xbutton.x;
1799                                            g_move_y_offset = xevent.xbutton.y;
1800                                    }
1801                                    return;
1802                            }
1803                    }
1804            }
1805    
1806            if (xevent.xmotion.window == g_wnd)
1807            {
1808                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1809                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1810            }
1811            else
1812            {
1813                    /* SeamlessRDP */
1814                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1815                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1816            }
1817    }
1818    
1819    static void
1820    ui_seamless_handle_restack(seamless_window * sw)
1821    {
1822            Status status;
1823            Window root, parent, *children;
1824            unsigned int nchildren, i;
1825            seamless_window *sw_below;
1826    
1827            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1828                                &root, &parent, &children, &nchildren);
1829            if (!status || !nchildren)
1830                    return;
1831    
1832            sw_below = NULL;
1833    
1834            i = 0;
1835            while (children[i] != sw->wnd)
1836            {
1837                    i++;
1838                    if (i >= nchildren)
1839                            return;
1840            }
1841    
1842            for (i++; i < nchildren; i++)
1843            {
1844                    sw_below = seamless_get_window_by_wnd(children[i]);
1845                    if (sw_below)
1846                            break;
1847            }
1848    
1849            if (!sw_below && !sw->behind)
1850                    return;
1851            if (sw_below && (sw_below->id == sw->behind))
1852                    return;
1853    
1854            if (sw_below)
1855            {
1856                    seamless_send_zchange(sw->id, sw_below->id, 0);
1857                    seamless_restack_window(sw, sw_below->id);
1858            }
1859            else
1860            {
1861                    seamless_send_zchange(sw->id, 0, 0);
1862                    seamless_restack_window(sw, 0);
1863            }
1864    }
1865    
1866    /* Process events in Xlib queue
1867     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1868  static int  static int
1869  xwin_process_events(void)  xwin_process_events(void)
1870  {  {
1871          XEvent xevent;          XEvent xevent;
1872          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1873          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1874          char str[256];          char str[256];
1875          Status status;          Status status;
1876            int events = 0;
1877            seamless_window *sw;
1878    
1879          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1880          {          {
1881                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1882    
# Line 1355  xwin_process_events(void) Line 1886  xwin_process_events(void)
1886                          continue;                          continue;
1887                  }                  }
1888    
                 flags = 0;  
   
1889                  switch (xevent.type)                  switch (xevent.type)
1890                  {                  {
1891                          case VisibilityNotify:                          case VisibilityNotify:
1892                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1893                                            g_Unobscured =
1894                                                    xevent.xvisibility.state == VisibilityUnobscured;
1895    
1896                                  break;                                  break;
1897                          case ClientMessage:                          case ClientMessage:
1898                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1393  xwin_process_events(void) Line 1925  xwin_process_events(void)
1925                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1926                                  }                                  }
1927    
1928                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1929                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1930    
1931                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1932                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1933                                          break;                                          break;
1934    
1935                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1936                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
1937                                  break;                                  break;
1938    
1939                          case KeyRelease:                          case KeyRelease:
# Line 1418  xwin_process_events(void) Line 1941  xwin_process_events(void)
1941                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1942                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1943    
1944                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1945                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1946    
1947                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1948                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1949                                          break;                                          break;
1950    
1951                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1952                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1953                                  break;                                  break;
1954    
1955                          case ButtonPress:                          case ButtonPress:
1956                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1957                                  /* fall through */                                  break;
1958    
1959                          case ButtonRelease:                          case ButtonRelease:
1960                                  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);  
1961                                  break;                                  break;
1962    
1963                          case MotionNotify:                          case MotionNotify:
# Line 1511  xwin_process_events(void) Line 1972  xwin_process_events(void)
1972                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1973                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1974                                                         CurrentTime);                                                         CurrentTime);
1975                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1976                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1977                                    {
1978                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1979                                                           xevent.xmotion.x, xevent.xmotion.y);
1980                                    }
1981                                    else
1982                                    {
1983                                            /* SeamlessRDP */
1984                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1985                                                           xevent.xmotion.x_root,
1986                                                           xevent.xmotion.y_root);
1987                                    }
1988                                  break;                                  break;
1989    
1990                          case FocusIn:                          case FocusIn:
# Line 1523  xwin_process_events(void) Line 1995  xwin_process_events(void)
1995                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
1996                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
1997                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
1998    
1999                                    sw = seamless_get_window_by_wnd(xevent.xfocus.window);
2000                                    if (!sw)
2001                                            break;
2002    
2003                                    if (sw->id != g_seamless_focused)
2004                                    {
2005                                            seamless_send_focus(sw->id, 0);
2006                                            g_seamless_focused = sw->id;
2007                                    }
2008                                  break;                                  break;
2009    
2010                          case FocusOut:                          case FocusOut:
# Line 1555  xwin_process_events(void) Line 2037  xwin_process_events(void)
2037                                  break;                                  break;
2038    
2039                          case Expose:                          case Expose:
2040                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2041                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2042                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2043                                            xevent.xexpose.height,                                                    g_gc,
2044                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2045                                                      xevent.xexpose.width, xevent.xexpose.height,
2046                                                      xevent.xexpose.x, xevent.xexpose.y);
2047                                    }
2048                                    else
2049                                    {
2050                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
2051                                            if (sw)
2052                                                    XCopyArea(g_display, g_backstore,
2053                                                              xevent.xexpose.window, g_gc,
2054                                                              xevent.xexpose.x + sw->xoffset,
2055                                                              xevent.xexpose.y + sw->yoffset,
2056                                                              xevent.xexpose.width,
2057                                                              xevent.xexpose.height, xevent.xexpose.x,
2058                                                              xevent.xexpose.y);
2059                                            else
2060                                            {
2061                                                    error("Expose for unknown window 0x%lx\n",
2062                                                          xevent.xexpose.window);
2063                                            }
2064                                    }
2065    
2066                                  break;                                  break;
2067    
2068                          case MappingNotify:                          case MappingNotify:
# Line 1588  xwin_process_events(void) Line 2091  xwin_process_events(void)
2091                                  break;                                  break;
2092                          case PropertyNotify:                          case PropertyNotify:
2093                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2094                                    if (xevent.xproperty.window == g_wnd)
2095                                            break;
2096                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2097                                            break;
2098    
2099                                    /* seamless */
2100                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2101                                    if (!sw)
2102                                            break;
2103    
2104                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2105                                        && (xevent.xproperty.state == PropertyNewValue))
2106                                    {
2107                                            sw->state = ewmh_get_window_state(sw->wnd);
2108                                            seamless_send_state(sw->id, sw->state, 0);
2109                                    }
2110    
2111                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2112                                        && (xevent.xproperty.state == PropertyNewValue))
2113                                    {
2114                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2115                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
2116                                    }
2117    
2118                                    break;
2119                            case MapNotify:
2120                                    if (!g_seamless_active)
2121                                            rdp_send_client_window_status(1);
2122                                    break;
2123                            case UnmapNotify:
2124                                    if (!g_seamless_active)
2125                                            rdp_send_client_window_status(0);
2126                                    break;
2127                            case ConfigureNotify:
2128                                    if (!g_seamless_active)
2129                                            break;
2130    
2131                                    sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2132                                    if (!sw)
2133                                    {
2134                                            error("ConfigureNotify for unknown window 0x%lx\n",
2135                                                  xevent.xconfigure.window);
2136                                    }
2137    
2138                                    gettimeofday(sw->position_timer, NULL);
2139                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2140                                        1000000)
2141                                    {
2142                                            sw->position_timer->tv_usec +=
2143                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2144                                            sw->position_timer->tv_sec += 1;
2145                                    }
2146                                    else
2147                                    {
2148                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2149                                    }
2150    
2151                                    ui_seamless_handle_restack(sw);
2152                                  break;                                  break;
2153                  }                  }
2154          }          }
# Line 1612  ui_select(int rdp_socket) Line 2173  ui_select(int rdp_socket)
2173                          /* User quit */                          /* User quit */
2174                          return 0;                          return 0;
2175    
2176                    if (g_seamless_active)
2177                            seamless_check_timers();
2178    
2179                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2180                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2181                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1631  ui_select(int rdp_socket) Line 2195  ui_select(int rdp_socket)
2195    
2196                  /* add redirection handles */                  /* add redirection handles */
2197                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2198                    seamless_select_timeout(&tv);
2199    
2200                  n++;                  n++;
2201    
# Line 1672  ui_create_bitmap(int width, int height, Line 2237  ui_create_bitmap(int width, int height,
2237          uint8 *tdata;          uint8 *tdata;
2238          int bitmap_pad;          int bitmap_pad;
2239    
2240          if (g_server_bpp == 8)          if (g_server_depth == 8)
2241          {          {
2242                  bitmap_pad = 8;                  bitmap_pad = 8;
2243          }          }
# Line 1704  ui_paint_bitmap(int x, int y, int cx, in Line 2269  ui_paint_bitmap(int x, int y, int cx, in
2269          uint8 *tdata;          uint8 *tdata;
2270          int bitmap_pad;          int bitmap_pad;
2271    
2272          if (g_server_bpp == 8)          if (g_server_depth == 8)
2273          {          {
2274                  bitmap_pad = 8;                  bitmap_pad = 8;
2275          }          }
# Line 1724  ui_paint_bitmap(int x, int y, int cx, in Line 2289  ui_paint_bitmap(int x, int y, int cx, in
2289          {          {
2290                  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);
2291                  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);
2292                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2293                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2294                                             x - sw->xoffset, y - sw->yoffset));
2295          }          }
2296          else          else
2297          {          {
2298                  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);
2299                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2300                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2301                                             x - sw->xoffset, y - sw->yoffset));
2302          }          }
2303    
2304          XFree(image);          XFree(image);
# Line 1848  ui_set_cursor(HCURSOR cursor) Line 2419  ui_set_cursor(HCURSOR cursor)
2419  {  {
2420          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2421          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2422            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2423  }  }
2424    
2425  void  void
# Line 1989  ui_set_colourmap(HCOLOURMAP map) Line 2561  ui_set_colourmap(HCOLOURMAP map)
2561                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2562          }          }
2563          else          else
2564            {
2565                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2566                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2567            }
2568  }  }
2569    
2570  void  void
2571  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2572  {  {
2573          XRectangle rect;          g_clip_rectangle.x = x;
2574            g_clip_rectangle.y = y;
2575          rect.x = x;          g_clip_rectangle.width = cx;
2576          rect.y = y;          g_clip_rectangle.height = cy;
2577          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);  
2578  }  }
2579    
2580  void  void
2581  ui_reset_clip(void)  ui_reset_clip(void)
2582  {  {
2583          XRectangle rect;          g_clip_rectangle.x = 0;
2584            g_clip_rectangle.y = 0;
2585          rect.x = 0;          g_clip_rectangle.width = g_width;
2586          rect.y = 0;          g_clip_rectangle.height = g_height;
2587          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);  
2588  }  }
2589    
2590  void  void
# Line 2094  ui_patblt(uint8 opcode, Line 2665  ui_patblt(uint8 opcode,
2665    
2666          if (g_ownbackstore)          if (g_ownbackstore)
2667                  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);
2668            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2669                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2670                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2671  }  }
2672    
2673  void  void
# Line 2104  ui_screenblt(uint8 opcode, Line 2678  ui_screenblt(uint8 opcode,
2678          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2679          if (g_ownbackstore)          if (g_ownbackstore)
2680          {          {
2681                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2682                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2683                          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);  
                 }  
2684          }          }
2685          else          else
2686          {          {
2687                  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);
2688          }          }
2689    
2690            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2691                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2692                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2693    
2694          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2695  }  }
2696    
# Line 2131  ui_memblt(uint8 opcode, Line 2701  ui_memblt(uint8 opcode,
2701  {  {
2702          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2703          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);
2704            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2705                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2706                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2707          if (g_ownbackstore)          if (g_ownbackstore)
2708                  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);
2709          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2177  ui_line(uint8 opcode, Line 2750  ui_line(uint8 opcode,
2750          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2751          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2752          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2753            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2754                                                startx - sw->xoffset, starty - sw->yoffset,
2755                                                endx - sw->xoffset, endy - sw->yoffset));
2756          if (g_ownbackstore)          if (g_ownbackstore)
2757                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2758          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2263  ui_polygon(uint8 opcode, Line 2839  ui_polygon(uint8 opcode,
2839  }  }
2840    
2841  void  void
2842    ui_polyline(uint8 opcode,
2843                /* dest */ POINT * points, int npoints,
2844                /* pen */ PEN * pen)
2845    {
2846            /* TODO: set join style */
2847            SET_FUNCTION(opcode);
2848            SET_FOREGROUND(pen->colour);
2849            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2850            if (g_ownbackstore)
2851                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2852                               CoordModePrevious);
2853    
2854            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2855                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2856    
2857            RESET_FUNCTION(opcode);
2858    }
2859    
2860    void
2861  ui_ellipse(uint8 opcode,  ui_ellipse(uint8 opcode,
2862             /* mode */ uint8 fillmode,             /* mode */ uint8 fillmode,
2863             /* dest */ int x, int y, int cx, int cy,             /* dest */ int x, int y, int cx, int cy,
# Line 2414  ui_draw_text(uint8 font, uint8 flags, ui Line 3009  ui_draw_text(uint8 font, uint8 flags, ui
3009                  switch (text[i])                  switch (text[i])
3010                  {                  {
3011                          case 0xff:                          case 0xff:
3012                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3013                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3014                                  {                                  {
3015                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3016                                          exit(1);                                          for (j = 0; j < length; j++)
3017                                                    fprintf(stderr, "%02x ", text[j]);
3018                                            fprintf(stderr, "\n");
3019                                            i = length = 0;
3020                                            break;
3021                                  }                                  }
3022                                    cache_put_text(text[i + 1], text, text[i + 2]);
3023                                    i += 3;
3024                                    length -= i;
3025                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3026                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3027                                  i = 0;                                  i = 0;
3028                                  break;                                  break;
3029    
3030                          case 0xfe:                          case 0xfe:
3031                                    /* At least one byte needs to follow */
3032                                    if (i + 2 > length)
3033                                    {
3034                                            warning("Skipping short 0xfe command:");
3035                                            for (j = 0; j < length; j++)
3036                                                    fprintf(stderr, "%02x ", text[j]);
3037                                            fprintf(stderr, "\n");
3038                                            i = length = 0;
3039                                            break;
3040                                    }
3041                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3042                                  if (entry != NULL)                                  if (entry->data != NULL)
3043                                  {                                  {
3044                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3045                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3046                                          {                                          {
3047                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3048                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2464  ui_draw_text(uint8 font, uint8 flags, ui Line 3074  ui_draw_text(uint8 font, uint8 flags, ui
3074          if (g_ownbackstore)          if (g_ownbackstore)
3075          {          {
3076                  if (boxcx > 1)                  if (boxcx > 1)
3077                    {
3078                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3079                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3080                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3081                                                    (g_display, g_backstore, sw->wnd, g_gc,
3082                                                     boxx, boxy,
3083                                                     boxcx, boxcy,
3084                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3085                    }
3086                  else                  else
3087                    {
3088                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3089                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3090                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3091                                                    (g_display, g_backstore, sw->wnd, g_gc,
3092                                                     clipx, clipy,
3093                                                     clipcx, clipcy, clipx - sw->xoffset,
3094                                                     clipy - sw->yoffset));
3095                    }
3096          }          }
3097  }  }
3098    
# Line 2514  ui_desktop_restore(uint32 offset, int x, Line 3138  ui_desktop_restore(uint32 offset, int x,
3138          {          {
3139                  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);
3140                  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);
3141                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3142                                            (g_display, g_backstore, sw->wnd, g_gc,
3143                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3144          }          }
3145          else          else
3146          {          {
3147                  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);
3148                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3149                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3150                                             x - sw->xoffset, y - sw->yoffset));
3151          }          }
3152    
3153          XFree(image);          XFree(image);
# Line 2533  void Line 3163  void
3163  ui_end_update(void)  ui_end_update(void)
3164  {  {
3165  }  }
3166    
3167    void
3168    ui_seamless_begin()
3169    {
3170            if (!g_seamless_rdp)
3171                    return;
3172    
3173            if (g_seamless_started)
3174                    return;
3175    
3176            g_seamless_started = True;
3177    
3178            ui_seamless_toggle();
3179    }
3180    
3181    void
3182    ui_seamless_toggle()
3183    {
3184            if (!g_seamless_rdp)
3185                    return;
3186    
3187            if (!g_seamless_started)
3188                    return;
3189    
3190            if (g_seamless_active)
3191            {
3192                    /* Deactivate */
3193                    while (g_seamless_windows)
3194                    {
3195                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3196                            seamless_remove_window(g_seamless_windows);
3197                    }
3198                    XMapWindow(g_display, g_wnd);
3199            }
3200            else
3201            {
3202                    /* Activate */
3203                    XUnmapWindow(g_display, g_wnd);
3204                    seamless_send_sync();
3205            }
3206    
3207            g_seamless_active = !g_seamless_active;
3208    }
3209    
3210    void
3211    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3212    {
3213            Window wnd;
3214            XSetWindowAttributes attribs;
3215            XClassHint *classhints;
3216            XSizeHints *sizehints;
3217            long input_mask;
3218            seamless_window *sw, *sw_parent;
3219    
3220            if (!g_seamless_active)
3221                    return;
3222    
3223            /* Ignore CREATEs for existing windows */
3224            sw = seamless_get_window_by_id(id);
3225            if (sw)
3226                    return;
3227    
3228            get_window_attribs(&attribs);
3229            attribs.override_redirect = False;
3230    
3231            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3232                                InputOutput, g_visual,
3233                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3234                                CWBorderPixel, &attribs);
3235    
3236            XStoreName(g_display, wnd, "SeamlessRDP");
3237            ewmh_set_wm_name(wnd, "SeamlessRDP");
3238    
3239            mwm_hide_decorations(wnd);
3240    
3241            classhints = XAllocClassHint();
3242            if (classhints != NULL)
3243            {
3244                    classhints->res_name = "rdesktop";
3245                    classhints->res_class = "SeamlessRDP";
3246                    XSetClassHint(g_display, wnd, classhints);
3247                    XFree(classhints);
3248            }
3249    
3250            /* WM_NORMAL_HINTS */
3251            sizehints = XAllocSizeHints();
3252            if (sizehints != NULL)
3253            {
3254                    sizehints->flags = USPosition;
3255                    XSetWMNormalHints(g_display, wnd, sizehints);
3256                    XFree(sizehints);
3257            }
3258    
3259            /* Set WM_TRANSIENT_FOR, if necessary */
3260            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3261            {
3262                    sw_parent = seamless_get_window_by_id(parent);
3263                    if (sw_parent)
3264                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3265                    else
3266                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3267            }
3268    
3269    
3270            /* FIXME: Support for Input Context:s */
3271    
3272            get_input_mask(&input_mask);
3273            input_mask |= PropertyChangeMask;
3274    
3275            XSelectInput(g_display, wnd, input_mask);
3276    
3277            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3278               seamless window, we could try to close the window on the
3279               serverside, instead of terminating rdesktop */
3280            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3281    
3282            sw = xmalloc(sizeof(seamless_window));
3283            sw->wnd = wnd;
3284            sw->id = id;
3285            sw->parent = parent;
3286            sw->behind = 0;
3287            sw->xoffset = 0;
3288            sw->yoffset = 0;
3289            sw->width = 0;
3290            sw->height = 0;
3291            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3292            sw->desktop = 0;
3293            sw->position_timer = xmalloc(sizeof(struct timeval));
3294            timerclear(sw->position_timer);
3295            sw->next = g_seamless_windows;
3296            g_seamless_windows = sw;
3297    }
3298    
3299    
3300    void
3301    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3302    {
3303            seamless_window *sw;
3304    
3305            if (!g_seamless_active)
3306                    return;
3307    
3308            sw = seamless_get_window_by_id(id);
3309            if (!sw)
3310            {
3311                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3312                    return;
3313            }
3314    
3315            XDestroyWindow(g_display, sw->wnd);
3316            seamless_remove_window(sw);
3317    }
3318    
3319    
3320    void
3321    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3322    {
3323            seamless_window *sw;
3324    
3325            if (!g_seamless_active)
3326                    return;
3327    
3328            sw = seamless_get_window_by_id(id);
3329            if (!sw)
3330            {
3331                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3332                    return;
3333            }
3334    
3335            if (!width || !height)
3336                    /* X11 windows must be at least 1x1 */
3337                    return;
3338    
3339            sw->xoffset = x;
3340            sw->yoffset = y;
3341            sw->width = width;
3342            sw->height = height;
3343    
3344            /* If we move the window in a maximized state, then KDE won't
3345               accept restoration */
3346            switch (sw->state)
3347            {
3348                    case SEAMLESSRDP_MINIMIZED:
3349                    case SEAMLESSRDP_MAXIMIZED:
3350                            return;
3351            }
3352    
3353            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3354            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3355    }
3356    
3357    void
3358    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3359    {
3360            seamless_window *sw;
3361    
3362            if (!g_seamless_active)
3363                    return;
3364    
3365            sw = seamless_get_window_by_id(id);
3366            if (!sw)
3367            {
3368                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3369                    return;
3370            }
3371    
3372            if (behind)
3373            {
3374                    seamless_window *sw_behind;
3375                    Window wnds[2];
3376    
3377                    sw_behind = seamless_get_window_by_id(behind);
3378                    if (!sw_behind)
3379                    {
3380                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3381                                    behind);
3382                            return;
3383                    }
3384    
3385                    wnds[1] = sw_behind->wnd;
3386                    wnds[0] = sw->wnd;
3387    
3388                    XRestackWindows(g_display, wnds, 2);
3389            }
3390            else
3391            {
3392                    XRaiseWindow(g_display, sw->wnd);
3393            }
3394    
3395            seamless_restack_window(sw, behind);
3396    }
3397    
3398    void
3399    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3400    {
3401            seamless_window *sw;
3402    
3403            if (!g_seamless_active)
3404                    return;
3405    
3406            sw = seamless_get_window_by_id(id);
3407            if (!sw)
3408            {
3409                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3410                    return;
3411            }
3412    
3413            /* FIXME: Might want to convert the name for non-EWMH WMs */
3414            XStoreName(g_display, sw->wnd, title);
3415            ewmh_set_wm_name(sw->wnd, title);
3416    }
3417    
3418    
3419    void
3420    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3421    {
3422            seamless_window *sw;
3423    
3424            if (!g_seamless_active)
3425                    return;
3426    
3427            sw = seamless_get_window_by_id(id);
3428            if (!sw)
3429            {
3430                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3431                    return;
3432            }
3433    
3434            switch (state)
3435            {
3436                    case SEAMLESSRDP_NORMAL:
3437                    case SEAMLESSRDP_MAXIMIZED:
3438                            ewmh_change_state(sw->wnd, state);
3439                            XMapWindow(g_display, sw->wnd);
3440                            break;
3441                    case SEAMLESSRDP_MINIMIZED:
3442                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3443                               the Window Manager should probably just ignore the request, since
3444                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3445                               such as minimization, rather than an independent state." Besides,
3446                               XIconifyWindow is easier. */
3447                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3448                            {
3449                                    XWMHints *hints;
3450                                    hints = XAllocWMHints();
3451                                    hints->flags = StateHint;
3452                                    hints->initial_state = IconicState;
3453                                    XSetWMHints(g_display, sw->wnd, hints);
3454                                    XFree(hints);
3455                                    XMapWindow(g_display, sw->wnd);
3456                            }
3457                            else
3458                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3459                            break;
3460                    default:
3461                            warning("SeamlessRDP: Invalid state %d\n", state);
3462                            break;
3463            }
3464    
3465            /* Handle popups without parents through some ewm hints */
3466            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3467                    ewmh_set_window_popup(sw->wnd);
3468    
3469            sw->state = state;
3470    }
3471    
3472    
3473    void
3474    ui_seamless_syncbegin(unsigned long flags)
3475    {
3476            if (!g_seamless_active)
3477                    return;
3478    
3479            /* Destroy all seamless windows */
3480            while (g_seamless_windows)
3481            {
3482                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3483                    seamless_remove_window(g_seamless_windows);
3484            }
3485    }

Legend:
Removed from v.843  
changed lines
  Added in v.1157

  ViewVC Help
Powered by ViewVC 1.1.26