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

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

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26