/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/xwin.c

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

revision 976 by astrand, Thu Aug 4 13:39:57 2005 UTC revision 1226 by astrand, Wed Apr 12 06:47:24 2006 UTC
# Line 28  Line 28 
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31    /* We can't include Xproto.h because of conflicting defines for BOOL */
32    #define X_ConfigureWindow              12
33    
34  extern int g_width;  extern int g_width;
35  extern int g_height;  extern int g_height;
36  extern int g_xpos;  extern int g_xpos;
# Line 38  extern BOOL g_fullscreen; Line 41  extern BOOL g_fullscreen;
41  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
42  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
43  extern char g_title[];  extern char g_title[];
44  extern int g_server_bpp;  /* Color depth of the RDP session.
45       As of RDP 5.1, it may be 8, 15, 16 or 24. */
46    extern int g_server_depth;
47  extern int g_win_button_size;  extern int g_win_button_size;
48    
49  Display *g_display;  Display *g_display;
# Line 46  Time g_last_gesturetime; Line 51  Time g_last_gesturetime;
51  static int g_x_socket;  static int g_x_socket;
52  static Screen *g_screen;  static Screen *g_screen;
53  Window g_wnd;  Window g_wnd;
54    
55    /* SeamlessRDP support */
56    typedef struct _seamless_group
57    {
58            Window wnd;
59            unsigned long id;
60            unsigned int refcnt;
61    } seamless_group;
62    typedef struct _seamless_window
63    {
64            Window wnd;
65            unsigned long id;
66            unsigned long behind;
67            seamless_group *group;
68            int xoffset, yoffset;
69            int width, height;
70            int state;              /* normal/minimized/maximized. */
71            unsigned int desktop;
72            struct timeval *position_timer;
73    
74            BOOL outstanding_position;
75            unsigned int outpos_serial;
76            int outpos_xoffset, outpos_yoffset;
77            int outpos_width, outpos_height;
78    
79            struct _seamless_window *next;
80    } seamless_window;
81    static seamless_window *g_seamless_windows = NULL;
82    static unsigned long g_seamless_focused = 0;
83    static BOOL g_seamless_started = False; /* Server end is up and running */
84    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
85    static BOOL g_seamless_hidden = False;  /* Desktop is hidden on server */
86    extern BOOL g_seamless_rdp;
87    
88  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
89  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
90  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
91  static GC g_gc = NULL;  static GC g_gc = NULL;
92  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
93  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
94    static XRectangle g_clip_rectangle;
95  static Visual *g_visual;  static Visual *g_visual;
96    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
97       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
98       as far as we're concerned. */
99  static int g_depth;  static int g_depth;
100    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
101       This may be larger than g_depth, in which case some of the bits would
102       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
103  static int g_bpp;  static int g_bpp;
104  static XIM g_IM;  static XIM g_IM;
105  static XIC g_IC;  static XIC g_IC;
# Line 61  static XModifierKeymap *g_mod_map; Line 107  static XModifierKeymap *g_mod_map;
107  static Cursor g_current_cursor;  static Cursor g_current_cursor;
108  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
109  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
110    extern Atom g_net_wm_state_atom;
111    extern Atom g_net_wm_desktop_atom;
112  static BOOL g_focused;  static BOOL g_focused;
113  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
114  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
115       1) visual has 15, 16 or 24 depth and the same color channel masks
116          as its RDP equivalent (implies X server is LE),
117       2) host is LE
118       This will trigger an optimization whose real value is questionable.
119    */
120    static BOOL g_compatible_arch;
121    /* Indicates whether RDP's bitmaps and our XImages have the same
122       binary format. If so, we can avoid an expensive translation.
123       Note that this can be true when g_compatible_arch is false,
124       e.g.:
125      
126         RDP(LE) <-> host(BE) <-> X-Server(LE)
127        
128       ('host' is the machine running rdesktop; the host simply memcpy's
129        so its endianess doesn't matter)
130     */
131    static BOOL g_no_translate_image = False;
132    
133  /* endianness */  /* endianness */
134  static BOOL g_host_be;  static BOOL g_host_be;
# Line 79  static Pixmap g_backstore = 0; Line 144  static Pixmap g_backstore = 0;
144  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
145  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
146  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
147    static BOOL g_using_full_workarea = False;
148    
149  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
150  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 91  extern BOOL g_rdpsnd; Line 157  extern BOOL g_rdpsnd;
157  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
158  typedef struct  typedef struct
159  {  {
160          uint32 flags;          unsigned long flags;
161          uint32 functions;          unsigned long functions;
162          uint32 decorations;          unsigned long decorations;
163          sint32 inputMode;          long inputMode;
164          uint32 status;          unsigned long status;
165  }  }
166  PropMotifWmHints;  PropMotifWmHints;
167    
# Line 107  typedef struct Line 173  typedef struct
173  }  }
174  PixelColour;  PixelColour;
175    
176    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
177            do { \
178                    seamless_window *sw; \
179                    XRectangle rect; \
180                    if (!g_seamless_windows) break; \
181                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
182                        rect.x = g_clip_rectangle.x - sw->xoffset; \
183                        rect.y = g_clip_rectangle.y - sw->yoffset; \
184                        rect.width = g_clip_rectangle.width; \
185                        rect.height = g_clip_rectangle.height; \
186                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
187                        func args; \
188                    } \
189                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
190            } while (0)
191    
192    static void
193    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
194    {
195            points[0].x -= xoffset;
196            points[0].y -= yoffset;
197            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
198            points[0].x += xoffset;
199            points[0].y += yoffset;
200    }
201    
202    static void
203    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
204    {
205            points[0].x -= xoffset;
206            points[0].y -= yoffset;
207            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
208            points[0].x += xoffset;
209            points[0].y += yoffset;
210    }
211    
212  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
213  { \  { \
214          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
215            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
216          if (g_ownbackstore) \          if (g_ownbackstore) \
217                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
218  }  }
# Line 125  PixelColour; Line 227  PixelColour;
227          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
228          if (g_ownbackstore) \          if (g_ownbackstore) \
229                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
230            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
231  }  }
232    
233  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 133  PixelColour; Line 236  PixelColour;
236          { \          { \
237                  case 0: /* Outline */ \                  case 0: /* Outline */ \
238                          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); \
239                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
240                          if (g_ownbackstore) \                          if (g_ownbackstore) \
241                                  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); \
242                          break; \                          break; \
243                  case 1: /* Filled */ \                  case 1: /* Filled */ \
244                          XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
245                                   cx, cy, 0, 360*64); \                          ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, \
246                                                                x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
247                          if (g_ownbackstore) \                          if (g_ownbackstore) \
248                                  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); \
249                          break; \                          break; \
250          } \          } \
251  }  }
# Line 150  extern BOOL g_owncolmap; Line 255  extern BOOL g_owncolmap;
255  static Colormap g_xcolmap;  static Colormap g_xcolmap;
256  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
257    
258  #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] )
259  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
260  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
261    
# Line 176  static int rop2_map[] = { Line 281  static int rop2_map[] = {
281  #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]); }
282  #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); }
283    
284    static seamless_window *
285    sw_get_window_by_id(unsigned long id)
286    {
287            seamless_window *sw;
288            for (sw = g_seamless_windows; sw; sw = sw->next)
289            {
290                    if (sw->id == id)
291                            return sw;
292            }
293            return NULL;
294    }
295    
296    
297    static seamless_window *
298    sw_get_window_by_wnd(Window wnd)
299    {
300            seamless_window *sw;
301            for (sw = g_seamless_windows; sw; sw = sw->next)
302            {
303                    if (sw->wnd == wnd)
304                            return sw;
305            }
306            return NULL;
307    }
308    
309    
310    static void
311    sw_remove_window(seamless_window * win)
312    {
313            seamless_window *sw, **prevnext = &g_seamless_windows;
314            for (sw = g_seamless_windows; sw; sw = sw->next)
315            {
316                    if (sw == win)
317                    {
318                            *prevnext = sw->next;
319                            sw->group->refcnt--;
320                            if (sw->group->refcnt == 0)
321                            {
322                                    XDestroyWindow(g_display, sw->group->wnd);
323                                    xfree(sw->group);
324                            }
325                            xfree(sw->position_timer);
326                            xfree(sw);
327                            return;
328                    }
329                    prevnext = &sw->next;
330            }
331            return;
332    }
333    
334    
335    /* Move all windows except wnd to new desktop */
336    static void
337    sw_all_to_desktop(Window wnd, unsigned int desktop)
338    {
339            seamless_window *sw;
340            for (sw = g_seamless_windows; sw; sw = sw->next)
341            {
342                    if (sw->wnd == wnd)
343                            continue;
344                    if (sw->desktop != desktop)
345                    {
346                            ewmh_move_to_desktop(sw->wnd, desktop);
347                            sw->desktop = desktop;
348                    }
349            }
350    }
351    
352    
353    /* Send our position */
354    static void
355    sw_update_position(seamless_window * sw)
356    {
357            XWindowAttributes wa;
358            int x, y;
359            Window child_return;
360            unsigned int serial;
361    
362            XGetWindowAttributes(g_display, sw->wnd, &wa);
363            XTranslateCoordinates(g_display, sw->wnd, wa.root,
364                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
365    
366            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
367    
368            sw->outstanding_position = True;
369            sw->outpos_serial = serial;
370    
371            sw->outpos_xoffset = x;
372            sw->outpos_yoffset = y;
373            sw->outpos_width = wa.width;
374            sw->outpos_height = wa.height;
375    }
376    
377    
378    /* Check if it's time to send our position */
379    static void
380    sw_check_timers()
381    {
382            seamless_window *sw;
383            struct timeval now;
384    
385            gettimeofday(&now, NULL);
386            for (sw = g_seamless_windows; sw; sw = sw->next)
387            {
388                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
389                    {
390                            timerclear(sw->position_timer);
391                            sw_update_position(sw);
392                    }
393            }
394    }
395    
396    
397    static void
398    sw_restack_window(seamless_window * sw, unsigned long behind)
399    {
400            seamless_window *sw_above;
401    
402            /* Remove window from stack */
403            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
404            {
405                    if (sw_above->behind == sw->id)
406                            break;
407            }
408    
409            if (sw_above)
410                    sw_above->behind = sw->behind;
411    
412            /* And then add it at the new position */
413            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
414            {
415                    if (sw_above->behind == behind)
416                            break;
417            }
418    
419            if (sw_above)
420                    sw_above->behind = sw->id;
421    
422            sw->behind = behind;
423    }
424    
425    
426  static void  static void
427  mwm_hide_decorations(void)  sw_handle_restack(seamless_window * sw)
428    {
429            Status status;
430            Window root, parent, *children;
431            unsigned int nchildren, i;
432            seamless_window *sw_below;
433    
434            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
435                                &root, &parent, &children, &nchildren);
436            if (!status || !nchildren)
437                    return;
438    
439            sw_below = NULL;
440    
441            i = 0;
442            while (children[i] != sw->wnd)
443            {
444                    i++;
445                    if (i >= nchildren)
446                            goto end;
447            }
448    
449            for (i++; i < nchildren; i++)
450            {
451                    sw_below = sw_get_window_by_wnd(children[i]);
452                    if (sw_below)
453                            break;
454            }
455    
456            if (!sw_below && !sw->behind)
457                    goto end;
458            if (sw_below && (sw_below->id == sw->behind))
459                    goto end;
460    
461            if (sw_below)
462            {
463                    seamless_send_zchange(sw->id, sw_below->id, 0);
464                    sw_restack_window(sw, sw_below->id);
465            }
466            else
467            {
468                    seamless_send_zchange(sw->id, 0, 0);
469                    sw_restack_window(sw, 0);
470            }
471    
472          end:
473            XFree(children);
474    }
475    
476    
477    static seamless_group *
478    sw_find_group(unsigned long id, BOOL dont_create)
479    {
480            seamless_window *sw;
481            seamless_group *sg;
482            XSetWindowAttributes attribs;
483    
484            for (sw = g_seamless_windows; sw; sw = sw->next)
485            {
486                    if (sw->group->id == id)
487                            return sw->group;
488            }
489    
490            if (dont_create)
491                    return NULL;
492    
493            sg = xmalloc(sizeof(seamless_group));
494    
495            sg->wnd =
496                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
497                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
498    
499            sg->id = id;
500            sg->refcnt = 0;
501    
502            return sg;
503    }
504    
505    
506    static void
507    mwm_hide_decorations(Window wnd)
508  {  {
509          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
510          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 521  mwm_hide_decorations(void)
521                  return;                  return;
522          }          }
523    
524          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
525                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
526    
527  }  }
528    
529  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 557  mwm_hide_decorations(void)
557  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
558                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
559    
560    /* The following macros output the same octet sequences
561       on both BE and LE hosts: */
562    
563  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
564  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
565  #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 571  static uint32
571  translate_colour(uint32 colour)  translate_colour(uint32 colour)
572  {  {
573          PixelColour pc;          PixelColour pc;
574          switch (g_server_bpp)          switch (g_server_depth)
575          {          {
576                  case 15:                  case 15:
577                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 251  translate_colour(uint32 colour) Line 582  translate_colour(uint32 colour)
582                  case 24:                  case 24:
583                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
584                          break;                          break;
585                    default:
586                            /* Avoid warning */
587                            pc.red = 0;
588                            pc.green = 0;
589                            pc.blue = 0;
590                            break;
591          }          }
592          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
593  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 639  translate8to16(const uint8 * data, uint8
639  {  {
640          uint16 value;          uint16 value;
641    
642          if (g_arch_match)          if (g_compatible_arch)
643          {          {
644                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
645                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 673  translate8to24(const uint8 * data, uint8
673  {  {
674          uint32 value;          uint32 value;
675    
676          if (g_xserver_be)          if (g_compatible_arch)
677          {          {
678                  while (out < end)                  while (out < end)
679                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 696  translate8to32(const uint8 * data, uint8
696  {  {
697          uint32 value;          uint32 value;
698    
699          if (g_arch_match)          if (g_compatible_arch)
700          {          {
701                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
702                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 768  translate15to24(const uint16 * data, uin
768          uint16 pixel;          uint16 pixel;
769          PixelColour pc;          PixelColour pc;
770    
771          if (g_arch_match)          if (g_compatible_arch)
772          {          {
773                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
774                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 818  translate15to32(const uint16 * data, uin
818          uint32 value;          uint32 value;
819          PixelColour pc;          PixelColour pc;
820    
821          if (g_arch_match)          if (g_compatible_arch)
822          {          {
823                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
824                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 926  translate16to24(const uint16 * data, uin
926          uint16 pixel;          uint16 pixel;
927          PixelColour pc;          PixelColour pc;
928    
929          if (g_arch_match)          if (g_compatible_arch)
930          {          {
931                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
932                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 996  translate16to32(const uint16 * data, uin
996          uint32 value;          uint32 value;
997          PixelColour pc;          PixelColour pc;
998    
999          if (g_arch_match)          if (g_compatible_arch)
1000          {          {
1001                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1002                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 1125  translate24to32(const uint8 * data, uint
1125          uint32 value;          uint32 value;
1126          PixelColour pc;          PixelColour pc;
1127    
1128          if (g_arch_match)          if (g_compatible_arch)
1129          {          {
1130                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1131  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 1139  translate24to32(const uint8 * data, uint
1139  #else  #else
1140                  REPEAT4                  REPEAT4
1141                  (                  (
1142                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1143                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1144                          data += 3;                   out += 4;
1145                     data += 3;
1146                  )                  )
1147  #endif  #endif
1148                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 842  translate_image(int width, int height, u Line 1180  translate_image(int width, int height, u
1180          uint8 *out;          uint8 *out;
1181          uint8 *end;          uint8 *end;
1182    
1183          /* if server and xserver bpp match, */          /*
1184          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1185          /* just return data */             and arch(endian) matches, no need to translate:
1186          if (g_arch_match)             just return data.
1187               Note: select_visual should've already ensured g_no_translate
1188               is only set for compatible depths, but the RDP depth might've
1189               changed during connection negotiations.
1190             */
1191            if (g_no_translate_image)
1192          {          {
1193                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1194                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1195                  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)  
1196                          return data;                          return data;
1197          }          }
1198    
# Line 859  translate_image(int width, int height, u Line 1200  translate_image(int width, int height, u
1200          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1201          end = out + size;          end = out + size;
1202    
1203          switch (g_server_bpp)          switch (g_server_depth)
1204          {          {
1205                  case 24:                  case 24:
1206                          switch (g_bpp)                          switch (g_bpp)
# Line 957  calculate_shifts(uint32 mask, int *shift Line 1298  calculate_shifts(uint32 mask, int *shift
1298          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1299  }  }
1300    
1301  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1302  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1303     */
1304    static unsigned
1305    calculate_mask_weight(uint32 mask)
1306    {
1307            unsigned weight = 0;
1308            do
1309            {
1310                    weight += (mask & 1);
1311            }
1312            while (mask >>= 1);
1313            return weight;
1314    }
1315    
1316    static BOOL
1317    select_visual()
1318  {  {
         XVisualInfo vi;  
1319          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1320          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1321          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1322          XVisualInfo template;          XVisualInfo template;
1323          Bool TrueColorVisual = False;          int i;
1324            unsigned red_weight, blue_weight, green_weight;
1325    
1326          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1327          if (g_display == NULL)  
1328            if (g_server_depth == -1)
1329          {          {
1330                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1331          }          }
1332    
1333          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1334          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1335          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1336          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1337                    XCloseDisplay(g_display);
1338                    return False;
1339            }
1340    
1341          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1342          template.class = TrueColor;          template.class = TrueColor;
1343          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1344            g_visual = NULL;
1345            g_no_translate_image = False;
1346            g_compatible_arch = False;
1347            if (vmatches != NULL)
1348            {
1349                    for (i = 0; i < visuals_count; ++i)
1350                    {
1351                            XVisualInfo *visual_info = &vmatches[i];
1352                            BOOL can_translate_to_bpp = False;
1353                            int j;
1354    
1355                            /* Try to find a no-translation visual that'll
1356                               allow us to use RDP bitmaps directly as ZPixmaps. */
1357                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1358                                                   /* R5G5B5 */
1359                                                   (visual_info->red_mask == 0x7c00) &&
1360                                                   (visual_info->green_mask == 0x3e0) &&
1361                                                   (visual_info->blue_mask == 0x1f)) ||
1362                                                  ((visual_info->depth == 16) &&
1363                                                   /* R5G6B5 */
1364                                                   (visual_info->red_mask == 0xf800) &&
1365                                                   (visual_info->green_mask == 0x7e0) &&
1366                                                   (visual_info->blue_mask == 0x1f)) ||
1367                                                  ((visual_info->depth == 24) &&
1368                                                   /* R8G8B8 */
1369                                                   (visual_info->red_mask == 0xff0000) &&
1370                                                   (visual_info->green_mask == 0xff00) &&
1371                                                   (visual_info->blue_mask == 0xff))))
1372                            {
1373                                    g_visual = visual_info->visual;
1374                                    g_depth = visual_info->depth;
1375                                    g_compatible_arch = !g_host_be;
1376                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1377                                    if (g_no_translate_image)
1378                                            /* We found the best visual */
1379                                            break;
1380                            }
1381                            else
1382                            {
1383                                    g_compatible_arch = False;
1384                            }
1385    
1386          nvisuals--;                          if (visual_info->depth > 24)
1387          while (nvisuals >= 0)                          {
1388          {                                  /* Avoid 32-bit visuals and likes like the plague.
1389                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1390                  {                                     (e.g. nvidia's Composite 32-bit visual).
1391                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1392                                    continue;
1393                            }
1394    
1395                            /* Only care for visuals, for whose BPPs (not depths!)
1396                               we have a translateXtoY function. */
1397                            for (j = 0; j < pixmap_formats_count; ++j)
1398                            {
1399                                    if (pfm[j].depth == visual_info->depth)
1400                                    {
1401                                            if ((pfm[j].bits_per_pixel == 16) ||
1402                                                (pfm[j].bits_per_pixel == 24) ||
1403                                                (pfm[j].bits_per_pixel == 32))
1404                                            {
1405                                                    can_translate_to_bpp = True;
1406                                            }
1407                                            break;
1408                                    }
1409                            }
1410    
1411                            /* Prefer formats which have the most colour depth.
1412                               We're being truly aristocratic here, minding each
1413                               weight on its own. */
1414                            if (can_translate_to_bpp)
1415                            {
1416                                    unsigned vis_red_weight =
1417                                            calculate_mask_weight(visual_info->red_mask);
1418                                    unsigned vis_green_weight =
1419                                            calculate_mask_weight(visual_info->green_mask);
1420                                    unsigned vis_blue_weight =
1421                                            calculate_mask_weight(visual_info->blue_mask);
1422                                    if ((vis_red_weight >= red_weight)
1423                                        && (vis_green_weight >= green_weight)
1424                                        && (vis_blue_weight >= blue_weight))
1425                                    {
1426                                            red_weight = vis_red_weight;
1427                                            green_weight = vis_green_weight;
1428                                            blue_weight = vis_blue_weight;
1429                                            g_visual = visual_info->visual;
1430                                            g_depth = visual_info->depth;
1431                                    }
1432                            }
1433                  }                  }
1434                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1435          }          }
1436    
1437          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)))  
1438          {          {
1439                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1440                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1441                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1442                    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;  
                 }  
1443          }          }
1444          else          else
1445          {          {
1446                  /* need a truecolour visual */                  template.class = PseudoColor;
1447                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1448                  {                  template.colormap_size = 256;
1449                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1450                            XGetVisualInfo(g_display,
1451                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1452                                           &template, &visuals_count);
1453                    if (vmatches == NULL)
1454                    {
1455                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1456                            XCloseDisplay(g_display);
1457                            XFree(pfm);
1458                          return False;                          return False;
1459                  }                  }
1460    
1461                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1462                  g_owncolmap = False;                  g_owncolmap = True;
1463                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1464                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1465                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1466    
1467                  /* if RGB video and everything is little endian */          g_bpp = 0;
1468                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1469                      !g_xserver_be && !g_host_be)          {
1470                    XPixmapFormatValues *pf = &pfm[i];
1471                    if (pf->depth == g_depth)
1472                  {                  {
1473                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1474                                                g_blue_shift_l == 0))  
1475                            if (g_no_translate_image)
1476                          {                          {
1477                                  g_arch_match = True;                                  switch (g_server_depth)
1478                                    {
1479                                            case 15:
1480                                            case 16:
1481                                                    if (g_bpp != 16)
1482                                                            g_no_translate_image = False;
1483                                                    break;
1484                                            case 24:
1485                                                    /* Yes, this will force image translation
1486                                                       on most modern servers which use 32 bits
1487                                                       for R8G8B8. */
1488                                                    if (g_bpp != 24)
1489                                                            g_no_translate_image = False;
1490                                                    break;
1491                                            default:
1492                                                    g_no_translate_image = False;
1493                                                    break;
1494                                    }
1495                          }                          }
                 }  
1496    
1497                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1498                  {                             there's just a single entry for every depth,
1499                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1500                            break;
1501                  }                  }
1502          }          }
1503            XFree(pfm);
1504            pfm = NULL;
1505            return True;
1506    }
1507    
1508    static XErrorHandler g_old_error_handler;
1509    
1510          pfm = XListPixmapFormats(g_display, &i);  static int
1511          if (pfm != NULL)  error_handler(Display * dpy, XErrorEvent * eev)
1512    {
1513            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1514          {          {
1515                  /* Use maximum bpp for this depth - this is generally                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1516                     desirable, e.g. 24 bits->32 bits. */                  fprintf(stderr,
1517                  while (i--)                          "This is most likely caused by a broken window manager (commonly KWin).\n");
1518                  {                  return 0;
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1519          }          }
1520    
1521          if (g_bpp < 8)          return g_old_error_handler(dpy, eev);
1522    }
1523    
1524    BOOL
1525    ui_init(void)
1526    {
1527            int screen_num;
1528    
1529            g_display = XOpenDisplay(NULL);
1530            if (g_display == NULL)
1531          {          {
1532                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(g_display);  
1533                  return False;                  return False;
1534          }          }
1535    
1536            {
1537                    uint16 endianess_test = 1;
1538                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1539            }
1540    
1541            g_old_error_handler = XSetErrorHandler(error_handler);
1542            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1543            screen_num = DefaultScreen(g_display);
1544            g_x_socket = ConnectionNumber(g_display);
1545            g_screen = ScreenOfDisplay(g_display, screen_num);
1546            g_depth = DefaultDepthOfScreen(g_screen);
1547    
1548            if (!select_visual())
1549                    return False;
1550    
1551            if (g_no_translate_image)
1552            {
1553                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1554            }
1555    
1556            if (g_server_depth > g_bpp)
1557            {
1558                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1559                            g_server_depth, g_bpp);
1560            }
1561    
1562            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1563                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1564    
1565          if (!g_owncolmap)          if (!g_owncolmap)
1566          {          {
1567                  g_xcolmap =                  g_xcolmap =
1568                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1569                                          AllocNone);                                          AllocNone);
1570                  if (g_depth <= 8)                  if (g_depth <= 8)
1571                          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);
1572          }          }
1573    
1574          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1575          {          {
1576                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1577                  g_ownbackstore = True;                  g_ownbackstore = True;
1578          }          }
1579    
# Line 1087  ui_init(void) Line 1584  ui_init(void)
1584          {          {
1585                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1586                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1587                    g_using_full_workarea = True;
1588          }          }
1589          else if (g_width < 0)          else if (g_width < 0)
1590          {          {
1591                  /* Percent of screen */                  /* Percent of screen */
1592                    if (-g_width >= 100)
1593                            g_using_full_workarea = True;
1594                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1595                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1596          }          }
# Line 1098  ui_init(void) Line 1598  ui_init(void)
1598          {          {
1599                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1600                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1601                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1602                  {                  {
1603                          g_width = cx;                          g_width = cx;
1604                          g_height = cy;                          g_height = cy;
1605                            g_using_full_workarea = True;
1606                  }                  }
1607                  else                  else
1608                  {                  {
1609                          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");
1610                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1611                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1612                  }                  }
1613          }          }
1614    
# Line 1123  ui_init(void) Line 1623  ui_init(void)
1623                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1624    
1625          xclip_init();          xclip_init();
1626            ewmh_init();
1627            if (g_seamless_rdp)
1628                    seamless_init();
1629    
1630          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));
1631    
1632          return True;          return True;
1633  }  }
# Line 1132  ui_init(void) Line 1635  ui_init(void)
1635  void  void
1636  ui_deinit(void)  ui_deinit(void)
1637  {  {
1638            while (g_seamless_windows)
1639            {
1640                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1641                    sw_remove_window(g_seamless_windows);
1642            }
1643    
1644            xclip_deinit();
1645    
1646          if (g_IM != NULL)          if (g_IM != NULL)
1647                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1648    
# Line 1148  ui_deinit(void) Line 1659  ui_deinit(void)
1659          g_display = NULL;          g_display = NULL;
1660  }  }
1661    
1662    
1663    static void
1664    get_window_attribs(XSetWindowAttributes * attribs)
1665    {
1666            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1667            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1668            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1669            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1670            attribs->override_redirect = g_fullscreen;
1671            attribs->colormap = g_xcolmap;
1672    }
1673    
1674    static void
1675    get_input_mask(long *input_mask)
1676    {
1677            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1678                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1679    
1680            if (g_sendmotion)
1681                    *input_mask |= PointerMotionMask;
1682            if (g_ownbackstore)
1683                    *input_mask |= ExposureMask;
1684            if (g_fullscreen || g_grab_keyboard)
1685                    *input_mask |= EnterWindowMask;
1686            if (g_grab_keyboard)
1687                    *input_mask |= LeaveWindowMask;
1688    }
1689    
1690  BOOL  BOOL
1691  ui_create_window(void)  ui_create_window(void)
1692  {  {
# Line 1170  ui_create_window(void) Line 1709  ui_create_window(void)
1709          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1710                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1711    
1712          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;  
1713    
1714          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,
1715                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1182  ui_create_window(void) Line 1717  ui_create_window(void)
1717                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1718    
1719          if (g_gc == NULL)          if (g_gc == NULL)
1720            {
1721                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1722                    ui_reset_clip();
1723            }
1724    
1725          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1726                  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 1737  ui_create_window(void)
1737          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1738    
1739          if (g_hide_decorations)          if (g_hide_decorations)
1740                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1741    
1742          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1743          if (classhints != NULL)          if (classhints != NULL)
# Line 1226  ui_create_window(void) Line 1764  ui_create_window(void)
1764                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1765          }          }
1766    
1767          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;  
1768    
1769          if (g_IM != NULL)          if (g_IM != NULL)
1770          {          {
# Line 1321  xwin_toggle_fullscreen(void) Line 1849  xwin_toggle_fullscreen(void)
1849  {  {
1850          Pixmap contents = 0;          Pixmap contents = 0;
1851    
1852            if (g_seamless_active)
1853                    /* Turn off SeamlessRDP mode */
1854                    ui_seamless_toggle();
1855    
1856          if (!g_ownbackstore)          if (!g_ownbackstore)
1857          {          {
1858                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1341  xwin_toggle_fullscreen(void) Line 1873  xwin_toggle_fullscreen(void)
1873          }          }
1874  }  }
1875    
1876    static void
1877    handle_button_event(XEvent xevent, BOOL down)
1878    {
1879            uint16 button, flags = 0;
1880            g_last_gesturetime = xevent.xbutton.time;
1881            button = xkeymap_translate_button(xevent.xbutton.button);
1882            if (button == 0)
1883                    return;
1884    
1885            if (down)
1886                    flags = MOUSE_FLAG_DOWN;
1887    
1888            /* Stop moving window when button is released, regardless of cursor position */
1889            if (g_moving_wnd && (xevent.type == ButtonRelease))
1890                    g_moving_wnd = False;
1891    
1892            /* If win_button_size is nonzero, enable single app mode */
1893            if (xevent.xbutton.y < g_win_button_size)
1894            {
1895                    /*  Check from right to left: */
1896                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1897                    {
1898                            /* The close button, continue */
1899                            ;
1900                    }
1901                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1902                    {
1903                            /* The maximize/restore button. Do not send to
1904                               server.  It might be a good idea to change the
1905                               cursor or give some other visible indication
1906                               that rdesktop inhibited this click */
1907                            if (xevent.type == ButtonPress)
1908                                    return;
1909                    }
1910                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1911                    {
1912                            /* The minimize button. Iconify window. */
1913                            if (xevent.type == ButtonRelease)
1914                            {
1915                                    /* Release the mouse button outside the minimize button, to prevent the
1916                                       actual minimazation to happen */
1917                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1918                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1919                                    return;
1920                            }
1921                    }
1922                    else if (xevent.xbutton.x <= g_win_button_size)
1923                    {
1924                            /* The system menu. Ignore. */
1925                            if (xevent.type == ButtonPress)
1926                                    return;
1927                    }
1928                    else
1929                    {
1930                            /* The title bar. */
1931                            if (xevent.type == ButtonPress)
1932                            {
1933                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1934                                    {
1935                                            g_moving_wnd = True;
1936                                            g_move_x_offset = xevent.xbutton.x;
1937                                            g_move_y_offset = xevent.xbutton.y;
1938                                    }
1939                                    return;
1940                            }
1941                    }
1942            }
1943    
1944            if (xevent.xmotion.window == g_wnd)
1945            {
1946                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1947                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1948            }
1949            else
1950            {
1951                    /* SeamlessRDP */
1952                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1953                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1954            }
1955    }
1956    
1957    
1958  /* Process events in Xlib queue  /* Process events in Xlib queue
1959     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1960  static int  static int
# Line 1348  xwin_process_events(void) Line 1962  xwin_process_events(void)
1962  {  {
1963          XEvent xevent;          XEvent xevent;
1964          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1965          uint32 ev_time;          uint32 ev_time;
1966          char str[256];          char str[256];
1967          Status status;          Status status;
1968          int events = 0;          int events = 0;
1969            seamless_window *sw;
1970    
1971          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
1972          {          {
# Line 1364  xwin_process_events(void) Line 1978  xwin_process_events(void)
1978                          continue;                          continue;
1979                  }                  }
1980    
                 flags = 0;  
   
1981                  switch (xevent.type)                  switch (xevent.type)
1982                  {                  {
1983                          case VisibilityNotify:                          case VisibilityNotify:
1984                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1985                                            g_Unobscured =
1986                                                    xevent.xvisibility.state == VisibilityUnobscured;
1987    
1988                                  break;                                  break;
1989                          case ClientMessage:                          case ClientMessage:
1990                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1430  xwin_process_events(void) Line 2045  xwin_process_events(void)
2045                                  break;                                  break;
2046    
2047                          case ButtonPress:                          case ButtonPress:
2048                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2049                                  /* fall through */                                  break;
2050    
2051                          case ButtonRelease:                          case ButtonRelease:
2052                                  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);  
2053                                  break;                                  break;
2054    
2055                          case MotionNotify:                          case MotionNotify:
# Line 1506  xwin_process_events(void) Line 2064  xwin_process_events(void)
2064                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2065                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2066                                                         CurrentTime);                                                         CurrentTime);
2067                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2068                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2069                                    {
2070                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2071                                                           xevent.xmotion.x, xevent.xmotion.y);
2072                                    }
2073                                    else
2074                                    {
2075                                            /* SeamlessRDP */
2076                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2077                                                           xevent.xmotion.x_root,
2078                                                           xevent.xmotion.y_root);
2079                                    }
2080                                  break;                                  break;
2081    
2082                          case FocusIn:                          case FocusIn:
# Line 1518  xwin_process_events(void) Line 2087  xwin_process_events(void)
2087                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2088                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2089                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2090    
2091                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2092                                    if (!sw)
2093                                            break;
2094    
2095                                    if (sw->id != g_seamless_focused)
2096                                    {
2097                                            seamless_send_focus(sw->id, 0);
2098                                            g_seamless_focused = sw->id;
2099                                    }
2100                                  break;                                  break;
2101    
2102                          case FocusOut:                          case FocusOut:
# Line 1550  xwin_process_events(void) Line 2129  xwin_process_events(void)
2129                                  break;                                  break;
2130    
2131                          case Expose:                          case Expose:
2132                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2133                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2134                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2135                                            xevent.xexpose.height,                                                    g_gc,
2136                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2137                                                      xevent.xexpose.width, xevent.xexpose.height,
2138                                                      xevent.xexpose.x, xevent.xexpose.y);
2139                                    }
2140                                    else
2141                                    {
2142                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2143                                            if (!sw)
2144                                                    break;
2145                                            XCopyArea(g_display, g_backstore,
2146                                                      xevent.xexpose.window, g_gc,
2147                                                      xevent.xexpose.x + sw->xoffset,
2148                                                      xevent.xexpose.y + sw->yoffset,
2149                                                      xevent.xexpose.width,
2150                                                      xevent.xexpose.height, xevent.xexpose.x,
2151                                                      xevent.xexpose.y);
2152                                    }
2153    
2154                                  break;                                  break;
2155    
2156                          case MappingNotify:                          case MappingNotify:
# Line 1583  xwin_process_events(void) Line 2179  xwin_process_events(void)
2179                                  break;                                  break;
2180                          case PropertyNotify:                          case PropertyNotify:
2181                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2182                                    if (xevent.xproperty.window == g_wnd)
2183                                            break;
2184                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2185                                            break;
2186    
2187                                    /* seamless */
2188                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2189                                    if (!sw)
2190                                            break;
2191    
2192                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2193                                        && (xevent.xproperty.state == PropertyNewValue))
2194                                    {
2195                                            sw->state = ewmh_get_window_state(sw->wnd);
2196                                            seamless_send_state(sw->id, sw->state, 0);
2197                                    }
2198    
2199                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2200                                        && (xevent.xproperty.state == PropertyNewValue))
2201                                    {
2202                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2203                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2204                                    }
2205    
2206                                  break;                                  break;
2207                          case MapNotify:                          case MapNotify:
2208                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2209                                            rdp_send_client_window_status(1);
2210                                  break;                                  break;
2211                          case UnmapNotify:                          case UnmapNotify:
2212                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2213                                            rdp_send_client_window_status(0);
2214                                    break;
2215                            case ConfigureNotify:
2216                                    if (!g_seamless_active)
2217                                            break;
2218    
2219                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2220                                    if (!sw)
2221                                            break;
2222    
2223                                    gettimeofday(sw->position_timer, NULL);
2224                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2225                                        1000000)
2226                                    {
2227                                            sw->position_timer->tv_usec +=
2228                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2229                                            sw->position_timer->tv_sec += 1;
2230                                    }
2231                                    else
2232                                    {
2233                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2234                                    }
2235    
2236                                    sw_handle_restack(sw);
2237                                  break;                                  break;
2238                  }                  }
2239          }          }
# Line 1613  ui_select(int rdp_socket) Line 2258  ui_select(int rdp_socket)
2258                          /* User quit */                          /* User quit */
2259                          return 0;                          return 0;
2260    
2261                    if (g_seamless_active)
2262                            sw_check_timers();
2263    
2264                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2265                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2266                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1632  ui_select(int rdp_socket) Line 2280  ui_select(int rdp_socket)
2280    
2281                  /* add redirection handles */                  /* add redirection handles */
2282                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2283                    seamless_select_timeout(&tv);
2284    
2285                  n++;                  n++;
2286    
# Line 1673  ui_create_bitmap(int width, int height, Line 2322  ui_create_bitmap(int width, int height,
2322          uint8 *tdata;          uint8 *tdata;
2323          int bitmap_pad;          int bitmap_pad;
2324    
2325          if (g_server_bpp == 8)          if (g_server_depth == 8)
2326          {          {
2327                  bitmap_pad = 8;                  bitmap_pad = 8;
2328          }          }
# Line 1705  ui_paint_bitmap(int x, int y, int cx, in Line 2354  ui_paint_bitmap(int x, int y, int cx, in
2354          uint8 *tdata;          uint8 *tdata;
2355          int bitmap_pad;          int bitmap_pad;
2356    
2357          if (g_server_bpp == 8)          if (g_server_depth == 8)
2358          {          {
2359                  bitmap_pad = 8;                  bitmap_pad = 8;
2360          }          }
# Line 1725  ui_paint_bitmap(int x, int y, int cx, in Line 2374  ui_paint_bitmap(int x, int y, int cx, in
2374          {          {
2375                  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);
2376                  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);
2377                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2378                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2379                                             x - sw->xoffset, y - sw->yoffset));
2380          }          }
2381          else          else
2382          {          {
2383                  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);
2384                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2385                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2386                                             x - sw->xoffset, y - sw->yoffset));
2387          }          }
2388    
2389          XFree(image);          XFree(image);
# Line 1849  ui_set_cursor(HCURSOR cursor) Line 2504  ui_set_cursor(HCURSOR cursor)
2504  {  {
2505          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2506          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2507            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2508  }  }
2509    
2510  void  void
# Line 1990  ui_set_colourmap(HCOLOURMAP map) Line 2646  ui_set_colourmap(HCOLOURMAP map)
2646                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2647          }          }
2648          else          else
2649            {
2650                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2651                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2652            }
2653  }  }
2654    
2655  void  void
2656  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2657  {  {
2658          XRectangle rect;          g_clip_rectangle.x = x;
2659            g_clip_rectangle.y = y;
2660          rect.x = x;          g_clip_rectangle.width = cx;
2661          rect.y = y;          g_clip_rectangle.height = cy;
2662          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);  
2663  }  }
2664    
2665  void  void
2666  ui_reset_clip(void)  ui_reset_clip(void)
2667  {  {
2668          XRectangle rect;          g_clip_rectangle.x = 0;
2669            g_clip_rectangle.y = 0;
2670          rect.x = 0;          g_clip_rectangle.width = g_width;
2671          rect.y = 0;          g_clip_rectangle.height = g_height;
2672          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);  
2673  }  }
2674    
2675  void  void
# Line 2095  ui_patblt(uint8 opcode, Line 2750  ui_patblt(uint8 opcode,
2750    
2751          if (g_ownbackstore)          if (g_ownbackstore)
2752                  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);
2753            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2754                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2755                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2756  }  }
2757    
2758  void  void
# Line 2105  ui_screenblt(uint8 opcode, Line 2763  ui_screenblt(uint8 opcode,
2763          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2764          if (g_ownbackstore)          if (g_ownbackstore)
2765          {          {
2766                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2767                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2768                          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);  
                 }  
2769          }          }
2770          else          else
2771          {          {
2772                  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);
2773          }          }
2774    
2775            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2776                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2777                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2778    
2779          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2780  }  }
2781    
# Line 2132  ui_memblt(uint8 opcode, Line 2786  ui_memblt(uint8 opcode,
2786  {  {
2787          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2788          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);
2789            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2790                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2791                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2792          if (g_ownbackstore)          if (g_ownbackstore)
2793                  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);
2794          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2178  ui_line(uint8 opcode, Line 2835  ui_line(uint8 opcode,
2835          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2836          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2837          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2838            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2839                                                startx - sw->xoffset, starty - sw->yoffset,
2840                                                endx - sw->xoffset, endy - sw->yoffset));
2841          if (g_ownbackstore)          if (g_ownbackstore)
2842                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2843          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2275  ui_polyline(uint8 opcode, Line 2935  ui_polyline(uint8 opcode,
2935          if (g_ownbackstore)          if (g_ownbackstore)
2936                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2937                             CoordModePrevious);                             CoordModePrevious);
2938    
2939            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2940                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2941    
2942          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2943  }  }
2944    
# Line 2430  ui_draw_text(uint8 font, uint8 flags, ui Line 3094  ui_draw_text(uint8 font, uint8 flags, ui
3094                  switch (text[i])                  switch (text[i])
3095                  {                  {
3096                          case 0xff:                          case 0xff:
3097                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3098                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3099                                  {                                  {
3100                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3101                                          exit(1);                                          for (j = 0; j < length; j++)
3102                                                    fprintf(stderr, "%02x ", text[j]);
3103                                            fprintf(stderr, "\n");
3104                                            i = length = 0;
3105                                            break;
3106                                  }                                  }
3107                                    cache_put_text(text[i + 1], text, text[i + 2]);
3108                                    i += 3;
3109                                    length -= i;
3110                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3111                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3112                                  i = 0;                                  i = 0;
3113                                  break;                                  break;
3114    
3115                          case 0xfe:                          case 0xfe:
3116                                    /* At least one byte needs to follow */
3117                                    if (i + 2 > length)
3118                                    {
3119                                            warning("Skipping short 0xfe command:");
3120                                            for (j = 0; j < length; j++)
3121                                                    fprintf(stderr, "%02x ", text[j]);
3122                                            fprintf(stderr, "\n");
3123                                            i = length = 0;
3124                                            break;
3125                                    }
3126                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3127                                  if (entry != NULL)                                  if (entry->data != NULL)
3128                                  {                                  {
3129                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3130                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3131                                          {                                          {
3132                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3133                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2480  ui_draw_text(uint8 font, uint8 flags, ui Line 3159  ui_draw_text(uint8 font, uint8 flags, ui
3159          if (g_ownbackstore)          if (g_ownbackstore)
3160          {          {
3161                  if (boxcx > 1)                  if (boxcx > 1)
3162                    {
3163                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3164                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3165                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3166                                                    (g_display, g_backstore, sw->wnd, g_gc,
3167                                                     boxx, boxy,
3168                                                     boxcx, boxcy,
3169                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3170                    }
3171                  else                  else
3172                    {
3173                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3174                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3175                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3176                                                    (g_display, g_backstore, sw->wnd, g_gc,
3177                                                     clipx, clipy,
3178                                                     clipcx, clipcy, clipx - sw->xoffset,
3179                                                     clipy - sw->yoffset));
3180                    }
3181          }          }
3182  }  }
3183    
# Line 2530  ui_desktop_restore(uint32 offset, int x, Line 3223  ui_desktop_restore(uint32 offset, int x,
3223          {          {
3224                  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);
3225                  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);
3226                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3227                                            (g_display, g_backstore, sw->wnd, g_gc,
3228                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3229          }          }
3230          else          else
3231          {          {
3232                  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);
3233                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3234                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3235                                             x - sw->xoffset, y - sw->yoffset));
3236          }          }
3237    
3238          XFree(image);          XFree(image);
# Line 2549  void Line 3248  void
3248  ui_end_update(void)  ui_end_update(void)
3249  {  {
3250  }  }
3251    
3252    
3253    void
3254    ui_seamless_begin(BOOL hidden)
3255    {
3256            if (!g_seamless_rdp)
3257                    return;
3258    
3259            if (g_seamless_started)
3260                    return;
3261    
3262            g_seamless_started = True;
3263            g_seamless_hidden = hidden;
3264    
3265            if (!hidden)
3266                    ui_seamless_toggle();
3267    }
3268    
3269    
3270    void
3271    ui_seamless_hide_desktop()
3272    {
3273            if (!g_seamless_rdp)
3274                    return;
3275    
3276            if (!g_seamless_started)
3277                    return;
3278    
3279            if (g_seamless_active)
3280                    ui_seamless_toggle();
3281    
3282            g_seamless_hidden = True;
3283    }
3284    
3285    
3286    void
3287    ui_seamless_unhide_desktop()
3288    {
3289            if (!g_seamless_rdp)
3290                    return;
3291    
3292            if (!g_seamless_started)
3293                    return;
3294    
3295            g_seamless_hidden = False;
3296    
3297            ui_seamless_toggle();
3298    }
3299    
3300    
3301    void
3302    ui_seamless_toggle()
3303    {
3304            if (!g_seamless_rdp)
3305                    return;
3306    
3307            if (!g_seamless_started)
3308                    return;
3309    
3310            if (g_seamless_hidden)
3311                    return;
3312    
3313            if (g_seamless_active)
3314            {
3315                    /* Deactivate */
3316                    while (g_seamless_windows)
3317                    {
3318                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3319                            sw_remove_window(g_seamless_windows);
3320                    }
3321                    XMapWindow(g_display, g_wnd);
3322            }
3323            else
3324            {
3325                    /* Activate */
3326                    XUnmapWindow(g_display, g_wnd);
3327                    seamless_send_sync();
3328            }
3329    
3330            g_seamless_active = !g_seamless_active;
3331    }
3332    
3333    
3334    void
3335    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3336                              unsigned long flags)
3337    {
3338            Window wnd;
3339            XSetWindowAttributes attribs;
3340            XClassHint *classhints;
3341            XSizeHints *sizehints;
3342            XWMHints *wmhints;
3343            long input_mask;
3344            seamless_window *sw, *sw_parent;
3345    
3346            if (!g_seamless_active)
3347                    return;
3348    
3349            /* Ignore CREATEs for existing windows */
3350            sw = sw_get_window_by_id(id);
3351            if (sw)
3352                    return;
3353    
3354            get_window_attribs(&attribs);
3355            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3356                                InputOutput, g_visual,
3357                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3358    
3359            XStoreName(g_display, wnd, "SeamlessRDP");
3360            ewmh_set_wm_name(wnd, "SeamlessRDP");
3361    
3362            mwm_hide_decorations(wnd);
3363    
3364            classhints = XAllocClassHint();
3365            if (classhints != NULL)
3366            {
3367                    classhints->res_name = "rdesktop";
3368                    classhints->res_class = "SeamlessRDP";
3369                    XSetClassHint(g_display, wnd, classhints);
3370                    XFree(classhints);
3371            }
3372    
3373            /* WM_NORMAL_HINTS */
3374            sizehints = XAllocSizeHints();
3375            if (sizehints != NULL)
3376            {
3377                    sizehints->flags = USPosition;
3378                    XSetWMNormalHints(g_display, wnd, sizehints);
3379                    XFree(sizehints);
3380            }
3381    
3382            /* Parent-less transient windows */
3383            if (parent == 0xFFFFFFFF)
3384            {
3385                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3386                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3387                       using some other hints. */
3388                    ewmh_set_window_popup(wnd);
3389            }
3390            /* Normal transient windows */
3391            else if (parent != 0x00000000)
3392            {
3393                    sw_parent = sw_get_window_by_id(parent);
3394                    if (sw_parent)
3395                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3396                    else
3397                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3398            }
3399    
3400            if (flags & SEAMLESSRDP_CREATE_MODAL)
3401            {
3402                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3403                       somewhat at least */
3404                    if (parent == 0x00000000)
3405                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3406                    ewmh_set_window_modal(wnd);
3407            }
3408    
3409            /* FIXME: Support for Input Context:s */
3410    
3411            get_input_mask(&input_mask);
3412            input_mask |= PropertyChangeMask;
3413    
3414            XSelectInput(g_display, wnd, input_mask);
3415    
3416            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3417               seamless window, we could try to close the window on the
3418               serverside, instead of terminating rdesktop */
3419            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3420    
3421            sw = xmalloc(sizeof(seamless_window));
3422            sw->wnd = wnd;
3423            sw->id = id;
3424            sw->behind = 0;
3425            sw->group = sw_find_group(group, False);
3426            sw->group->refcnt++;
3427            sw->xoffset = 0;
3428            sw->yoffset = 0;
3429            sw->width = 0;
3430            sw->height = 0;
3431            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3432            sw->desktop = 0;
3433            sw->position_timer = xmalloc(sizeof(struct timeval));
3434            timerclear(sw->position_timer);
3435    
3436            sw->outstanding_position = False;
3437            sw->outpos_serial = 0;
3438            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3439            sw->outpos_width = sw->outpos_height = 0;
3440    
3441            sw->next = g_seamless_windows;
3442            g_seamless_windows = sw;
3443    
3444            /* WM_HINTS */
3445            wmhints = XAllocWMHints();
3446            if (wmhints)
3447            {
3448                    wmhints->flags = WindowGroupHint;
3449                    wmhints->window_group = sw->group->wnd;
3450                    XSetWMHints(g_display, sw->wnd, wmhints);
3451                    XFree(wmhints);
3452            }
3453    }
3454    
3455    
3456    void
3457    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3458    {
3459            seamless_window *sw;
3460    
3461            if (!g_seamless_active)
3462                    return;
3463    
3464            sw = sw_get_window_by_id(id);
3465            if (!sw)
3466            {
3467                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3468                    return;
3469            }
3470    
3471            XDestroyWindow(g_display, sw->wnd);
3472            sw_remove_window(sw);
3473    }
3474    
3475    
3476    void
3477    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3478    {
3479            seamless_window *sw;
3480    
3481            if (!g_seamless_active)
3482                    return;
3483    
3484            sw = sw_get_window_by_id(id);
3485            if (!sw)
3486            {
3487                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3488                    return;
3489            }
3490    
3491            /* We ignore server updates until it has handled our request. */
3492            if (sw->outstanding_position)
3493                    return;
3494    
3495            if (!width || !height)
3496                    /* X11 windows must be at least 1x1 */
3497                    return;
3498    
3499            sw->xoffset = x;
3500            sw->yoffset = y;
3501            sw->width = width;
3502            sw->height = height;
3503    
3504            /* If we move the window in a maximized state, then KDE won't
3505               accept restoration */
3506            switch (sw->state)
3507            {
3508                    case SEAMLESSRDP_MINIMIZED:
3509                    case SEAMLESSRDP_MAXIMIZED:
3510                            return;
3511            }
3512    
3513            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3514            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3515    }
3516    
3517    
3518    void
3519    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3520    {
3521            seamless_window *sw;
3522    
3523            if (!g_seamless_active)
3524                    return;
3525    
3526            sw = sw_get_window_by_id(id);
3527            if (!sw)
3528            {
3529                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3530                    return;
3531            }
3532    
3533            if (behind)
3534            {
3535                    seamless_window *sw_behind;
3536                    Window wnds[2];
3537    
3538                    sw_behind = sw_get_window_by_id(behind);
3539                    if (!sw_behind)
3540                    {
3541                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3542                                    behind);
3543                            return;
3544                    }
3545    
3546                    wnds[1] = sw_behind->wnd;
3547                    wnds[0] = sw->wnd;
3548    
3549                    XRestackWindows(g_display, wnds, 2);
3550            }
3551            else
3552            {
3553                    XRaiseWindow(g_display, sw->wnd);
3554            }
3555    
3556            sw_restack_window(sw, behind);
3557    }
3558    
3559    
3560    void
3561    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3562    {
3563            seamless_window *sw;
3564    
3565            if (!g_seamless_active)
3566                    return;
3567    
3568            sw = sw_get_window_by_id(id);
3569            if (!sw)
3570            {
3571                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3572                    return;
3573            }
3574    
3575            /* FIXME: Might want to convert the name for non-EWMH WMs */
3576            XStoreName(g_display, sw->wnd, title);
3577            ewmh_set_wm_name(sw->wnd, title);
3578    }
3579    
3580    
3581    void
3582    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3583    {
3584            seamless_window *sw;
3585    
3586            if (!g_seamless_active)
3587                    return;
3588    
3589            sw = sw_get_window_by_id(id);
3590            if (!sw)
3591            {
3592                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3593                    return;
3594            }
3595    
3596            switch (state)
3597            {
3598                    case SEAMLESSRDP_NORMAL:
3599                    case SEAMLESSRDP_MAXIMIZED:
3600                            ewmh_change_state(sw->wnd, state);
3601                            XMapWindow(g_display, sw->wnd);
3602                            break;
3603                    case SEAMLESSRDP_MINIMIZED:
3604                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3605                               the Window Manager should probably just ignore the request, since
3606                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3607                               such as minimization, rather than an independent state." Besides,
3608                               XIconifyWindow is easier. */
3609                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3610                            {
3611                                    XWMHints *hints;
3612                                    hints = XGetWMHints(g_display, sw->wnd);
3613                                    if (hints)
3614                                    {
3615                                            hints->flags |= StateHint;
3616                                            hints->initial_state = IconicState;
3617                                            XSetWMHints(g_display, sw->wnd, hints);
3618                                            XFree(hints);
3619                                    }
3620                                    XMapWindow(g_display, sw->wnd);
3621                            }
3622                            else
3623                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3624                            break;
3625                    default:
3626                            warning("SeamlessRDP: Invalid state %d\n", state);
3627                            break;
3628            }
3629    
3630            sw->state = state;
3631    }
3632    
3633    
3634    void
3635    ui_seamless_syncbegin(unsigned long flags)
3636    {
3637            if (!g_seamless_active)
3638                    return;
3639    
3640            /* Destroy all seamless windows */
3641            while (g_seamless_windows)
3642            {
3643                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3644                    sw_remove_window(g_seamless_windows);
3645            }
3646    }
3647    
3648    
3649    void
3650    ui_seamless_ack(unsigned int serial)
3651    {
3652            seamless_window *sw;
3653            for (sw = g_seamless_windows; sw; sw = sw->next)
3654            {
3655                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3656                    {
3657                            sw->xoffset = sw->outpos_xoffset;
3658                            sw->yoffset = sw->outpos_yoffset;
3659                            sw->width = sw->outpos_width;
3660                            sw->height = sw->outpos_height;
3661                            sw->outstanding_position = False;
3662    
3663                            /* Do a complete redraw of the window as part of the
3664                               completion of the move. This is to remove any
3665                               artifacts caused by our lack of synchronization. */
3666                            XCopyArea(g_display, g_backstore,
3667                                      sw->wnd, g_gc,
3668                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3669    
3670                            break;
3671                    }
3672            }
3673    }

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

  ViewVC Help
Powered by ViewVC 1.1.26