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

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

sourceforge.net/trunk/rdesktop/xwin.c revision 988 by astrand, Thu Aug 25 20:27:45 2005 UTC jpeg/rdesktop/trunk/xwin.c revision 1508 by dpavlin, Mon Jul 20 16:47:49 2009 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2005     Copyright (C) Matthew Chapman 1999-2008
5       Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB
6    
7     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 21 
21    
22  #include <X11/Xlib.h>  #include <X11/Xlib.h>
23  #include <X11/Xutil.h>  #include <X11/Xutil.h>
24    #include <X11/Xproto.h>
25  #include <unistd.h>  #include <unistd.h>
26  #include <sys/time.h>  #include <sys/time.h>
27  #include <time.h>  #include <time.h>
# Line 28  Line 30 
30  #include "rdesktop.h"  #include "rdesktop.h"
31  #include "xproto.h"  #include "xproto.h"
32    
33    /* DJ globals begin */
34    extern uint8 * g_bitmap_data;
35    extern uint8 * g_bitmap_data_last_write;
36    extern uint32 g_pixels_changed;
37    extern unsigned long long g_time_last_change;
38    /* DJ globals end */
39    
40  extern int g_width;  extern int g_width;
41  extern int g_height;  extern int g_height;
42  extern int g_xpos;  extern int g_xpos;
43  extern int g_ypos;  extern int g_ypos;
44  extern int g_pos;  extern int g_pos;
45  extern BOOL g_sendmotion;  extern RD_BOOL g_sendmotion;
46  extern BOOL g_fullscreen;  extern RD_BOOL g_fullscreen;
47  extern BOOL g_grab_keyboard;  extern RD_BOOL g_grab_keyboard;
48  extern BOOL g_hide_decorations;  extern RD_BOOL g_hide_decorations;
49  extern char g_title[];  extern char g_title[];
50  extern int g_server_bpp;  /* Color depth of the RDP session.
51       As of RDP 5.1, it may be 8, 15, 16 or 24. */
52    extern int g_server_depth;
53  extern int g_win_button_size;  extern int g_win_button_size;
54    
55  Display *g_display;  Display *g_display;
# Line 46  Time g_last_gesturetime; Line 57  Time g_last_gesturetime;
57  static int g_x_socket;  static int g_x_socket;
58  static Screen *g_screen;  static Screen *g_screen;
59  Window g_wnd;  Window g_wnd;
60    
61    /* SeamlessRDP support */
62    typedef struct _seamless_group
63    {
64            Window wnd;
65            unsigned long id;
66            unsigned int refcnt;
67    } seamless_group;
68    typedef struct _seamless_window
69    {
70            Window wnd;
71            unsigned long id;
72            unsigned long behind;
73            seamless_group *group;
74            int xoffset, yoffset;
75            int width, height;
76            int state;              /* normal/minimized/maximized. */
77            unsigned int desktop;
78            struct timeval *position_timer;
79    
80            RD_BOOL outstanding_position;
81            unsigned int outpos_serial;
82            int outpos_xoffset, outpos_yoffset;
83            int outpos_width, outpos_height;
84    
85            unsigned int icon_size;
86            unsigned int icon_offset;
87            char icon_buffer[32 * 32 * 4];
88    
89            struct _seamless_window *next;
90    } seamless_window;
91    static seamless_window *g_seamless_windows = NULL;
92    static unsigned long g_seamless_focused = 0;
93    static RD_BOOL g_seamless_started = False;      /* Server end is up and running */
94    static RD_BOOL g_seamless_active = False;       /* We are currently in seamless mode */
95    static RD_BOOL g_seamless_hidden = False;       /* Desktop is hidden on server */
96    static RD_BOOL g_seamless_broken_restack = False;       /* WM does not properly restack */
97    extern RD_BOOL g_seamless_rdp;
98    
99  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
100  BOOL g_enable_compose = False;  RD_BOOL g_enable_compose = False;
101  BOOL g_Unobscured;              /* used for screenblt */  RD_BOOL g_Unobscured;           /* used for screenblt */
102  static GC g_gc = NULL;  static GC g_gc = NULL;
103  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
104  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
105    static XRectangle g_clip_rectangle;
106  static Visual *g_visual;  static Visual *g_visual;
107    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
108       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
109       as far as we're concerned. */
110  static int g_depth;  static int g_depth;
111    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
112       This may be larger than g_depth, in which case some of the bits would
113       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
114  static int g_bpp;  static int g_bpp;
115  static XIM g_IM;  static XIM g_IM;
116  static XIC g_IC;  static XIC g_IC;
117  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
118    /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
119       to physical (1-based) indices. */
120    static unsigned char g_pointer_log_to_phys_map[32];
121  static Cursor g_current_cursor;  static Cursor g_current_cursor;
122  static HCURSOR g_null_cursor = NULL;  static RD_HCURSOR g_null_cursor = NULL;
123  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
124  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
125  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
126  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  static RD_BOOL g_focused;
127    static RD_BOOL g_mouse_in_wnd;
128    /* Indicates that:
129       1) visual has 15, 16 or 24 depth and the same color channel masks
130          as its RDP equivalent (implies X server is LE),
131       2) host is LE
132       This will trigger an optimization whose real value is questionable.
133    */
134    static RD_BOOL g_compatible_arch;
135    /* Indicates whether RDP's bitmaps and our XImages have the same
136       binary format. If so, we can avoid an expensive translation.
137       Note that this can be true when g_compatible_arch is false,
138       e.g.:
139      
140         RDP(LE) <-> host(BE) <-> X-Server(LE)
141        
142       ('host' is the machine running rdesktop; the host simply memcpy's
143        so its endianess doesn't matter)
144     */
145    static RD_BOOL g_no_translate_image = False;
146    
147  /* endianness */  /* endianness */
148  static BOOL g_host_be;  static RD_BOOL g_host_be;
149  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
150  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
151  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
152    
153  /* software backing store */  /* software backing store */
154  extern BOOL g_ownbackstore;  extern RD_BOOL g_ownbackstore;
155  static Pixmap g_backstore = 0;  static Pixmap g_backstore = 0;
156    
157  /* Moving in single app mode */  /* Moving in single app mode */
158  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
159  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
160  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
161    static RD_BOOL g_using_full_workarea = False;
162    
163  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
164  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
165  #endif  #endif
166    
167  /* MWM decorations */  /* MWM decorations */
# Line 91  extern BOOL g_rdpsnd; Line 169  extern BOOL g_rdpsnd;
169  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
170  typedef struct  typedef struct
171  {  {
172          uint32 flags;          unsigned long flags;
173          uint32 functions;          unsigned long functions;
174          uint32 decorations;          unsigned long decorations;
175          sint32 inputMode;          long inputMode;
176          uint32 status;          unsigned long status;
177  }  }
178  PropMotifWmHints;  PropMotifWmHints;
179    
# Line 107  typedef struct Line 185  typedef struct
185  }  }
186  PixelColour;  PixelColour;
187    
188    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
189            do { \
190                    seamless_window *sw; \
191                    XRectangle rect; \
192                    if (!g_seamless_windows) break; \
193                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
194                        rect.x = g_clip_rectangle.x - sw->xoffset; \
195                        rect.y = g_clip_rectangle.y - sw->yoffset; \
196                        rect.width = g_clip_rectangle.width; \
197                        rect.height = g_clip_rectangle.height; \
198                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
199                        func args; \
200                    } \
201                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
202            } while (0)
203    
204    static void
205    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
206    {
207            points[0].x -= xoffset;
208            points[0].y -= yoffset;
209            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
210            points[0].x += xoffset;
211            points[0].y += yoffset;
212    }
213    
214    static void
215    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
216    {
217            points[0].x -= xoffset;
218            points[0].y -= yoffset;
219            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
220            points[0].x += xoffset;
221            points[0].y += yoffset;
222    }
223    
224  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
225  { \  { \
226          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
227            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
228          if (g_ownbackstore) \          if (g_ownbackstore) \
229                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
230  }  }
# Line 125  PixelColour; Line 239  PixelColour;
239          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
240          if (g_ownbackstore) \          if (g_ownbackstore) \
241                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
242            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
243  }  }
244    
245  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 133  PixelColour; Line 248  PixelColour;
248          { \          { \
249                  case 0: /* Outline */ \                  case 0: /* Outline */ \
250                          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); \
251                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
252                          if (g_ownbackstore) \                          if (g_ownbackstore) \
253                                  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); \
254                          break; \                          break; \
255                  case 1: /* Filled */ \                  case 1: /* Filled */ \
256                          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); \
257                                   cx, cy, 0, 360*64); \                          ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
258                          if (g_ownbackstore) \                          if (g_ownbackstore) \
259                                  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); \
260                          break; \                          break; \
261          } \          } \
262  }  }
263    
264  /* colour maps */  /* colour maps */
265  extern BOOL g_owncolmap;  extern RD_BOOL g_owncolmap;
266  static Colormap g_xcolmap;  static Colormap g_xcolmap;
267  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
268    
269  #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] )
270  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
271  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
272    
# Line 176  static int rop2_map[] = { Line 292  static int rop2_map[] = {
292  #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]); }
293  #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); }
294    
295    static seamless_window *
296    sw_get_window_by_id(unsigned long id)
297    {
298            seamless_window *sw;
299            for (sw = g_seamless_windows; sw; sw = sw->next)
300            {
301                    if (sw->id == id)
302                            return sw;
303            }
304            return NULL;
305    }
306    
307    
308    static seamless_window *
309    sw_get_window_by_wnd(Window wnd)
310    {
311            seamless_window *sw;
312            for (sw = g_seamless_windows; sw; sw = sw->next)
313            {
314                    if (sw->wnd == wnd)
315                            return sw;
316            }
317            return NULL;
318    }
319    
320    
321  static void  static void
322  mwm_hide_decorations(void)  sw_remove_window(seamless_window * win)
323    {
324            seamless_window *sw, **prevnext = &g_seamless_windows;
325            for (sw = g_seamless_windows; sw; sw = sw->next)
326            {
327                    if (sw == win)
328                    {
329                            *prevnext = sw->next;
330                            sw->group->refcnt--;
331                            if (sw->group->refcnt == 0)
332                            {
333                                    XDestroyWindow(g_display, sw->group->wnd);
334                                    xfree(sw->group);
335                            }
336                            xfree(sw->position_timer);
337                            xfree(sw);
338                            return;
339                    }
340                    prevnext = &sw->next;
341            }
342            return;
343    }
344    
345    
346    /* Move all windows except wnd to new desktop */
347    static void
348    sw_all_to_desktop(Window wnd, unsigned int desktop)
349    {
350            seamless_window *sw;
351            for (sw = g_seamless_windows; sw; sw = sw->next)
352            {
353                    if (sw->wnd == wnd)
354                            continue;
355                    if (sw->desktop != desktop)
356                    {
357                            ewmh_move_to_desktop(sw->wnd, desktop);
358                            sw->desktop = desktop;
359                    }
360            }
361    }
362    
363    
364    /* Send our position */
365    static void
366    sw_update_position(seamless_window * sw)
367    {
368            XWindowAttributes wa;
369            int x, y;
370            Window child_return;
371            unsigned int serial;
372    
373            XGetWindowAttributes(g_display, sw->wnd, &wa);
374            XTranslateCoordinates(g_display, sw->wnd, wa.root,
375                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
376    
377            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
378    
379            sw->outstanding_position = True;
380            sw->outpos_serial = serial;
381    
382            sw->outpos_xoffset = x;
383            sw->outpos_yoffset = y;
384            sw->outpos_width = wa.width;
385            sw->outpos_height = wa.height;
386    }
387    
388    
389    /* Check if it's time to send our position */
390    static void
391    sw_check_timers()
392    {
393            seamless_window *sw;
394            struct timeval now;
395    
396            gettimeofday(&now, NULL);
397            for (sw = g_seamless_windows; sw; sw = sw->next)
398            {
399                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
400                    {
401                            timerclear(sw->position_timer);
402                            sw_update_position(sw);
403                    }
404            }
405    }
406    
407    
408    static void
409    sw_restack_window(seamless_window * sw, unsigned long behind)
410    {
411            seamless_window *sw_above;
412    
413            /* Remove window from stack */
414            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
415            {
416                    if (sw_above->behind == sw->id)
417                            break;
418            }
419    
420            if (sw_above)
421                    sw_above->behind = sw->behind;
422    
423            /* And then add it at the new position */
424            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
425            {
426                    if (sw_above->behind == behind)
427                            break;
428            }
429    
430            if (sw_above)
431                    sw_above->behind = sw->id;
432    
433            sw->behind = behind;
434    }
435    
436    
437    static void
438    sw_handle_restack(seamless_window * sw)
439    {
440            Status status;
441            Window root, parent, *children;
442            unsigned int nchildren, i;
443            seamless_window *sw_below;
444    
445            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
446                                &root, &parent, &children, &nchildren);
447            if (!status || !nchildren)
448                    return;
449    
450            sw_below = NULL;
451    
452            i = 0;
453            while (children[i] != sw->wnd)
454            {
455                    i++;
456                    if (i >= nchildren)
457                            goto end;
458            }
459    
460            for (i++; i < nchildren; i++)
461            {
462                    sw_below = sw_get_window_by_wnd(children[i]);
463                    if (sw_below)
464                            break;
465            }
466    
467            if (!sw_below && !sw->behind)
468                    goto end;
469            if (sw_below && (sw_below->id == sw->behind))
470                    goto end;
471    
472            if (sw_below)
473            {
474                    seamless_send_zchange(sw->id, sw_below->id, 0);
475                    sw_restack_window(sw, sw_below->id);
476            }
477            else
478            {
479                    seamless_send_zchange(sw->id, 0, 0);
480                    sw_restack_window(sw, 0);
481            }
482    
483          end:
484            XFree(children);
485    }
486    
487    
488    static seamless_group *
489    sw_find_group(unsigned long id, RD_BOOL dont_create)
490    {
491            seamless_window *sw;
492            seamless_group *sg;
493            XSetWindowAttributes attribs;
494    
495            for (sw = g_seamless_windows; sw; sw = sw->next)
496            {
497                    if (sw->group->id == id)
498                            return sw->group;
499            }
500    
501            if (dont_create)
502                    return NULL;
503    
504            sg = xmalloc(sizeof(seamless_group));
505    
506            sg->wnd =
507                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
508                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
509    
510            sg->id = id;
511            sg->refcnt = 0;
512    
513            return sg;
514    }
515    
516    
517    static void
518    mwm_hide_decorations(Window wnd)
519  {  {
520          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
521          Atom hintsatom;          Atom hintsatom;
# Line 194  mwm_hide_decorations(void) Line 532  mwm_hide_decorations(void)
532                  return;                  return;
533          }          }
534    
535          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
536                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
537    
538    }
539    
540    typedef struct _sw_configurenotify_context
541    {
542            Window window;
543            unsigned long serial;
544    } sw_configurenotify_context;
545    
546    /* Predicate procedure for sw_wait_configurenotify */
547    static Bool
548    sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg)
549    {
550            sw_configurenotify_context *context = (sw_configurenotify_context *) arg;
551            if (xevent->xany.type == ConfigureNotify
552                && xevent->xconfigure.window == context->window
553                && xevent->xany.serial >= context->serial)
554                    return True;
555    
556            return False;
557    }
558    
559    /* Wait for a ConfigureNotify, with a equal or larger serial, on the
560       specified window. The event will be removed from the queue. We
561       could use XMaskEvent(StructureNotifyMask), but we would then risk
562       throwing away crucial events like DestroyNotify.
563    
564       After a ConfigureWindow, according to ICCCM section 4.1.5, we
565       should recieve a ConfigureNotify, either a real or synthetic
566       one. This indicates that the configure has been "completed".
567       However, some WMs such as several versions of Metacity fails to
568       send synthetic events. See bug
569       http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
570       timeout to avoid a hang. Tk uses the same approach. */
571    static void
572    sw_wait_configurenotify(Window wnd, unsigned long serial)
573    {
574            XEvent xevent;
575            sw_configurenotify_context context;
576            struct timeval now;
577            struct timeval nextsecond;
578            RD_BOOL got = False;
579    
580            context.window = wnd;
581            context.serial = serial;
582    
583            gettimeofday(&nextsecond, NULL);
584            nextsecond.tv_sec += 1;
585    
586            do
587            {
588                    if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context))
589                    {
590                            got = True;
591                            break;
592                    }
593                    usleep(100000);
594                    gettimeofday(&now, NULL);
595            }
596            while (timercmp(&now, &nextsecond, <));
597    
598            if (!got)
599            {
600                    warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
601            }
602    }
603    
604    /* Get the toplevel window, in case of reparenting */
605    static Window
606    sw_get_toplevel(Window wnd)
607    {
608            Window root, parent;
609            Window *child_list;
610            unsigned int num_children;
611    
612            while (1)
613            {
614                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
615                    if (root == parent)
616                    {
617                            break;
618                    }
619                    else if (!parent)
620                    {
621                            warning("Internal error: sw_get_toplevel called with root window\n");
622                    }
623    
624                    wnd = parent;
625            }
626    
627            return wnd;
628    }
629    
630    
631    /* Check if wnd is already behind a window wrt stacking order */
632    static RD_BOOL
633    sw_window_is_behind(Window wnd, Window behind)
634    {
635            Window dummy1, dummy2;
636            Window *child_list;
637            unsigned int num_children;
638            unsigned int i;
639            RD_BOOL found_behind = False;
640            RD_BOOL found_wnd = False;
641    
642            wnd = sw_get_toplevel(wnd);
643            behind = sw_get_toplevel(behind);
644    
645            XQueryTree(g_display, RootWindowOfScreen(g_screen), &dummy1, &dummy2, &child_list,
646                       &num_children);
647    
648            for (i = num_children - 1; i >= 0; i--)
649            {
650                    if (child_list[i] == behind)
651                    {
652                            found_behind = True;
653                    }
654                    else if (child_list[i] == wnd)
655                    {
656                            found_wnd = True;
657                            break;
658                    }
659            }
660    
661            if (child_list)
662                    XFree(child_list);
663    
664            if (!found_wnd)
665            {
666                    warning("sw_window_is_behind: Unable to find window 0x%lx\n", wnd);
667    
668                    if (!found_behind)
669                    {
670                            warning("sw_window_is_behind: Unable to find behind window 0x%lx\n",
671                                    behind);
672                    }
673            }
674    
675            return found_behind;
676    }
677    
678    
679    /* Test if the window manager correctly handles window restacking. In
680       particular, we are testing if it's possible to place a window
681       between two other windows. Many WMs such as Metacity can only stack
682       windows on the top or bottom. The window creation should mostly
683       match ui_seamless_create_window. */
684    static void
685    seamless_restack_test()
686    {
687            /* The goal is to have the middle window between top and
688               bottom.  The middle window is initially at the top,
689               though. */
690            Window wnds[3];         /* top, middle and bottom */
691            int i;
692            XEvent xevent;
693            XWindowChanges values;
694            unsigned long restack_serial;
695    
696            for (i = 0; i < 3; i++)
697            {
698                    char name[64];
699                    wnds[i] =
700                            XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 20, 20,
701                                                0, 0, 0);
702                    snprintf(name, sizeof(name), "SeamlessRDP restack test - window %d", i);
703                    XStoreName(g_display, wnds[i], name);
704                    ewmh_set_wm_name(wnds[i], name);
705    
706                    /* Hide decorations. Often this means that no
707                       reparenting will be done, which makes the restack
708                       easier. Besides, we want to mimic our other
709                       seamless windows as much as possible. We must still
710                       handle the case with reparenting, though. */
711                    mwm_hide_decorations(wnds[i]);
712    
713                    /* Prevent windows from appearing in task bar */
714                    XSetTransientForHint(g_display, wnds[i], RootWindowOfScreen(g_screen));
715                    ewmh_set_window_popup(wnds[i]);
716    
717                    /* We need to catch MapNotify/ConfigureNotify */
718                    XSelectInput(g_display, wnds[i], StructureNotifyMask);
719            }
720    
721            /* Map Windows. Currently, we assume that XMapRaised places
722               the window on the top of the stack. Should be fairly safe;
723               the window is configured before it's mapped. */
724            XMapRaised(g_display, wnds[2]); /* bottom */
725            do
726            {
727                    XWindowEvent(g_display, wnds[2], StructureNotifyMask, &xevent);
728            }
729            while (xevent.type != MapNotify);
730            XMapRaised(g_display, wnds[0]); /* top */
731            do
732            {
733                    XWindowEvent(g_display, wnds[0], StructureNotifyMask, &xevent);
734            }
735            while (xevent.type != MapNotify);
736            XMapRaised(g_display, wnds[1]); /* middle */
737            do
738            {
739                    XWindowEvent(g_display, wnds[1], StructureNotifyMask, &xevent);
740            }
741            while (xevent.type != MapNotify);
742    
743            /* The stacking order should now be 1 - 0 - 2 */
744            if (!sw_window_is_behind(wnds[0], wnds[1]) || !sw_window_is_behind(wnds[2], wnds[1]))
745            {
746                    /* Ok, technically a WM is allowed to stack windows arbitrarily, but... */
747                    warning("Broken Window Manager: Unable to test window restacking\n");
748                    g_seamless_broken_restack = True;
749                    for (i = 0; i < 3; i++)
750                            XDestroyWindow(g_display, wnds[i]);
751                    return;
752            }
753    
754            /* Restack, using XReconfigureWMWindow, which should correctly
755               handle reparented windows as well as nonreparenting WMs. */
756            values.stack_mode = Below;
757            values.sibling = wnds[0];
758            restack_serial = XNextRequest(g_display);
759            XReconfigureWMWindow(g_display, wnds[1], DefaultScreen(g_display), CWStackMode | CWSibling,
760                                 &values);
761            sw_wait_configurenotify(wnds[1], restack_serial);
762    
763            /* Now verify that middle is behind top but not behind
764               bottom */
765            if (!sw_window_is_behind(wnds[1], wnds[0]))
766            {
767                    warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n");
768                    g_seamless_broken_restack = True;
769            }
770            else if (sw_window_is_behind(wnds[1], wnds[2]))
771            {
772                    warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n");
773                    g_seamless_broken_restack = True;
774            }
775    
776            /* Destroy windows */
777            for (i = 0; i < 3; i++)
778                    XDestroyWindow(g_display, wnds[i]);
779  }  }
780    
781  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 229  mwm_hide_decorations(void) Line 809  mwm_hide_decorations(void)
809  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
810                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
811    
812    /* The following macros output the same octet sequences
813       on both BE and LE hosts: */
814    
815  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
816  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
817  #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 823  static uint32
823  translate_colour(uint32 colour)  translate_colour(uint32 colour)
824  {  {
825          PixelColour pc;          PixelColour pc;
826          switch (g_server_bpp)          switch (g_server_depth)
827          {          {
828                  case 15:                  case 15:
829                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 249  translate_colour(uint32 colour) Line 832  translate_colour(uint32 colour)
832                          SPLITCOLOUR16(colour, pc);                          SPLITCOLOUR16(colour, pc);
833                          break;                          break;
834                  case 24:                  case 24:
835                    case 32:
836                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
837                          break;                          break;
838                    default:
839                            /* Avoid warning */
840                            pc.red = 0;
841                            pc.green = 0;
842                            pc.blue = 0;
843                            break;
844          }          }
845          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
846  }  }
# Line 302  translate8to16(const uint8 * data, uint8 Line 892  translate8to16(const uint8 * data, uint8
892  {  {
893          uint16 value;          uint16 value;
894    
895          if (g_arch_match)          if (g_compatible_arch)
896          {          {
897                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
898                  REPEAT2                  REPEAT2
# Line 336  translate8to24(const uint8 * data, uint8 Line 926  translate8to24(const uint8 * data, uint8
926  {  {
927          uint32 value;          uint32 value;
928    
929          if (g_xserver_be)          if (g_compatible_arch)
930          {          {
931                  while (out < end)                  while (out < end)
932                  {                  {
# Line 359  translate8to32(const uint8 * data, uint8 Line 949  translate8to32(const uint8 * data, uint8
949  {  {
950          uint32 value;          uint32 value;
951    
952          if (g_arch_match)          if (g_compatible_arch)
953          {          {
954                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
955                  REPEAT4                  REPEAT4
# Line 431  translate15to24(const uint16 * data, uin Line 1021  translate15to24(const uint16 * data, uin
1021          uint16 pixel;          uint16 pixel;
1022          PixelColour pc;          PixelColour pc;
1023    
1024          if (g_arch_match)          if (g_compatible_arch)
1025          {          {
1026                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1027                  REPEAT3                  REPEAT3
# Line 481  translate15to32(const uint16 * data, uin Line 1071  translate15to32(const uint16 * data, uin
1071          uint32 value;          uint32 value;
1072          PixelColour pc;          PixelColour pc;
1073    
1074          if (g_arch_match)          if (g_compatible_arch)
1075          {          {
1076                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1077                  REPEAT4                  REPEAT4
# Line 589  translate16to24(const uint16 * data, uin Line 1179  translate16to24(const uint16 * data, uin
1179          uint16 pixel;          uint16 pixel;
1180          PixelColour pc;          PixelColour pc;
1181    
1182          if (g_arch_match)          if (g_compatible_arch)
1183          {          {
1184                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1185                  REPEAT3                  REPEAT3
# Line 659  translate16to32(const uint16 * data, uin Line 1249  translate16to32(const uint16 * data, uin
1249          uint32 value;          uint32 value;
1250          PixelColour pc;          PixelColour pc;
1251    
1252          if (g_arch_match)          if (g_compatible_arch)
1253          {          {
1254                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1255                  REPEAT4                  REPEAT4
# Line 788  translate24to32(const uint8 * data, uint Line 1378  translate24to32(const uint8 * data, uint
1378          uint32 value;          uint32 value;
1379          PixelColour pc;          PixelColour pc;
1380    
1381          if (g_arch_match)          if (g_compatible_arch)
1382          {          {
1383                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1384  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 802  translate24to32(const uint8 * data, uint Line 1392  translate24to32(const uint8 * data, uint
1392  #else  #else
1393                  REPEAT4                  REPEAT4
1394                  (                  (
1395                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1396                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1397                          data += 3;                   out += 4;
1398                     data += 3;
1399                  )                  )
1400  #endif  #endif
1401                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 842  translate_image(int width, int height, u Line 1433  translate_image(int width, int height, u
1433          uint8 *out;          uint8 *out;
1434          uint8 *end;          uint8 *end;
1435    
1436          /* if server and xserver bpp match, */          /*
1437          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1438          /* just return data */             and arch(endian) matches, no need to translate:
1439          if (g_arch_match)             just return data.
1440               Note: select_visual should've already ensured g_no_translate
1441               is only set for compatible depths, but the RDP depth might've
1442               changed during connection negotiations.
1443             */
1444    
1445            /* todo */
1446            if (g_server_depth == 32 && g_depth == 24)
1447          {          {
1448                  if (g_depth == 15 && g_server_bpp == 15)                  return data;
1449                          return data;          }
1450                  if (g_depth == 16 && g_server_bpp == 16)  
1451                          return data;          if (g_no_translate_image)
1452                  if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)          {
1453                    if ((g_depth == 15 && g_server_depth == 15) ||
1454                        (g_depth == 16 && g_server_depth == 16) ||
1455                        (g_depth == 24 && g_server_depth == 24))
1456                          return data;                          return data;
1457          }          }
1458    
# Line 859  translate_image(int width, int height, u Line 1460  translate_image(int width, int height, u
1460          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1461          end = out + size;          end = out + size;
1462    
1463          switch (g_server_bpp)          switch (g_server_depth)
1464          {          {
1465                  case 24:                  case 24:
1466                          switch (g_bpp)                          switch (g_bpp)
# Line 924  translate_image(int width, int height, u Line 1525  translate_image(int width, int height, u
1525          return out;          return out;
1526  }  }
1527    
1528  BOOL  static void
1529    xwin_refresh_pointer_map(void)
1530    {
1531            unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
1532            int i, pointer_buttons;
1533    
1534            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1535            if (pointer_buttons > sizeof(phys_to_log_map))
1536                    pointer_buttons = sizeof(phys_to_log_map);
1537    
1538            /* if multiple physical buttons map to the same logical button, then
1539             * use the lower numbered physical one */
1540            for (i = pointer_buttons - 1; i >= 0; i--)
1541            {
1542                    /* a user could specify arbitrary values for the logical button
1543                     * number, ignore any that are abnormally large */
1544                    if (phys_to_log_map[i] > sizeof(g_pointer_log_to_phys_map))
1545                            continue;
1546                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1547            }
1548    }
1549    
1550    RD_BOOL
1551  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1552  {  {
1553          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 957  calculate_shifts(uint32 mask, int *shift Line 1580  calculate_shifts(uint32 mask, int *shift
1580          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1581  }  }
1582    
1583  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1584  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1585     */
1586    static unsigned
1587    calculate_mask_weight(uint32 mask)
1588    {
1589            unsigned weight = 0;
1590            do
1591            {
1592                    weight += (mask & 1);
1593            }
1594            while (mask >>= 1);
1595            return weight;
1596    }
1597    
1598    static RD_BOOL
1599    select_visual(int screen_num)
1600  {  {
         XVisualInfo vi;  
1601          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1602          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1603          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1604          XVisualInfo template;          XVisualInfo template;
1605          Bool TrueColorVisual = False;          int i;
1606            unsigned red_weight, blue_weight, green_weight;
1607    
1608          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1609          if (g_display == NULL)  
1610            if (g_server_depth == -1)
1611          {          {
1612                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1613          }          }
1614    
1615          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1616          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1617          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1618          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1619                    XCloseDisplay(g_display);
1620                    return False;
1621            }
1622    
1623          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1624          template.class = TrueColor;          template.class = TrueColor;
1625          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          template.screen = screen_num;
1626            vmatches =
1627                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1628                                   &visuals_count);
1629            g_visual = NULL;
1630            g_no_translate_image = False;
1631            g_compatible_arch = False;
1632            if (vmatches != NULL)
1633            {
1634                    for (i = 0; i < visuals_count; ++i)
1635                    {
1636                            XVisualInfo *visual_info = &vmatches[i];
1637                            RD_BOOL can_translate_to_bpp = False;
1638                            int j;
1639    
1640                            /* Try to find a no-translation visual that'll
1641                               allow us to use RDP bitmaps directly as ZPixmaps. */
1642                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1643                                                   /* R5G5B5 */
1644                                                   (visual_info->red_mask == 0x7c00) &&
1645                                                   (visual_info->green_mask == 0x3e0) &&
1646                                                   (visual_info->blue_mask == 0x1f)) ||
1647                                                  ((visual_info->depth == 16) &&
1648                                                   /* R5G6B5 */
1649                                                   (visual_info->red_mask == 0xf800) &&
1650                                                   (visual_info->green_mask == 0x7e0) &&
1651                                                   (visual_info->blue_mask == 0x1f)) ||
1652                                                  ((visual_info->depth == 24) &&
1653                                                   /* R8G8B8 */
1654                                                   (visual_info->red_mask == 0xff0000) &&
1655                                                   (visual_info->green_mask == 0xff00) &&
1656                                                   (visual_info->blue_mask == 0xff))))
1657                            {
1658                                    g_visual = visual_info->visual;
1659                                    g_depth = visual_info->depth;
1660                                    g_compatible_arch = !g_host_be;
1661                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1662                                    if (g_no_translate_image)
1663                                            /* We found the best visual */
1664                                            break;
1665                            }
1666                            else
1667                            {
1668                                    g_compatible_arch = False;
1669                            }
1670    
1671          nvisuals--;                          if (visual_info->depth > 24)
1672          while (nvisuals >= 0)                          {
1673          {                                  /* Avoid 32-bit visuals and likes like the plague.
1674                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1675                  {                                     (e.g. nvidia's Composite 32-bit visual).
1676                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1677                                    continue;
1678                            }
1679    
1680                            /* Only care for visuals, for whose BPPs (not depths!)
1681                               we have a translateXtoY function. */
1682                            for (j = 0; j < pixmap_formats_count; ++j)
1683                            {
1684                                    if (pfm[j].depth == visual_info->depth)
1685                                    {
1686                                            if ((pfm[j].bits_per_pixel == 16) ||
1687                                                (pfm[j].bits_per_pixel == 24) ||
1688                                                (pfm[j].bits_per_pixel == 32))
1689                                            {
1690                                                    can_translate_to_bpp = True;
1691                                            }
1692                                            break;
1693                                    }
1694                            }
1695    
1696                            /* Prefer formats which have the most colour depth.
1697                               We're being truly aristocratic here, minding each
1698                               weight on its own. */
1699                            if (can_translate_to_bpp)
1700                            {
1701                                    unsigned vis_red_weight =
1702                                            calculate_mask_weight(visual_info->red_mask);
1703                                    unsigned vis_green_weight =
1704                                            calculate_mask_weight(visual_info->green_mask);
1705                                    unsigned vis_blue_weight =
1706                                            calculate_mask_weight(visual_info->blue_mask);
1707                                    if ((vis_red_weight >= red_weight)
1708                                        && (vis_green_weight >= green_weight)
1709                                        && (vis_blue_weight >= blue_weight))
1710                                    {
1711                                            red_weight = vis_red_weight;
1712                                            green_weight = vis_green_weight;
1713                                            blue_weight = vis_blue_weight;
1714                                            g_visual = visual_info->visual;
1715                                            g_depth = visual_info->depth;
1716                                    }
1717                            }
1718                  }                  }
1719                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1720          }          }
1721    
1722          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)))  
1723          {          {
1724                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1725                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1726                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1727                    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;  
                 }  
1728          }          }
1729          else          else
1730          {          {
1731                  /* need a truecolour visual */                  template.class = PseudoColor;
1732                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1733                  {                  template.colormap_size = 256;
1734                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1735                            XGetVisualInfo(g_display,
1736                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1737                                           &template, &visuals_count);
1738                    if (vmatches == NULL)
1739                    {
1740                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1741                            XCloseDisplay(g_display);
1742                            XFree(pfm);
1743                          return False;                          return False;
1744                  }                  }
1745    
1746                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1747                  g_owncolmap = False;                  g_owncolmap = True;
1748                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1749                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1750                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1751    
1752                  /* if RGB video and everything is little endian */          g_bpp = 0;
1753                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1754                      !g_xserver_be && !g_host_be)          {
1755                    XPixmapFormatValues *pf = &pfm[i];
1756                    if (pf->depth == g_depth)
1757                  {                  {
1758                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1759                                                g_blue_shift_l == 0))  
1760                            if (g_no_translate_image)
1761                          {                          {
1762                                  g_arch_match = True;                                  switch (g_server_depth)
1763                                    {
1764                                            case 15:
1765                                            case 16:
1766                                                    if (g_bpp != 16)
1767                                                            g_no_translate_image = False;
1768                                                    break;
1769                                            case 24:
1770                                                    /* Yes, this will force image translation
1771                                                       on most modern servers which use 32 bits
1772                                                       for R8G8B8. */
1773                                                    if (g_bpp != 24)
1774                                                            g_no_translate_image = False;
1775                                                    break;
1776                                            default:
1777                                                    g_no_translate_image = False;
1778                                                    break;
1779                                    }
1780                          }                          }
                 }  
1781    
1782                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1783                  {                             there's just a single entry for every depth,
1784                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1785                            break;
1786                  }                  }
1787          }          }
1788            XFree(pfm);
1789            pfm = NULL;
1790            return True;
1791    }
1792    
1793    static XErrorHandler g_old_error_handler;
1794    static RD_BOOL g_error_expected = False;
1795    
1796    /* Check if the X11 window corresponding to a seamless window with
1797       specified id exists. */
1798    RD_BOOL
1799    sw_window_exists(unsigned long id)
1800    {
1801            seamless_window *sw;
1802            char *name;
1803            Status sts = 0;
1804    
1805          pfm = XListPixmapFormats(g_display, &i);          sw = sw_get_window_by_id(id);
1806          if (pfm != NULL)          if (!sw)
1807                    return False;
1808    
1809            g_error_expected = True;
1810            sts = XFetchName(g_display, sw->wnd, &name);
1811            g_error_expected = False;
1812            if (sts)
1813          {          {
1814                  /* Use maximum bpp for this depth - this is generally                  XFree(name);
                    desirable, e.g. 24 bits->32 bits. */  
                 while (i--)  
                 {  
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1815          }          }
1816    
1817          if (g_bpp < 8)          return sts;
1818    }
1819    
1820    static int
1821    error_handler(Display * dpy, XErrorEvent * eev)
1822    {
1823            if (g_error_expected)
1824                    return 0;
1825    
1826            return g_old_error_handler(dpy, eev);
1827    }
1828    
1829    RD_BOOL
1830    ui_init(void)
1831    {
1832            int screen_num;
1833    
1834            g_display = XOpenDisplay(NULL);
1835            if (g_display == NULL)
1836          {          {
1837                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(g_display);  
1838                  return False;                  return False;
1839          }          }
1840    
1841            {
1842                    uint16 endianess_test = 1;
1843                    g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1844            }
1845    
1846            g_old_error_handler = XSetErrorHandler(error_handler);
1847            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1848            screen_num = DefaultScreen(g_display);
1849            g_x_socket = ConnectionNumber(g_display);
1850            g_screen = ScreenOfDisplay(g_display, screen_num);
1851            g_depth = DefaultDepthOfScreen(g_screen);
1852    
1853            if (!select_visual(screen_num))
1854                    return False;
1855    
1856            if (g_no_translate_image)
1857            {
1858                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1859            }
1860    
1861            if (g_server_depth > g_bpp)
1862            {
1863                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1864                            g_server_depth, g_bpp);
1865            }
1866    
1867            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1868                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1869    
1870          if (!g_owncolmap)          if (!g_owncolmap)
1871          {          {
1872                  g_xcolmap =                  g_xcolmap =
1873                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1874                                          AllocNone);                                          AllocNone);
1875                  if (g_depth <= 8)                  if (g_depth <= 8)
1876                          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);
1877          }          }
1878    
1879          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1880          {          {
1881                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1882                  g_ownbackstore = True;                  g_ownbackstore = True;
1883          }          }
1884    
# Line 1087  ui_init(void) Line 1889  ui_init(void)
1889          {          {
1890                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1891                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1892                    g_using_full_workarea = True;
1893          }          }
1894          else if (g_width < 0)          else if (g_width < 0)
1895          {          {
1896                  /* Percent of screen */                  /* Percent of screen */
1897                    if (-g_width >= 100)
1898                            g_using_full_workarea = True;
1899                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1900                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1901          }          }
# Line 1098  ui_init(void) Line 1903  ui_init(void)
1903          {          {
1904                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1905                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1906                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1907                  {                  {
1908                          g_width = cx;                          g_width = cx;
1909                          g_height = cy;                          g_height = cy;
1910                            g_using_full_workarea = True;
1911                  }                  }
1912                  else                  else
1913                  {                  {
1914                          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");
1915                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1916                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1917                  }                  }
1918          }          }
1919    
# Line 1116  ui_init(void) Line 1921  ui_init(void)
1921          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1922    
1923          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1924            xwin_refresh_pointer_map();
1925    
1926          xkeymap_init();          xkeymap_init();
1927    
# Line 1123  ui_init(void) Line 1929  ui_init(void)
1929                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1930    
1931          xclip_init();          xclip_init();
1932            ewmh_init();
1933            if (g_seamless_rdp)
1934            {
1935                    seamless_init();
1936            }
1937    
1938          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));
1939    
1940          return True;          return True;
1941  }  }
# Line 1132  ui_init(void) Line 1943  ui_init(void)
1943  void  void
1944  ui_deinit(void)  ui_deinit(void)
1945  {  {
1946            while (g_seamless_windows)
1947            {
1948                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1949                    sw_remove_window(g_seamless_windows);
1950            }
1951    
1952            xclip_deinit();
1953    
1954          if (g_IM != NULL)          if (g_IM != NULL)
1955                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1956    
# Line 1148  ui_deinit(void) Line 1967  ui_deinit(void)
1967          g_display = NULL;          g_display = NULL;
1968  }  }
1969    
1970  BOOL  
1971    static void
1972    get_window_attribs(XSetWindowAttributes * attribs)
1973    {
1974            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1975            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1976            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1977            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1978            attribs->override_redirect = g_fullscreen;
1979            attribs->colormap = g_xcolmap;
1980    }
1981    
1982    static void
1983    get_input_mask(long *input_mask)
1984    {
1985            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1986                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1987    
1988            if (g_sendmotion)
1989                    *input_mask |= PointerMotionMask;
1990            if (g_ownbackstore)
1991                    *input_mask |= ExposureMask;
1992            if (g_fullscreen || g_grab_keyboard)
1993                    *input_mask |= EnterWindowMask;
1994            if (g_grab_keyboard)
1995                    *input_mask |= LeaveWindowMask;
1996    }
1997    
1998    RD_BOOL
1999  ui_create_window(void)  ui_create_window(void)
2000  {  {
2001          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
# Line 1170  ui_create_window(void) Line 2017  ui_create_window(void)
2017          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2018                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2019    
2020          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;  
2021    
2022          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,
2023                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1182  ui_create_window(void) Line 2025  ui_create_window(void)
2025                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
2026    
2027          if (g_gc == NULL)          if (g_gc == NULL)
2028            {
2029                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2030                    ui_reset_clip();
2031            }
2032    
2033          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
2034                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1197  ui_create_window(void) Line 2043  ui_create_window(void)
2043          }          }
2044    
2045          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
2046            ewmh_set_wm_name(g_wnd, g_title);
2047    
2048          if (g_hide_decorations)          if (g_hide_decorations)
2049                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2050    
2051          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2052          if (classhints != NULL)          if (classhints != NULL)
# Line 1226  ui_create_window(void) Line 2073  ui_create_window(void)
2073                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2074          }          }
2075    
2076          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;  
2077    
2078          if (g_IM != NULL)          if (g_IM != NULL)
2079          {          {
# Line 1271  ui_create_window(void) Line 2108  ui_create_window(void)
2108          if (g_null_cursor == NULL)          if (g_null_cursor == NULL)
2109                  g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);                  g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
2110    
2111            if (g_seamless_rdp)
2112            {
2113                    seamless_restack_test();
2114            }
2115    
2116          return True;          return True;
2117  }  }
2118    
# Line 1321  xwin_toggle_fullscreen(void) Line 2163  xwin_toggle_fullscreen(void)
2163  {  {
2164          Pixmap contents = 0;          Pixmap contents = 0;
2165    
2166            if (g_seamless_active)
2167                    /* Turn off SeamlessRDP mode */
2168                    ui_seamless_toggle();
2169    
2170          if (!g_ownbackstore)          if (!g_ownbackstore)
2171          {          {
2172                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1342  xwin_toggle_fullscreen(void) Line 2188  xwin_toggle_fullscreen(void)
2188  }  }
2189    
2190  static void  static void
2191  handle_button_event(XEvent xevent, BOOL down)  handle_button_event(XEvent xevent, RD_BOOL down)
2192  {  {
2193          uint16 button, flags = 0;          uint16 button, flags = 0;
2194          g_last_gesturetime = xevent.xbutton.time;          g_last_gesturetime = xevent.xbutton.time;
2195            /* Reverse the pointer button mapping, e.g. in the case of
2196               "left-handed mouse mode"; the RDP session expects to
2197               receive physical buttons (true in mstsc as well) and
2198               logical button behavior depends on the remote desktop's own
2199               mouse settings */
2200            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
2201          button = xkeymap_translate_button(xevent.xbutton.button);          button = xkeymap_translate_button(xevent.xbutton.button);
2202          if (button == 0)          if (button == 0)
2203                  return;                  return;
# Line 1398  handle_button_event(XEvent xevent, BOOL Line 2250  handle_button_event(XEvent xevent, BOOL
2250                          /* The title bar. */                          /* The title bar. */
2251                          if (xevent.type == ButtonPress)                          if (xevent.type == ButtonPress)
2252                          {                          {
2253                                  if (!g_fullscreen && g_hide_decorations)                                  if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
2254                                  {                                  {
2255                                          g_moving_wnd = True;                                          g_moving_wnd = True;
2256                                          g_move_x_offset = xevent.xbutton.x;                                          g_move_x_offset = xevent.xbutton.x;
# Line 1409  handle_button_event(XEvent xevent, BOOL Line 2261  handle_button_event(XEvent xevent, BOOL
2261                  }                  }
2262          }          }
2263    
2264          rdp_send_input(time(NULL), RDP_INPUT_MOUSE,          if (xevent.xmotion.window == g_wnd)
2265                         flags | button, xevent.xbutton.x, xevent.xbutton.y);          {
2266                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2267                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
2268            }
2269            else
2270            {
2271                    /* SeamlessRDP */
2272                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2273                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
2274            }
2275  }  }
2276    
2277    
2278  /* Process events in Xlib queue  /* Process events in Xlib queue
2279     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
2280  static int  static int
# Line 1424  xwin_process_events(void) Line 2286  xwin_process_events(void)
2286          char str[256];          char str[256];
2287          Status status;          Status status;
2288          int events = 0;          int events = 0;
2289            seamless_window *sw;
2290    
2291          while ((XPending(g_display) > 0) && events++ < 20)          while ((XPending(g_display) > 0) && events++ < 20)
2292          {          {
# Line 1438  xwin_process_events(void) Line 2301  xwin_process_events(void)
2301                  switch (xevent.type)                  switch (xevent.type)
2302                  {                  {
2303                          case VisibilityNotify:                          case VisibilityNotify:
2304                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
2305                                            g_Unobscured =
2306                                                    xevent.xvisibility.state == VisibilityUnobscured;
2307    
2308                                  break;                                  break;
2309                          case ClientMessage:                          case ClientMessage:
2310                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2311                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2312                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2313                                          /* Quit */                                  {
2314                                          return 0;                                          /* When killing a seamless window, close the window on the
2315                                               serverside instead of terminating rdesktop */
2316                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2317                                            if (!sw)
2318                                                    /* Otherwise, quit */
2319                                                    return 0;
2320                                            /* send seamless destroy process message */
2321                                            seamless_send_destroy(sw->id);
2322                                    }
2323                                  break;                                  break;
2324    
2325                          case KeyPress:                          case KeyPress:
# Line 1518  xwin_process_events(void) Line 2392  xwin_process_events(void)
2392                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2393                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2394                                                         CurrentTime);                                                         CurrentTime);
2395                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2396                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2397                                    {
2398                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2399                                                           xevent.xmotion.x, xevent.xmotion.y);
2400                                    }
2401                                    else
2402                                    {
2403                                            /* SeamlessRDP */
2404                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2405                                                           xevent.xmotion.x_root,
2406                                                           xevent.xmotion.y_root);
2407                                    }
2408                                  break;                                  break;
2409    
2410                          case FocusIn:                          case FocusIn:
# Line 1530  xwin_process_events(void) Line 2415  xwin_process_events(void)
2415                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2416                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2417                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2418    
2419                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2420                                    if (!sw)
2421                                            break;
2422    
2423                                    /* Menu windows are real X11 windows,
2424                                       with focus. When such a window is
2425                                       destroyed, focus is reverted to the
2426                                       main application window, which
2427                                       would cause us to send FOCUS. This
2428                                       breaks window switching in, say,
2429                                       Seamonkey. We shouldn't need to
2430                                       send FOCUS: Windows should also
2431                                       revert focus to some other window
2432                                       when the menu window is
2433                                       destroyed. So, we only send FOCUS
2434                                       if the previous focus window still
2435                                       exists. */
2436                                    if (sw->id != g_seamless_focused)
2437                                    {
2438    
2439                                            if (sw_window_exists(g_seamless_focused))
2440                                                    seamless_send_focus(sw->id, 0);
2441                                            g_seamless_focused = sw->id;
2442                                    }
2443                                  break;                                  break;
2444    
2445                          case FocusOut:                          case FocusOut:
# Line 1562  xwin_process_events(void) Line 2472  xwin_process_events(void)
2472                                  break;                                  break;
2473    
2474                          case Expose:                          case Expose:
2475                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2476                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2477                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2478                                            xevent.xexpose.height,                                                    g_gc,
2479                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2480                                                      xevent.xexpose.width, xevent.xexpose.height,
2481                                                      xevent.xexpose.x, xevent.xexpose.y);
2482                                    }
2483                                    else
2484                                    {
2485                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2486                                            if (!sw)
2487                                                    break;
2488                                            XCopyArea(g_display, g_backstore,
2489                                                      xevent.xexpose.window, g_gc,
2490                                                      xevent.xexpose.x + sw->xoffset,
2491                                                      xevent.xexpose.y + sw->yoffset,
2492                                                      xevent.xexpose.width,
2493                                                      xevent.xexpose.height, xevent.xexpose.x,
2494                                                      xevent.xexpose.y);
2495                                    }
2496    
2497                                  break;                                  break;
2498    
2499                          case MappingNotify:                          case MappingNotify:
# Line 1581  xwin_process_events(void) Line 2508  xwin_process_events(void)
2508                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2509                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2510                                  }                                  }
2511    
2512                                    if (xevent.xmapping.request == MappingPointer)
2513                                    {
2514                                            xwin_refresh_pointer_map();
2515                                    }
2516    
2517                                  break;                                  break;
2518    
2519                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1595  xwin_process_events(void) Line 2528  xwin_process_events(void)
2528                                  break;                                  break;
2529                          case PropertyNotify:                          case PropertyNotify:
2530                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2531                                    if (xevent.xproperty.window == g_wnd)
2532                                            break;
2533                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2534                                            break;
2535    
2536                                    /* seamless */
2537                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2538                                    if (!sw)
2539                                            break;
2540    
2541                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2542                                        && (xevent.xproperty.state == PropertyNewValue))
2543                                    {
2544                                            sw->state = ewmh_get_window_state(sw->wnd);
2545                                            seamless_send_state(sw->id, sw->state, 0);
2546                                    }
2547    
2548                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2549                                        && (xevent.xproperty.state == PropertyNewValue))
2550                                    {
2551                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2552                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2553                                    }
2554    
2555                                  break;                                  break;
2556                          case MapNotify:                          case MapNotify:
2557                                  rdp_send_client_window_status(1);                                  if (!g_seamless_active)
2558                                            rdp_send_client_window_status(1);
2559                                  break;                                  break;
2560                          case UnmapNotify:                          case UnmapNotify:
2561                                  rdp_send_client_window_status(0);                                  if (!g_seamless_active)
2562                                            rdp_send_client_window_status(0);
2563                                    break;
2564                            case ConfigureNotify:
2565                                    if (!g_seamless_active)
2566                                            break;
2567    
2568                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2569                                    if (!sw)
2570                                            break;
2571    
2572                                    gettimeofday(sw->position_timer, NULL);
2573                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2574                                        1000000)
2575                                    {
2576                                            sw->position_timer->tv_usec +=
2577                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2578                                            sw->position_timer->tv_sec += 1;
2579                                    }
2580                                    else
2581                                    {
2582                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2583                                    }
2584    
2585                                    sw_handle_restack(sw);
2586                                  break;                                  break;
2587                  }                  }
2588          }          }
# Line 1615  ui_select(int rdp_socket) Line 2597  ui_select(int rdp_socket)
2597          int n;          int n;
2598          fd_set rfds, wfds;          fd_set rfds, wfds;
2599          struct timeval tv;          struct timeval tv;
2600          BOOL s_timeout = False;          RD_BOOL s_timeout = False;
2601    
2602          while (True)          while (True)
2603          {          {
# Line 1625  ui_select(int rdp_socket) Line 2607  ui_select(int rdp_socket)
2607                          /* User quit */                          /* User quit */
2608                          return 0;                          return 0;
2609    
2610                    if (g_seamless_active)
2611                            sw_check_timers();
2612    
2613                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2614                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2615                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2616                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2617    
 #ifdef WITH_RDPSND  
                 /* FIXME: there should be an API for registering fds */  
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd > n) ? g_dsp_fd : n;  
                 }  
 #endif  
2618                  /* default timeout */                  /* default timeout */
2619                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2620                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2621    
2622    #ifdef WITH_RDPSND
2623                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2624    #endif
2625    
2626                  /* add redirection handles */                  /* add redirection handles */
2627                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2628                    seamless_select_timeout(&tv);
2629    
2630                  n++;                  n++;
2631    
# Line 1653  ui_select(int rdp_socket) Line 2635  ui_select(int rdp_socket)
2635                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2636    
2637                          case 0:                          case 0:
2638    #ifdef WITH_RDPSND
2639                                    rdpsnd_check_fds(&rfds, &wfds);
2640    #endif
2641    
2642                                  /* Abort serial read calls */                                  /* Abort serial read calls */
2643                                  if (s_timeout)                                  if (s_timeout)
2644                                          rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                          rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2645                                  continue;                                  continue;
2646                  }                  }
2647    
2648                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);  #ifdef WITH_RDPSND
2649                    rdpsnd_check_fds(&rfds, &wfds);
2650    #endif
2651    
2652                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2653    
2654                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2655                          return 1;                          return 1;
2656    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2657          }          }
2658  }  }
2659    
# Line 1677  ui_move_pointer(int x, int y) Line 2663  ui_move_pointer(int x, int y)
2663          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2664  }  }
2665    
2666  HBITMAP  RD_HBITMAP
2667  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2668  {  {
2669          XImage *image;          XImage *image;
# Line 1685  ui_create_bitmap(int width, int height, Line 2671  ui_create_bitmap(int width, int height,
2671          uint8 *tdata;          uint8 *tdata;
2672          int bitmap_pad;          int bitmap_pad;
2673    
2674          if (g_server_bpp == 8)          if (g_server_depth == 8)
2675          {          {
2676                  bitmap_pad = 8;                  bitmap_pad = 8;
2677          }          }
# Line 1707  ui_create_bitmap(int width, int height, Line 2693  ui_create_bitmap(int width, int height,
2693          XFree(image);          XFree(image);
2694          if (tdata != data)          if (tdata != data)
2695                  xfree(tdata);                  xfree(tdata);
2696          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2697    }
2698    
2699    void
2700    update_bitmap(int x, int y, int width, int height, uint8 * data)
2701    {
2702            int size;
2703            uint8 *out;
2704            uint8 *end;
2705            uint8 *c_current;
2706            uint8 *c_update;
2707            uint8 *c_written;
2708            int col;
2709            int row;
2710            BOOL matches_written;
2711            BOOL matches_current;
2712    
2713            size = width * height * 3;   /* force 24-bit color for libjpeg: R G B */
2714            out = (uint8 *) xmalloc(size);
2715            end = out + size;
2716    
2717            switch (g_server_depth)
2718            {
2719                    case 24:
2720                            translate24to24(data, out, end);
2721                            break;
2722                    case 16:
2723                            translate16to24((uint16 *) data, out, end);
2724                            break;
2725                    case 15:
2726                            translate15to24((uint16 *) data, out, end);
2727                            break;
2728                    case 8:
2729                            translate8to24(data, out, end);
2730                            break;
2731            }
2732    
2733            for (row=0; row<height; row++)
2734            {
2735                    /* truncate if out of bounds */
2736                    if (g_height <= (y + row))
2737                            break;
2738    
2739                    c_update = out + row * width * 3;
2740                    c_current = g_bitmap_data + (row + y) * g_width * 3 + x * 3;
2741                    c_written = g_bitmap_data_last_write + (row + y) * g_width * 3 + x * 3;
2742    
2743                    for (col = 0; col < width; col++)
2744                    {
2745                            /* truncate if out of bounds */
2746                            if (g_width <= (x + col))
2747                                    break;
2748    
2749                            matches_written = True;
2750                            matches_current = True;
2751    
2752                            /* updates come in as BGR order... force RGB */
2753                            if (*c_current != *(c_update+2))
2754                            {
2755                                    if (*(c_update+2) != *c_written)
2756                                            matches_written = False;
2757                                    matches_current = False;
2758                                    *c_current = *(c_update+2);
2759                            }
2760    
2761                            c_written++;
2762    
2763                            if (*(++c_current) != *(++c_update))
2764                            {
2765                                    if (*c_update != *c_written)
2766                                            matches_written = False;
2767                                    matches_current = False;
2768                                    *c_current = *c_update;
2769                            }
2770    
2771                            c_written++;
2772    
2773                            if (*(++c_current) != *(++c_update-2))
2774                            {
2775                                    if (*(c_update-2) != *c_written)
2776                                            matches_written = False;
2777                                    matches_current = False;
2778                                    *c_current = *(c_update-2);
2779                            }
2780    
2781                            c_written++;
2782                            c_current++;
2783                            c_update++;
2784    
2785                            if (!matches_current)
2786                            {
2787                                    if (matches_written)
2788                                            g_pixels_changed--;
2789                                    else
2790                                            g_pixels_changed++;
2791                            }
2792                    }
2793            }
2794    
2795            //printf("g_pixels_changed=%d\n", g_pixels_changed);
2796    
2797            xfree(out);
2798            g_time_last_change = tod();
2799  }  }
2800    
2801  void  void
# Line 1717  ui_paint_bitmap(int x, int y, int cx, in Line 2805  ui_paint_bitmap(int x, int y, int cx, in
2805          uint8 *tdata;          uint8 *tdata;
2806          int bitmap_pad;          int bitmap_pad;
2807    
2808          if (g_server_bpp == 8)          update_bitmap(x, y, width, height, data);
2809    
2810            if (g_server_depth == 8)
2811          {          {
2812                  bitmap_pad = 8;                  bitmap_pad = 8;
2813          }          }
# Line 1737  ui_paint_bitmap(int x, int y, int cx, in Line 2827  ui_paint_bitmap(int x, int y, int cx, in
2827          {          {
2828                  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);
2829                  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);
2830                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2831                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2832                                             x - sw->xoffset, y - sw->yoffset));
2833          }          }
2834          else          else
2835          {          {
2836                  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);
2837                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2838                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2839                                             x - sw->xoffset, y - sw->yoffset));
2840          }          }
2841    
2842          XFree(image);          XFree(image);
# Line 1749  ui_paint_bitmap(int x, int y, int cx, in Line 2845  ui_paint_bitmap(int x, int y, int cx, in
2845  }  }
2846    
2847  void  void
2848  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2849  {  {
2850          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2851  }  }
2852    
2853  HGLYPH  RD_HGLYPH
2854  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2855  {  {
2856          XImage *image;          XImage *image;
# Line 1776  ui_create_glyph(int width, int height, u Line 2872  ui_create_glyph(int width, int height, u
2872          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2873    
2874          XFree(image);          XFree(image);
2875          return (HGLYPH) bitmap;          return (RD_HGLYPH) bitmap;
2876  }  }
2877    
2878  void  void
2879  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2880  {  {
2881          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2882  }  }
2883    
2884  HCURSOR  RD_HCURSOR
2885  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2886                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2887  {  {
2888          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2889          XColor bg, fg;          XColor bg, fg;
2890          Cursor xcursor;          Cursor xcursor;
2891          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1853  ui_create_cursor(unsigned int x, unsigne Line 2949  ui_create_cursor(unsigned int x, unsigne
2949          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2950          xfree(mask);          xfree(mask);
2951          xfree(cursor);          xfree(cursor);
2952          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2953  }  }
2954    
2955  void  void
2956  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2957  {  {
2958          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2959          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2960            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2961  }  }
2962    
2963  void  void
2964  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2965  {  {
2966          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2967  }  }
# Line 1882  ui_set_null_cursor(void) Line 2979  ui_set_null_cursor(void)
2979                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2980    
2981    
2982  HCOLOURMAP  RD_HCOLOURMAP
2983  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2984  {  {
2985          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1978  ui_create_colourmap(COLOURMAP * colours) Line 3075  ui_create_colourmap(COLOURMAP * colours)
3075                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
3076    
3077                  xfree(xcolours);                  xfree(xcolours);
3078                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
3079          }          }
3080  }  }
3081    
3082  void  void
3083  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
3084  {  {
3085          if (!g_owncolmap)          if (!g_owncolmap)
3086                  xfree(map);                  xfree(map);
# Line 1992  ui_destroy_colourmap(HCOLOURMAP map) Line 3089  ui_destroy_colourmap(HCOLOURMAP map)
3089  }  }
3090    
3091  void  void
3092  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
3093  {  {
3094          if (!g_owncolmap)          if (!g_owncolmap)
3095          {          {
# Line 2002  ui_set_colourmap(HCOLOURMAP map) Line 3099  ui_set_colourmap(HCOLOURMAP map)
3099                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
3100          }          }
3101          else          else
3102            {
3103                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
3104                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
3105            }
3106  }  }
3107    
3108  void  void
3109  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
3110  {  {
3111          XRectangle rect;          g_clip_rectangle.x = x;
3112            g_clip_rectangle.y = y;
3113          rect.x = x;          g_clip_rectangle.width = cx;
3114          rect.y = y;          g_clip_rectangle.height = cy;
3115          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);  
3116  }  }
3117    
3118  void  void
3119  ui_reset_clip(void)  ui_reset_clip(void)
3120  {  {
3121          XRectangle rect;          g_clip_rectangle.x = 0;
3122            g_clip_rectangle.y = 0;
3123          rect.x = 0;          g_clip_rectangle.width = g_width;
3124          rect.y = 0;          g_clip_rectangle.height = g_height;
3125          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);  
3126  }  }
3127    
3128  void  void
# Line 2081  ui_patblt(uint8 opcode, Line 3177  ui_patblt(uint8 opcode,
3177                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3178                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3179                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3180                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3181                          break;                          break;
3182    
3183                  case 3: /* Pattern */                  case 3: /* Pattern */
3184                          for (i = 0; i != 8; i++)                          if (brush->bd == 0)     /* rdp4 brush */
3185                                  ipattern[7 - i] = brush->pattern[i];                          {
3186                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                                  for (i = 0; i != 8; i++)
3187                          SET_FOREGROUND(bgcolour);                                          ipattern[7 - i] = brush->pattern[i];
3188                          SET_BACKGROUND(fgcolour);                                  fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3189                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                                  SET_FOREGROUND(bgcolour);
3190                          XSetStipple(g_display, g_gc, fill);                                  SET_BACKGROUND(fgcolour);
3191                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                                  XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3192                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                                  XSetStipple(g_display, g_gc, fill);
3193                          XSetFillStyle(g_display, g_gc, FillSolid);                                  XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3194                          XSetTSOrigin(g_display, g_gc, 0, 0);                                  FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3195                          ui_destroy_glyph((HGLYPH) fill);                                  XSetFillStyle(g_display, g_gc, FillSolid);
3196                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3197                                    ui_destroy_glyph((RD_HGLYPH) fill);
3198                            }
3199                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3200                            {
3201                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3202                                    XSetFillStyle(g_display, g_gc, FillTiled);
3203                                    XSetTile(g_display, g_gc, fill);
3204                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3205                                    FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3206                                    XSetFillStyle(g_display, g_gc, FillSolid);
3207                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3208                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3209                            }
3210                            else
3211                            {
3212                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3213                                    SET_FOREGROUND(bgcolour);
3214                                    SET_BACKGROUND(fgcolour);
3215                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3216                                    XSetStipple(g_display, g_gc, fill);
3217                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3218                                    FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3219                                    XSetFillStyle(g_display, g_gc, FillSolid);
3220                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3221                                    ui_destroy_glyph((RD_HGLYPH) fill);
3222                            }
3223                          break;                          break;
3224    
3225                  default:                  default:
# Line 2107  ui_patblt(uint8 opcode, Line 3230  ui_patblt(uint8 opcode,
3230    
3231          if (g_ownbackstore)          if (g_ownbackstore)
3232                  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);
3233            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3234                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3235                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3236  }  }
3237    
3238  void  void
# Line 2117  ui_screenblt(uint8 opcode, Line 3243  ui_screenblt(uint8 opcode,
3243          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3244          if (g_ownbackstore)          if (g_ownbackstore)
3245          {          {
3246                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3247                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3248                          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);  
                 }  
3249          }          }
3250          else          else
3251          {          {
3252                  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);
3253          }          }
3254    
3255            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3256                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3257                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3258    
3259          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3260  }  }
3261    
3262  void  void
3263  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3264            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3265            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3266  {  {
3267          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3268          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);
3269            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3270                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3271                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3272          if (g_ownbackstore)          if (g_ownbackstore)
3273                  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);
3274          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2152  ui_memblt(uint8 opcode, Line 3277  ui_memblt(uint8 opcode,
3277  void  void
3278  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3279            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3280            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3281            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3282  {  {
3283          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 2190  ui_line(uint8 opcode, Line 3315  ui_line(uint8 opcode,
3315          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3316          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3317          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3318            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3319                                                startx - sw->xoffset, starty - sw->yoffset,
3320                                                endx - sw->xoffset, endy - sw->yoffset));
3321          if (g_ownbackstore)          if (g_ownbackstore)
3322                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3323          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2207  ui_rect( Line 3335  ui_rect(
3335  void  void
3336  ui_polygon(uint8 opcode,  ui_polygon(uint8 opcode,
3337             /* mode */ uint8 fillmode,             /* mode */ uint8 fillmode,
3338             /* dest */ POINT * point, int npoints,             /* dest */ RD_POINT * point, int npoints,
3339             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3340  {  {
3341          uint8 style, i, ipattern[8];          uint8 style, i, ipattern[8];
# Line 2250  ui_polygon(uint8 opcode, Line 3378  ui_polygon(uint8 opcode,
3378                          FILL_POLYGON((XPoint *) point, npoints);                          FILL_POLYGON((XPoint *) point, npoints);
3379                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3380                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3381                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3382                          break;                          break;
3383    
3384                  case 3: /* Pattern */                  case 3: /* Pattern */
3385                          for (i = 0; i != 8; i++)                          if (brush->bd == 0)     /* rdp4 brush */
3386                                  ipattern[7 - i] = brush->pattern[i];                          {
3387                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                                  for (i = 0; i != 8; i++)
3388                          SET_FOREGROUND(bgcolour);                                          ipattern[7 - i] = brush->pattern[i];
3389                          SET_BACKGROUND(fgcolour);                                  fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3390                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                                  SET_FOREGROUND(bgcolour);
3391                          XSetStipple(g_display, g_gc, fill);                                  SET_BACKGROUND(fgcolour);
3392                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                                  XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3393                          FILL_POLYGON((XPoint *) point, npoints);                                  XSetStipple(g_display, g_gc, fill);
3394                          XSetFillStyle(g_display, g_gc, FillSolid);                                  XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3395                          XSetTSOrigin(g_display, g_gc, 0, 0);                                  FILL_POLYGON((XPoint *) point, npoints);
3396                          ui_destroy_glyph((HGLYPH) fill);                                  XSetFillStyle(g_display, g_gc, FillSolid);
3397                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3398                                    ui_destroy_glyph((RD_HGLYPH) fill);
3399                            }
3400                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3401                            {
3402                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3403                                    XSetFillStyle(g_display, g_gc, FillTiled);
3404                                    XSetTile(g_display, g_gc, fill);
3405                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3406                                    FILL_POLYGON((XPoint *) point, npoints);
3407                                    XSetFillStyle(g_display, g_gc, FillSolid);
3408                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3409                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3410                            }
3411                            else
3412                            {
3413                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3414                                    SET_FOREGROUND(bgcolour);
3415                                    SET_BACKGROUND(fgcolour);
3416                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3417                                    XSetStipple(g_display, g_gc, fill);
3418                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3419                                    FILL_POLYGON((XPoint *) point, npoints);
3420                                    XSetFillStyle(g_display, g_gc, FillSolid);
3421                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3422                                    ui_destroy_glyph((RD_HGLYPH) fill);
3423                            }
3424                          break;                          break;
3425    
3426                  default:                  default:
# Line 2277  ui_polygon(uint8 opcode, Line 3432  ui_polygon(uint8 opcode,
3432    
3433  void  void
3434  ui_polyline(uint8 opcode,  ui_polyline(uint8 opcode,
3435              /* dest */ POINT * points, int npoints,              /* dest */ RD_POINT * points, int npoints,
3436              /* pen */ PEN * pen)              /* pen */ PEN * pen)
3437  {  {
3438          /* TODO: set join style */          /* TODO: set join style */
# Line 2287  ui_polyline(uint8 opcode, Line 3442  ui_polyline(uint8 opcode,
3442          if (g_ownbackstore)          if (g_ownbackstore)
3443                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3444                             CoordModePrevious);                             CoordModePrevious);
3445    
3446            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3447                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3448    
3449          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3450  }  }
3451    
# Line 2324  ui_ellipse(uint8 opcode, Line 3483  ui_ellipse(uint8 opcode,
3483                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3484                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3485                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3486                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3487                          break;                          break;
3488    
3489                  case 3: /* Pattern */                  case 3: /* Pattern */
3490                          for (i = 0; i != 8; i++)                          if (brush->bd == 0)     /* rdp4 brush */
3491                                  ipattern[7 - i] = brush->pattern[i];                          {
3492                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                                  for (i = 0; i != 8; i++)
3493                          SET_FOREGROUND(bgcolour);                                          ipattern[7 - i] = brush->pattern[i];
3494                          SET_BACKGROUND(fgcolour);                                  fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3495                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                                  SET_FOREGROUND(bgcolour);
3496                          XSetStipple(g_display, g_gc, fill);                                  SET_BACKGROUND(fgcolour);
3497                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                                  XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3498                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                                  XSetStipple(g_display, g_gc, fill);
3499                          XSetFillStyle(g_display, g_gc, FillSolid);                                  XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3500                          XSetTSOrigin(g_display, g_gc, 0, 0);                                  DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3501                          ui_destroy_glyph((HGLYPH) fill);                                  XSetFillStyle(g_display, g_gc, FillSolid);
3502                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3503                                    ui_destroy_glyph((RD_HGLYPH) fill);
3504                            }
3505                            else if (brush->bd->colour_code > 1)    /* > 1 bpp */
3506                            {
3507                                    fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data);
3508                                    XSetFillStyle(g_display, g_gc, FillTiled);
3509                                    XSetTile(g_display, g_gc, fill);
3510                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3511                                    DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3512                                    XSetFillStyle(g_display, g_gc, FillSolid);
3513                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3514                                    ui_destroy_bitmap((RD_HBITMAP) fill);
3515                            }
3516                            else
3517                            {
3518                                    fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data);
3519                                    SET_FOREGROUND(bgcolour);
3520                                    SET_BACKGROUND(fgcolour);
3521                                    XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3522                                    XSetStipple(g_display, g_gc, fill);
3523                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3524                                    DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3525                                    XSetFillStyle(g_display, g_gc, FillSolid);
3526                                    XSetTSOrigin(g_display, g_gc, 0, 0);
3527                                    ui_destroy_glyph((RD_HGLYPH) fill);
3528                            }
3529                          break;                          break;
3530    
3531                  default:                  default:
# Line 2353  ui_ellipse(uint8 opcode, Line 3539  ui_ellipse(uint8 opcode,
3539  void  void
3540  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3541                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3542                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3543                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3544  {  {
3545          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 2442  ui_draw_text(uint8 font, uint8 flags, ui Line 3628  ui_draw_text(uint8 font, uint8 flags, ui
3628                  switch (text[i])                  switch (text[i])
3629                  {                  {
3630                          case 0xff:                          case 0xff:
3631                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3632                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3633                                  {                                  {
3634                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3635                                          exit(1);                                          for (j = 0; j < length; j++)
3636                                                    fprintf(stderr, "%02x ", text[j]);
3637                                            fprintf(stderr, "\n");
3638                                            i = length = 0;
3639                                            break;
3640                                  }                                  }
3641                                    cache_put_text(text[i + 1], text, text[i + 2]);
3642                                    i += 3;
3643                                    length -= i;
3644                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3645                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3646                                  i = 0;                                  i = 0;
3647                                  break;                                  break;
3648    
3649                          case 0xfe:                          case 0xfe:
3650                                    /* At least one byte needs to follow */
3651                                    if (i + 2 > length)
3652                                    {
3653                                            warning("Skipping short 0xfe command:");
3654                                            for (j = 0; j < length; j++)
3655                                                    fprintf(stderr, "%02x ", text[j]);
3656                                            fprintf(stderr, "\n");
3657                                            i = length = 0;
3658                                            break;
3659                                    }
3660                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3661                                  if (entry != NULL)                                  if (entry->data != NULL)
3662                                  {                                  {
3663                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3664                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3665                                          {                                          {
3666                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3667                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2492  ui_draw_text(uint8 font, uint8 flags, ui Line 3693  ui_draw_text(uint8 font, uint8 flags, ui
3693          if (g_ownbackstore)          if (g_ownbackstore)
3694          {          {
3695                  if (boxcx > 1)                  if (boxcx > 1)
3696                    {
3697                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3698                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3699                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3700                                                    (g_display, g_backstore, sw->wnd, g_gc,
3701                                                     boxx, boxy,
3702                                                     boxcx, boxcy,
3703                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3704                    }
3705                  else                  else
3706                    {
3707                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3708                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3709                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3710                                                    (g_display, g_backstore, sw->wnd, g_gc,
3711                                                     clipx, clipy,
3712                                                     clipcx, clipcy, clipx - sw->xoffset,
3713                                                     clipy - sw->yoffset));
3714                    }
3715          }          }
3716  }  }
3717    
# Line 2509  ui_desktop_save(uint32 offset, int x, in Line 3724  ui_desktop_save(uint32 offset, int x, in
3724          if (g_ownbackstore)          if (g_ownbackstore)
3725          {          {
3726                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3727                    exit_if_null(image);
3728          }          }
3729          else          else
3730          {          {
3731                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3732                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3733                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3734                    exit_if_null(image);
3735                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3736          }          }
3737    
# Line 2536  ui_desktop_restore(uint32 offset, int x, Line 3753  ui_desktop_restore(uint32 offset, int x,
3753                  return;                  return;
3754    
3755          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3756                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3757    
3758          if (g_ownbackstore)          if (g_ownbackstore)
3759          {          {
3760                  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);
3761                  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);
3762                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3763                                            (g_display, g_backstore, sw->wnd, g_gc,
3764                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3765          }          }
3766          else          else
3767          {          {
3768                  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);
3769                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3770                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3771                                             x - sw->xoffset, y - sw->yoffset));
3772          }          }
3773    
3774          XFree(image);          XFree(image);
# Line 2561  void Line 3784  void
3784  ui_end_update(void)  ui_end_update(void)
3785  {  {
3786  }  }
3787    
3788    
3789    void
3790    ui_seamless_begin(RD_BOOL hidden)
3791    {
3792            if (!g_seamless_rdp)
3793                    return;
3794    
3795            if (g_seamless_started)
3796                    return;
3797    
3798            g_seamless_started = True;
3799            g_seamless_hidden = hidden;
3800    
3801            if (!hidden)
3802                    ui_seamless_toggle();
3803    }
3804    
3805    
3806    void
3807    ui_seamless_hide_desktop()
3808    {
3809            if (!g_seamless_rdp)
3810                    return;
3811    
3812            if (!g_seamless_started)
3813                    return;
3814    
3815            if (g_seamless_active)
3816                    ui_seamless_toggle();
3817    
3818            g_seamless_hidden = True;
3819    }
3820    
3821    
3822    void
3823    ui_seamless_unhide_desktop()
3824    {
3825            if (!g_seamless_rdp)
3826                    return;
3827    
3828            if (!g_seamless_started)
3829                    return;
3830    
3831            g_seamless_hidden = False;
3832    
3833            ui_seamless_toggle();
3834    }
3835    
3836    
3837    void
3838    ui_seamless_toggle()
3839    {
3840            if (!g_seamless_rdp)
3841                    return;
3842    
3843            if (!g_seamless_started)
3844                    return;
3845    
3846            if (g_seamless_hidden)
3847                    return;
3848    
3849            if (g_seamless_active)
3850            {
3851                    /* Deactivate */
3852                    while (g_seamless_windows)
3853                    {
3854                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3855                            sw_remove_window(g_seamless_windows);
3856                    }
3857                    XMapWindow(g_display, g_wnd);
3858            }
3859            else
3860            {
3861                    /* Activate */
3862                    XUnmapWindow(g_display, g_wnd);
3863                    seamless_send_sync();
3864            }
3865    
3866            g_seamless_active = !g_seamless_active;
3867    }
3868    
3869    
3870    void
3871    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3872                              unsigned long flags)
3873    {
3874            Window wnd;
3875            XSetWindowAttributes attribs;
3876            XClassHint *classhints;
3877            XSizeHints *sizehints;
3878            XWMHints *wmhints;
3879            long input_mask;
3880            seamless_window *sw, *sw_parent;
3881    
3882            if (!g_seamless_active)
3883                    return;
3884    
3885            /* Ignore CREATEs for existing windows */
3886            sw = sw_get_window_by_id(id);
3887            if (sw)
3888                    return;
3889    
3890            get_window_attribs(&attribs);
3891            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3892                                InputOutput, g_visual,
3893                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3894    
3895            XStoreName(g_display, wnd, "SeamlessRDP");
3896            ewmh_set_wm_name(wnd, "SeamlessRDP");
3897    
3898            mwm_hide_decorations(wnd);
3899    
3900            classhints = XAllocClassHint();
3901            if (classhints != NULL)
3902            {
3903                    classhints->res_name = "rdesktop";
3904                    classhints->res_class = "SeamlessRDP";
3905                    XSetClassHint(g_display, wnd, classhints);
3906                    XFree(classhints);
3907            }
3908    
3909            /* WM_NORMAL_HINTS */
3910            sizehints = XAllocSizeHints();
3911            if (sizehints != NULL)
3912            {
3913                    sizehints->flags = USPosition;
3914                    XSetWMNormalHints(g_display, wnd, sizehints);
3915                    XFree(sizehints);
3916            }
3917    
3918            /* Parent-less transient windows */
3919            if (parent == 0xFFFFFFFF)
3920            {
3921                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3922                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3923                       using some other hints. */
3924                    ewmh_set_window_popup(wnd);
3925            }
3926            /* Normal transient windows */
3927            else if (parent != 0x00000000)
3928            {
3929                    sw_parent = sw_get_window_by_id(parent);
3930                    if (sw_parent)
3931                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3932                    else
3933                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3934            }
3935    
3936            if (flags & SEAMLESSRDP_CREATE_MODAL)
3937            {
3938                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3939                       somewhat at least */
3940                    if (parent == 0x00000000)
3941                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3942                    ewmh_set_window_modal(wnd);
3943            }
3944    
3945            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3946            {
3947                    /* Make window always-on-top */
3948                    ewmh_set_window_above(wnd);
3949            }
3950    
3951            /* FIXME: Support for Input Context:s */
3952    
3953            get_input_mask(&input_mask);
3954            input_mask |= PropertyChangeMask;
3955    
3956            XSelectInput(g_display, wnd, input_mask);
3957    
3958            /* handle the WM_DELETE_WINDOW protocol. */
3959            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3960    
3961            sw = xmalloc(sizeof(seamless_window));
3962    
3963            memset(sw, 0, sizeof(seamless_window));
3964    
3965            sw->wnd = wnd;
3966            sw->id = id;
3967            sw->group = sw_find_group(group, False);
3968            sw->group->refcnt++;
3969            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3970            sw->desktop = 0;
3971            sw->position_timer = xmalloc(sizeof(struct timeval));
3972            timerclear(sw->position_timer);
3973    
3974            sw->outstanding_position = False;
3975            sw->outpos_serial = 0;
3976            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3977            sw->outpos_width = sw->outpos_height = 0;
3978    
3979            sw->next = g_seamless_windows;
3980            g_seamless_windows = sw;
3981    
3982            /* WM_HINTS */
3983            wmhints = XAllocWMHints();
3984            if (wmhints)
3985            {
3986                    wmhints->flags = WindowGroupHint;
3987                    wmhints->window_group = sw->group->wnd;
3988                    XSetWMHints(g_display, sw->wnd, wmhints);
3989                    XFree(wmhints);
3990            }
3991    }
3992    
3993    
3994    void
3995    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3996    {
3997            seamless_window *sw;
3998    
3999            if (!g_seamless_active)
4000                    return;
4001    
4002            sw = sw_get_window_by_id(id);
4003            if (!sw)
4004            {
4005                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
4006                    return;
4007            }
4008    
4009            XDestroyWindow(g_display, sw->wnd);
4010            sw_remove_window(sw);
4011    }
4012    
4013    
4014    void
4015    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
4016    {
4017            seamless_window *sw, *sw_next;
4018    
4019            if (!g_seamless_active)
4020                    return;
4021    
4022            for (sw = g_seamless_windows; sw; sw = sw_next)
4023            {
4024                    sw_next = sw->next;
4025    
4026                    if (sw->group->id == id)
4027                    {
4028                            XDestroyWindow(g_display, sw->wnd);
4029                            sw_remove_window(sw);
4030                    }
4031            }
4032    }
4033    
4034    
4035    void
4036    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
4037                        const char *data, int chunk_len)
4038    {
4039            seamless_window *sw;
4040    
4041            if (!g_seamless_active)
4042                    return;
4043    
4044            sw = sw_get_window_by_id(id);
4045            if (!sw)
4046            {
4047                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
4048                    return;
4049            }
4050    
4051            if (chunk == 0)
4052            {
4053                    if (sw->icon_size)
4054                            warning("ui_seamless_seticon: New icon started before previous completed\n");
4055    
4056                    if (strcmp(format, "RGBA") != 0)
4057                    {
4058                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
4059                            return;
4060                    }
4061    
4062                    sw->icon_size = width * height * 4;
4063                    if (sw->icon_size > 32 * 32 * 4)
4064                    {
4065                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
4066                            sw->icon_size = 0;
4067                            return;
4068                    }
4069    
4070                    sw->icon_offset = 0;
4071            }
4072            else
4073            {
4074                    if (!sw->icon_size)
4075                            return;
4076            }
4077    
4078            if (chunk_len > (sw->icon_size - sw->icon_offset))
4079            {
4080                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
4081                            chunk_len, sw->icon_size - sw->icon_offset);
4082                    sw->icon_size = 0;
4083                    return;
4084            }
4085    
4086            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
4087            sw->icon_offset += chunk_len;
4088    
4089            if (sw->icon_offset == sw->icon_size)
4090            {
4091                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
4092                    sw->icon_size = 0;
4093            }
4094    }
4095    
4096    
4097    void
4098    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
4099    {
4100            seamless_window *sw;
4101    
4102            if (!g_seamless_active)
4103                    return;
4104    
4105            sw = sw_get_window_by_id(id);
4106            if (!sw)
4107            {
4108                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
4109                    return;
4110            }
4111    
4112            if (strcmp(format, "RGBA") != 0)
4113            {
4114                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
4115                    return;
4116            }
4117    
4118            ewmh_del_icon(sw->wnd, width, height);
4119    }
4120    
4121    
4122    void
4123    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
4124    {
4125            seamless_window *sw;
4126    
4127            if (!g_seamless_active)
4128                    return;
4129    
4130            sw = sw_get_window_by_id(id);
4131            if (!sw)
4132            {
4133                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
4134                    return;
4135            }
4136    
4137            /* We ignore server updates until it has handled our request. */
4138            if (sw->outstanding_position)
4139                    return;
4140    
4141            if (!width || !height)
4142                    /* X11 windows must be at least 1x1 */
4143                    return;
4144    
4145            sw->xoffset = x;
4146            sw->yoffset = y;
4147            sw->width = width;
4148            sw->height = height;
4149    
4150            /* If we move the window in a maximized state, then KDE won't
4151               accept restoration */
4152            switch (sw->state)
4153            {
4154                    case SEAMLESSRDP_MINIMIZED:
4155                    case SEAMLESSRDP_MAXIMIZED:
4156                            return;
4157            }
4158    
4159            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
4160            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
4161    }
4162    
4163    
4164    void
4165    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
4166    {
4167            seamless_window *sw;
4168            XWindowChanges values;
4169            unsigned long restack_serial;
4170    
4171            if (!g_seamless_active)
4172                    return;
4173    
4174            sw = sw_get_window_by_id(id);
4175            if (!sw)
4176            {
4177                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
4178                    return;
4179            }
4180    
4181            if (behind)
4182            {
4183                    seamless_window *sw_behind;
4184    
4185                    sw_behind = sw_get_window_by_id(behind);
4186                    if (!sw_behind)
4187                    {
4188                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
4189                            return;
4190                    }
4191    
4192                    if (!g_seamless_broken_restack)
4193                    {
4194                            values.stack_mode = Below;
4195                            values.sibling = sw_behind->wnd;
4196                            restack_serial = XNextRequest(g_display);
4197                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
4198                                                 CWStackMode | CWSibling, &values);
4199                            sw_wait_configurenotify(sw->wnd, restack_serial);
4200                    }
4201            }
4202            else
4203            {
4204                    values.stack_mode = Above;
4205                    restack_serial = XNextRequest(g_display);
4206                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4207                                         &values);
4208                    sw_wait_configurenotify(sw->wnd, restack_serial);
4209            }
4210    
4211            sw_restack_window(sw, behind);
4212    
4213            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4214            {
4215                    /* Make window always-on-top */
4216                    ewmh_set_window_above(sw->wnd);
4217            }
4218    }
4219    
4220    
4221    void
4222    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4223    {
4224            seamless_window *sw;
4225    
4226            if (!g_seamless_active)
4227                    return;
4228    
4229            sw = sw_get_window_by_id(id);
4230            if (!sw)
4231            {
4232                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4233                    return;
4234            }
4235    
4236            /* FIXME: Might want to convert the name for non-EWMH WMs */
4237            XStoreName(g_display, sw->wnd, title);
4238            ewmh_set_wm_name(sw->wnd, title);
4239    }
4240    
4241    
4242    void
4243    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
4244    {
4245            seamless_window *sw;
4246    
4247            if (!g_seamless_active)
4248                    return;
4249    
4250            sw = sw_get_window_by_id(id);
4251            if (!sw)
4252            {
4253                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
4254                    return;
4255            }
4256    
4257            switch (state)
4258            {
4259                    case SEAMLESSRDP_NORMAL:
4260                    case SEAMLESSRDP_MAXIMIZED:
4261                            ewmh_change_state(sw->wnd, state);
4262                            XMapWindow(g_display, sw->wnd);
4263                            break;
4264                    case SEAMLESSRDP_MINIMIZED:
4265                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4266                               the Window Manager should probably just ignore the request, since
4267                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4268                               such as minimization, rather than an independent state." Besides,
4269                               XIconifyWindow is easier. */
4270                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4271                            {
4272                                    XWMHints *hints;
4273                                    hints = XGetWMHints(g_display, sw->wnd);
4274                                    if (hints)
4275                                    {
4276                                            hints->flags |= StateHint;
4277                                            hints->initial_state = IconicState;
4278                                            XSetWMHints(g_display, sw->wnd, hints);
4279                                            XFree(hints);
4280                                    }
4281                                    XMapWindow(g_display, sw->wnd);
4282                            }
4283                            else
4284                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4285                            break;
4286                    default:
4287                            warning("SeamlessRDP: Invalid state %d\n", state);
4288                            break;
4289            }
4290    
4291            sw->state = state;
4292    }
4293    
4294    
4295    void
4296    ui_seamless_syncbegin(unsigned long flags)
4297    {
4298            if (!g_seamless_active)
4299                    return;
4300    
4301            /* Destroy all seamless windows */
4302            while (g_seamless_windows)
4303            {
4304                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4305                    sw_remove_window(g_seamless_windows);
4306            }
4307    }
4308    
4309    
4310    void
4311    ui_seamless_ack(unsigned int serial)
4312    {
4313            seamless_window *sw;
4314            for (sw = g_seamless_windows; sw; sw = sw->next)
4315            {
4316                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4317                    {
4318                            sw->xoffset = sw->outpos_xoffset;
4319                            sw->yoffset = sw->outpos_yoffset;
4320                            sw->width = sw->outpos_width;
4321                            sw->height = sw->outpos_height;
4322                            sw->outstanding_position = False;
4323    
4324                            /* Do a complete redraw of the window as part of the
4325                               completion of the move. This is to remove any
4326                               artifacts caused by our lack of synchronization. */
4327                            XCopyArea(g_display, g_backstore,
4328                                      sw->wnd, g_gc,
4329                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4330    
4331                            break;
4332                    }
4333            }
4334    }

Legend:
Removed from v.988  
changed lines
  Added in v.1508

  ViewVC Help
Powered by ViewVC 1.1.26