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

Diff of /sourceforge.net/trunk/rdesktop/xwin.c

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

revision 528 by matthewc, Wed Oct 29 08:37:20 2003 UTC revision 1459 by astrand, Wed Mar 26 16:44:55 2008 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-2002     Copyright (C) Matthew Chapman 1999-2007
5       Copyright 2007 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>
26    #include <sys/time.h>
27  #include <time.h>  #include <time.h>
28  #include <errno.h>  #include <errno.h>
29    #include <strings.h>
30  #include "rdesktop.h"  #include "rdesktop.h"
31  #include "xproto.h"  #include "xproto.h"
32    
33  extern int g_width;  extern int g_width;
34  extern int g_height;  extern int g_height;
35  extern BOOL g_sendmotion;  extern int g_xpos;
36  extern BOOL g_fullscreen;  extern int g_ypos;
37  extern BOOL g_grab_keyboard;  extern int g_pos;
38  extern BOOL g_hide_decorations;  extern RD_BOOL g_sendmotion;
39    extern RD_BOOL g_fullscreen;
40    extern RD_BOOL g_grab_keyboard;
41    extern RD_BOOL g_hide_decorations;
42  extern char g_title[];  extern char g_title[];
43  extern int g_server_bpp;  /* Color depth of the RDP session.
44       As of RDP 5.1, it may be 8, 15, 16 or 24. */
45    extern int g_server_depth;
46  extern int g_win_button_size;  extern int g_win_button_size;
47    
48  Display *g_display;  Display *g_display;
# Line 40  Time g_last_gesturetime; Line 50  Time g_last_gesturetime;
50  static int g_x_socket;  static int g_x_socket;
51  static Screen *g_screen;  static Screen *g_screen;
52  Window g_wnd;  Window g_wnd;
53  BOOL g_enable_compose = False;  
54  static GC g_gc;  /* SeamlessRDP support */
55    typedef struct _seamless_group
56    {
57            Window wnd;
58            unsigned long id;
59            unsigned int refcnt;
60    } seamless_group;
61    typedef struct _seamless_window
62    {
63            Window wnd;
64            unsigned long id;
65            unsigned long behind;
66            seamless_group *group;
67            int xoffset, yoffset;
68            int width, height;
69            int state;              /* normal/minimized/maximized. */
70            unsigned int desktop;
71            struct timeval *position_timer;
72    
73            RD_BOOL outstanding_position;
74            unsigned int outpos_serial;
75            int outpos_xoffset, outpos_yoffset;
76            int outpos_width, outpos_height;
77    
78            unsigned int icon_size;
79            unsigned int icon_offset;
80            char icon_buffer[32 * 32 * 4];
81    
82            struct _seamless_window *next;
83    } seamless_window;
84    static seamless_window *g_seamless_windows = NULL;
85    static unsigned long g_seamless_focused = 0;
86    static RD_BOOL g_seamless_started = False;      /* Server end is up and running */
87    static RD_BOOL g_seamless_active = False;       /* We are currently in seamless mode */
88    static RD_BOOL g_seamless_hidden = False;       /* Desktop is hidden on server */
89    static RD_BOOL g_seamless_broken_restack = False;       /* WM does not properly restack */
90    extern RD_BOOL g_seamless_rdp;
91    
92    extern uint32 g_embed_wnd;
93    RD_BOOL g_enable_compose = False;
94    RD_BOOL g_Unobscured;           /* used for screenblt */
95    static GC g_gc = NULL;
96    static GC g_create_bitmap_gc = NULL;
97    static GC g_create_glyph_gc = NULL;
98    static XRectangle g_clip_rectangle;
99  static Visual *g_visual;  static Visual *g_visual;
100    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
101       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
102       as far as we're concerned. */
103  static int g_depth;  static int g_depth;
104    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
105       This may be larger than g_depth, in which case some of the bits would
106       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
107  static int g_bpp;  static int g_bpp;
108  static XIM g_IM;  static XIM g_IM;
109  static XIC g_IC;  static XIC g_IC;
110  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
111    /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
112       to physical (1-based) indices. */
113    static unsigned char g_pointer_log_to_phys_map[16];
114  static Cursor g_current_cursor;  static Cursor g_current_cursor;
115  static HCURSOR g_null_cursor;  static RD_HCURSOR g_null_cursor = NULL;
116  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
117  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
118  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
119    static RD_BOOL g_focused;
120    static RD_BOOL g_mouse_in_wnd;
121    /* Indicates that:
122       1) visual has 15, 16 or 24 depth and the same color channel masks
123          as its RDP equivalent (implies X server is LE),
124       2) host is LE
125       This will trigger an optimization whose real value is questionable.
126    */
127    static RD_BOOL g_compatible_arch;
128    /* Indicates whether RDP's bitmaps and our XImages have the same
129       binary format. If so, we can avoid an expensive translation.
130       Note that this can be true when g_compatible_arch is false,
131       e.g.:
132      
133         RDP(LE) <-> host(BE) <-> X-Server(LE)
134        
135       ('host' is the machine running rdesktop; the host simply memcpy's
136        so its endianess doesn't matter)
137     */
138    static RD_BOOL g_no_translate_image = False;
139    
140  /* endianness */  /* endianness */
141  static BOOL g_host_be;  static RD_BOOL g_host_be;
142  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
143  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;
144  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;
145    
146  /* software backing store */  /* software backing store */
147  static BOOL g_ownbackstore;  extern RD_BOOL g_ownbackstore;
148  static Pixmap g_backstore;  static Pixmap g_backstore = 0;
149    
150  /* Moving in single app mode */  /* Moving in single app mode */
151  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
152  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
153  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
154    static RD_BOOL g_using_full_workarea = False;
155    
156  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
157  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
158  #endif  #endif
159    
160  /* MWM decorations */  /* MWM decorations */
# Line 80  extern BOOL g_rdpsnd; Line 162  extern BOOL g_rdpsnd;
162  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
163  typedef struct  typedef struct
164  {  {
165          uint32 flags;          unsigned long flags;
166          uint32 functions;          unsigned long functions;
167          uint32 decorations;          unsigned long decorations;
168          sint32 inputMode;          long inputMode;
169          uint32 status;          unsigned long status;
170  }  }
171  PropMotifWmHints;  PropMotifWmHints;
172    
# Line 96  typedef struct Line 178  typedef struct
178  }  }
179  PixelColour;  PixelColour;
180    
181    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
182            do { \
183                    seamless_window *sw; \
184                    XRectangle rect; \
185                    if (!g_seamless_windows) break; \
186                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
187                        rect.x = g_clip_rectangle.x - sw->xoffset; \
188                        rect.y = g_clip_rectangle.y - sw->yoffset; \
189                        rect.width = g_clip_rectangle.width; \
190                        rect.height = g_clip_rectangle.height; \
191                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
192                        func args; \
193                    } \
194                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
195            } while (0)
196    
197    static void
198    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
199    {
200            points[0].x -= xoffset;
201            points[0].y -= yoffset;
202            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
203            points[0].x += xoffset;
204            points[0].y += yoffset;
205    }
206    
207    static void
208    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
209    {
210            points[0].x -= xoffset;
211            points[0].y -= yoffset;
212            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
213            points[0].x += xoffset;
214            points[0].y += yoffset;
215    }
216    
217  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
218  { \  { \
219          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
220            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
221          if (g_ownbackstore) \          if (g_ownbackstore) \
222                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
223  }  }
# Line 109  PixelColour; Line 227  PixelColour;
227          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
228  }  }
229    
230    #define FILL_POLYGON(p,np)\
231    { \
232            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
233            if (g_ownbackstore) \
234                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
235            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
236    }
237    
238    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
239    { \
240            switch (m) \
241            { \
242                    case 0: /* Outline */ \
243                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
244                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
245                            if (g_ownbackstore) \
246                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
247                            break; \
248                    case 1: /* Filled */ \
249                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
250                            ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
251                            if (g_ownbackstore) \
252                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
253                            break; \
254            } \
255    }
256    
257  /* colour maps */  /* colour maps */
258  BOOL g_owncolmap = False;  extern RD_BOOL g_owncolmap;
259  static Colormap g_xcolmap;  static Colormap g_xcolmap;
260  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
261    
262  #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] )
263  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
264  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
265    
# Line 140  static int rop2_map[] = { Line 285  static int rop2_map[] = {
285  #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]); }
286  #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); }
287    
288    static seamless_window *
289    sw_get_window_by_id(unsigned long id)
290    {
291            seamless_window *sw;
292            for (sw = g_seamless_windows; sw; sw = sw->next)
293            {
294                    if (sw->id == id)
295                            return sw;
296            }
297            return NULL;
298    }
299    
300    
301    static seamless_window *
302    sw_get_window_by_wnd(Window wnd)
303    {
304            seamless_window *sw;
305            for (sw = g_seamless_windows; sw; sw = sw->next)
306            {
307                    if (sw->wnd == wnd)
308                            return sw;
309            }
310            return NULL;
311    }
312    
313    
314  static void  static void
315  mwm_hide_decorations(void)  sw_remove_window(seamless_window * win)
316    {
317            seamless_window *sw, **prevnext = &g_seamless_windows;
318            for (sw = g_seamless_windows; sw; sw = sw->next)
319            {
320                    if (sw == win)
321                    {
322                            *prevnext = sw->next;
323                            sw->group->refcnt--;
324                            if (sw->group->refcnt == 0)
325                            {
326                                    XDestroyWindow(g_display, sw->group->wnd);
327                                    xfree(sw->group);
328                            }
329                            xfree(sw->position_timer);
330                            xfree(sw);
331                            return;
332                    }
333                    prevnext = &sw->next;
334            }
335            return;
336    }
337    
338    
339    /* Move all windows except wnd to new desktop */
340    static void
341    sw_all_to_desktop(Window wnd, unsigned int desktop)
342    {
343            seamless_window *sw;
344            for (sw = g_seamless_windows; sw; sw = sw->next)
345            {
346                    if (sw->wnd == wnd)
347                            continue;
348                    if (sw->desktop != desktop)
349                    {
350                            ewmh_move_to_desktop(sw->wnd, desktop);
351                            sw->desktop = desktop;
352                    }
353            }
354    }
355    
356    
357    /* Send our position */
358    static void
359    sw_update_position(seamless_window * sw)
360    {
361            XWindowAttributes wa;
362            int x, y;
363            Window child_return;
364            unsigned int serial;
365    
366            XGetWindowAttributes(g_display, sw->wnd, &wa);
367            XTranslateCoordinates(g_display, sw->wnd, wa.root,
368                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
369    
370            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
371    
372            sw->outstanding_position = True;
373            sw->outpos_serial = serial;
374    
375            sw->outpos_xoffset = x;
376            sw->outpos_yoffset = y;
377            sw->outpos_width = wa.width;
378            sw->outpos_height = wa.height;
379    }
380    
381    
382    /* Check if it's time to send our position */
383    static void
384    sw_check_timers()
385    {
386            seamless_window *sw;
387            struct timeval now;
388    
389            gettimeofday(&now, NULL);
390            for (sw = g_seamless_windows; sw; sw = sw->next)
391            {
392                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
393                    {
394                            timerclear(sw->position_timer);
395                            sw_update_position(sw);
396                    }
397            }
398    }
399    
400    
401    static void
402    sw_restack_window(seamless_window * sw, unsigned long behind)
403    {
404            seamless_window *sw_above;
405    
406            /* Remove window from stack */
407            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
408            {
409                    if (sw_above->behind == sw->id)
410                            break;
411            }
412    
413            if (sw_above)
414                    sw_above->behind = sw->behind;
415    
416            /* And then add it at the new position */
417            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
418            {
419                    if (sw_above->behind == behind)
420                            break;
421            }
422    
423            if (sw_above)
424                    sw_above->behind = sw->id;
425    
426            sw->behind = behind;
427    }
428    
429    
430    static void
431    sw_handle_restack(seamless_window * sw)
432    {
433            Status status;
434            Window root, parent, *children;
435            unsigned int nchildren, i;
436            seamless_window *sw_below;
437    
438            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
439                                &root, &parent, &children, &nchildren);
440            if (!status || !nchildren)
441                    return;
442    
443            sw_below = NULL;
444    
445            i = 0;
446            while (children[i] != sw->wnd)
447            {
448                    i++;
449                    if (i >= nchildren)
450                            goto end;
451            }
452    
453            for (i++; i < nchildren; i++)
454            {
455                    sw_below = sw_get_window_by_wnd(children[i]);
456                    if (sw_below)
457                            break;
458            }
459    
460            if (!sw_below && !sw->behind)
461                    goto end;
462            if (sw_below && (sw_below->id == sw->behind))
463                    goto end;
464    
465            if (sw_below)
466            {
467                    seamless_send_zchange(sw->id, sw_below->id, 0);
468                    sw_restack_window(sw, sw_below->id);
469            }
470            else
471            {
472                    seamless_send_zchange(sw->id, 0, 0);
473                    sw_restack_window(sw, 0);
474            }
475    
476          end:
477            XFree(children);
478    }
479    
480    
481    static seamless_group *
482    sw_find_group(unsigned long id, RD_BOOL dont_create)
483    {
484            seamless_window *sw;
485            seamless_group *sg;
486            XSetWindowAttributes attribs;
487    
488            for (sw = g_seamless_windows; sw; sw = sw->next)
489            {
490                    if (sw->group->id == id)
491                            return sw->group;
492            }
493    
494            if (dont_create)
495                    return NULL;
496    
497            sg = xmalloc(sizeof(seamless_group));
498    
499            sg->wnd =
500                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
501                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
502    
503            sg->id = id;
504            sg->refcnt = 0;
505    
506            return sg;
507    }
508    
509    
510    static void
511    mwm_hide_decorations(Window wnd)
512  {  {
513          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
514          Atom hintsatom;          Atom hintsatom;
# Line 158  mwm_hide_decorations(void) Line 525  mwm_hide_decorations(void)
525                  return;                  return;
526          }          }
527    
528          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
529                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
530    
531  }  }
532    
533  static PixelColour  typedef struct _sw_configurenotify_context
 split_colour15(uint32 colour)  
534  {  {
535          PixelColour rv;          Window window;
536          rv.red = (colour & 0x7c00) >> 10;          unsigned long serial;
537          rv.red = (rv.red * 0xff) / 0x1f;  } sw_configurenotify_context;
538          rv.green = (colour & 0x03e0) >> 5;  
539          rv.green = (rv.green * 0xff) / 0x1f;  /* Predicate procedure for sw_wait_configurenotify */
540          rv.blue = (colour & 0x1f);  static Bool
541          rv.blue = (rv.blue * 0xff) / 0x1f;  sw_configurenotify_p(Display * display, XEvent * xevent, XPointer arg)
542          return rv;  {
543  }          sw_configurenotify_context *context = (sw_configurenotify_context *) arg;
544            if (xevent->xany.type == ConfigureNotify
545  static PixelColour              && xevent->xconfigure.window == context->window
546  split_colour16(uint32 colour)              && xevent->xany.serial >= context->serial)
547  {                  return True;
548          PixelColour rv;  
549          rv.red = (colour & 0xf800) >> 11;          return False;
550          rv.red = (rv.red * 0xff) / 0x1f;  }
551          rv.green = (colour & 0x07e0) >> 5;  
552          rv.green = (rv.green * 0xff) / 0x3f;  /* Wait for a ConfigureNotify, with a equal or larger serial, on the
553          rv.blue = (colour & 0x001f);     specified window. The event will be removed from the queue. We
554          rv.blue = (rv.blue * 0xff) / 0x1f;     could use XMaskEvent(StructureNotifyMask), but we would then risk
555          return rv;     throwing away crucial events like DestroyNotify.
556  }  
557       After a ConfigureWindow, according to ICCCM section 4.1.5, we
558  static PixelColour     should recieve a ConfigureNotify, either a real or synthetic
559  split_colour24(uint32 colour)     one. This indicates that the configure has been "completed".
560  {     However, some WMs such as several versions of Metacity fails to
561          PixelColour rv;     send synthetic events. See bug
562          rv.blue = (colour & 0xff0000) >> 16;     http://bugzilla.gnome.org/show_bug.cgi?id=322840. We need to use a
563          rv.green = (colour & 0xff00) >> 8;     timeout to avoid a hang. Tk uses the same approach. */
564          rv.red = (colour & 0xff);  static void
565          return rv;  sw_wait_configurenotify(Window wnd, unsigned long serial)
566    {
567            XEvent xevent;
568            sw_configurenotify_context context;
569            time_t start;
570            RD_BOOL got = False;
571    
572            context.window = wnd;
573            context.serial = serial;
574            start = time(NULL);
575    
576            do
577            {
578                    if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context))
579                    {
580                            got = True;
581                            break;
582                    }
583                    usleep(100000);
584            }
585            while (time(NULL) - start < 2);
586    
587            if (!got)
588            {
589                    warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
590            }
591  }  }
592    
593  static uint32  /* Get the toplevel window, in case of reparenting */
594  make_colour(PixelColour pc)  static Window
595    sw_get_toplevel(Window wnd)
596  {  {
597          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          Window root, parent;
598                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          Window *child_list;
599                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));          unsigned int num_children;
600    
601            while (1)
602            {
603                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
604                    if (root == parent)
605                    {
606                            break;
607                    }
608                    else if (!parent)
609                    {
610                            warning("Internal error: sw_get_toplevel called with root window\n");
611                    }
612    
613                    wnd = parent;
614            }
615    
616            return wnd;
617    }
618    
619    
620    /* Check if wnd is already behind a window wrt stacking order */
621    static RD_BOOL
622    sw_window_is_behind(Window wnd, Window behind)
623    {
624            Window dummy1, dummy2;
625            Window *child_list;
626            unsigned int num_children;
627            unsigned int i;
628            RD_BOOL found_behind = False;
629            RD_BOOL found_wnd = False;
630    
631            wnd = sw_get_toplevel(wnd);
632            behind = sw_get_toplevel(behind);
633    
634            XQueryTree(g_display, RootWindowOfScreen(g_screen), &dummy1, &dummy2, &child_list,
635                       &num_children);
636    
637            for (i = num_children - 1; i >= 0; i--)
638            {
639                    if (child_list[i] == behind)
640                    {
641                            found_behind = True;
642                    }
643                    else if (child_list[i] == wnd)
644                    {
645                            found_wnd = True;
646                            break;
647                    }
648            }
649    
650            if (child_list)
651                    XFree(child_list);
652    
653            if (!found_wnd)
654            {
655                    warning("sw_window_is_behind: Unable to find window 0x%lx\n", wnd);
656    
657                    if (!found_behind)
658                    {
659                            warning("sw_window_is_behind: Unable to find behind window 0x%lx\n",
660                                    behind);
661                    }
662            }
663    
664            return found_behind;
665    }
666    
667    
668    /* Test if the window manager correctly handles window restacking. In
669       particular, we are testing if it's possible to place a window
670       between two other windows. Many WMs such as Metacity can only stack
671       windows on the top or bottom. The window creation should mostly
672       match ui_seamless_create_window. */
673    static void
674    seamless_restack_test()
675    {
676            /* The goal is to have the middle window between top and
677               bottom.  The middle window is initially at the top,
678               though. */
679            Window wnds[3];         /* top, middle and bottom */
680            int i;
681            XEvent xevent;
682            XWindowChanges values;
683            unsigned long restack_serial;
684    
685            for (i = 0; i < 3; i++)
686            {
687                    char name[64];
688                    wnds[i] =
689                            XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, 20, 20,
690                                                0, 0, 0);
691                    snprintf(name, sizeof(name), "SeamlessRDP restack test - window %d", i);
692                    XStoreName(g_display, wnds[i], name);
693                    ewmh_set_wm_name(wnds[i], name);
694    
695                    /* Hide decorations. Often this means that no
696                       reparenting will be done, which makes the restack
697                       easier. Besides, we want to mimic our other
698                       seamless windows as much as possible. We must still
699                       handle the case with reparenting, though. */
700                    mwm_hide_decorations(wnds[i]);
701    
702                    /* Prevent windows from appearing in task bar */
703                    XSetTransientForHint(g_display, wnds[i], RootWindowOfScreen(g_screen));
704                    ewmh_set_window_popup(wnds[i]);
705    
706                    /* We need to catch MapNotify/ConfigureNotify */
707                    XSelectInput(g_display, wnds[i], StructureNotifyMask);
708            }
709    
710            /* Map Windows. Currently, we assume that XMapRaised places
711               the window on the top of the stack. Should be fairly safe;
712               the window is configured before it's mapped. */
713            XMapRaised(g_display, wnds[2]); /* bottom */
714            do
715            {
716                    XWindowEvent(g_display, wnds[2], StructureNotifyMask, &xevent);
717            }
718            while (xevent.type != MapNotify);
719            XMapRaised(g_display, wnds[0]); /* top */
720            do
721            {
722                    XWindowEvent(g_display, wnds[0], StructureNotifyMask, &xevent);
723            }
724            while (xevent.type != MapNotify);
725            XMapRaised(g_display, wnds[1]); /* middle */
726            do
727            {
728                    XWindowEvent(g_display, wnds[1], StructureNotifyMask, &xevent);
729            }
730            while (xevent.type != MapNotify);
731    
732            /* The stacking order should now be 1 - 0 - 2 */
733            if (!sw_window_is_behind(wnds[0], wnds[1]) || !sw_window_is_behind(wnds[2], wnds[1]))
734            {
735                    /* Ok, technically a WM is allowed to stack windows arbitrarily, but... */
736                    warning("Broken Window Manager: Unable to test window restacking\n");
737                    g_seamless_broken_restack = True;
738                    for (i = 0; i < 3; i++)
739                            XDestroyWindow(g_display, wnds[i]);
740                    return;
741            }
742    
743            /* Restack, using XReconfigureWMWindow, which should correctly
744               handle reparented windows as well as nonreparenting WMs. */
745            values.stack_mode = Below;
746            values.sibling = wnds[0];
747            restack_serial = XNextRequest(g_display);
748            XReconfigureWMWindow(g_display, wnds[1], DefaultScreen(g_display), CWStackMode | CWSibling,
749                                 &values);
750            sw_wait_configurenotify(wnds[1], restack_serial);
751    
752            /* Now verify that middle is behind top but not behind
753               bottom */
754            if (!sw_window_is_behind(wnds[1], wnds[0]))
755            {
756                    warning("Broken Window Manager: doesn't handle restack (restack request was ignored)\n");
757                    g_seamless_broken_restack = True;
758            }
759            else if (sw_window_is_behind(wnds[1], wnds[2]))
760            {
761                    warning("Broken Window Manager: doesn't handle restack (window was moved to bottom)\n");
762                    g_seamless_broken_restack = True;
763            }
764    
765            /* Destroy windows */
766            for (i = 0; i < 3; i++)
767                    XDestroyWindow(g_display, wnds[i]);
768    }
769    
770    #define SPLITCOLOUR15(colour, rv) \
771    { \
772            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
773            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
774            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
775  }  }
776    
777    #define SPLITCOLOUR16(colour, rv) \
778    { \
779            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
780            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
781            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
782    } \
783    
784    #define SPLITCOLOUR24(colour, rv) \
785    { \
786            rv.blue = (colour & 0xff0000) >> 16; \
787            rv.green = (colour & 0x00ff00) >> 8; \
788            rv.red = (colour & 0x0000ff); \
789    }
790    
791    #define MAKECOLOUR(pc) \
792            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
793                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
794                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
795    
796  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
797  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
798  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
799                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
800    
801    /* The following macros output the same octet sequences
802       on both BE and LE hosts: */
803    
804    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
805    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
806    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
807    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
808    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
809    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
810    
811  static uint32  static uint32
812  translate_colour(uint32 colour)  translate_colour(uint32 colour)
813  {  {
814          PixelColour pc;          PixelColour pc;
815          switch (g_server_bpp)          switch (g_server_depth)
816          {          {
817                  case 15:                  case 15:
818                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
819                          break;                          break;
820                  case 16:                  case 16:
821                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
822                          break;                          break;
823                  case 24:                  case 24:
824                          pc = split_colour24(colour);                  case 32:
825                            SPLITCOLOUR24(colour, pc);
826                            break;
827                    default:
828                            /* Avoid warning */
829                            pc.red = 0;
830                            pc.green = 0;
831                            pc.blue = 0;
832                          break;                          break;
833          }          }
834          return make_colour(pc);          return MAKECOLOUR(pc);
835    }
836    
837    /* indent is confused by UNROLL8 */
838    /* *INDENT-OFF* */
839    
840    /* repeat and unroll, similar to bitmap.c */
841    /* potentialy any of the following translate */
842    /* functions can use repeat but just doing */
843    /* the most common ones */
844    
845    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
846    /* 2 byte output repeat */
847    #define REPEAT2(stm) \
848    { \
849            while (out <= end - 8 * 2) \
850                    UNROLL8(stm) \
851            while (out < end) \
852                    { stm } \
853    }
854    /* 3 byte output repeat */
855    #define REPEAT3(stm) \
856    { \
857            while (out <= end - 8 * 3) \
858                    UNROLL8(stm) \
859            while (out < end) \
860                    { stm } \
861  }  }
862    /* 4 byte output repeat */
863    #define REPEAT4(stm) \
864    { \
865            while (out <= end - 8 * 4) \
866                    UNROLL8(stm) \
867            while (out < end) \
868                    { stm } \
869    }
870    /* *INDENT-ON* */
871    
872  static void  static void
873  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
874  {  {
875          while (out < end)          while (out < end)
876                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
877  }  }
878    
879  static void  static void
880  translate8to16(uint8 * data, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
881  {  {
882          uint16 value;          uint16 value;
883    
884          while (out < end)          if (g_compatible_arch)
885          {          {
886                  value = (uint16) g_colmap[*(data++)];                  /* *INDENT-OFF* */
887                                    REPEAT2
888                  if (g_xserver_be)                  (
889                            *((uint16 *) out) = g_colmap[*(data++)];
890                            out += 2;
891                    )
892                    /* *INDENT-ON* */
893            }
894            else if (g_xserver_be)
895            {
896                    while (out < end)
897                  {                  {
898                          *(out++) = value >> 8;                          value = (uint16) g_colmap[*(data++)];
899                          *(out++) = value;                          BOUT16(out, value);
900                  }                  }
901                  else          }
902            else
903            {
904                    while (out < end)
905                  {                  {
906                          *(out++) = value;                          value = (uint16) g_colmap[*(data++)];
907                          *(out++) = value >> 8;                          LOUT16(out, value);
908                  }                  }
909          }          }
910  }  }
911    
912  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
913  static void  static void
914  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
915  {  {
916          uint32 value;          uint32 value;
917    
918          while (out < end)          if (g_compatible_arch)
919          {          {
920                  value = g_colmap[*(data++)];                  while (out < end)
                   
                 if (g_xserver_be)  
921                  {                  {
922                          *(out++) = value >> 16;                          value = g_colmap[*(data++)];
923                          *(out++) = value >> 8;                          BOUT24(out, value);
                         *(out++) = value;  
924                  }                  }
925                  else          }
926            else
927            {
928                    while (out < end)
929                  {                  {
930                          *(out++) = value;                          value = g_colmap[*(data++)];
931                          *(out++) = value >> 8;                          LOUT24(out, value);
                         *(out++) = value >> 16;  
932                  }                  }
933          }          }
934  }  }
935    
936  static void  static void
937  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
938  {  {
939          uint32 value;          uint32 value;
940    
941          while (out < end)          if (g_compatible_arch)
942          {          {
943                  value = g_colmap[*(data++)];                  /* *INDENT-OFF* */
944                    REPEAT4
945                  if (g_xserver_be)                  (
946                            *((uint32 *) out) = g_colmap[*(data++)];
947                            out += 4;
948                    )
949                    /* *INDENT-ON* */
950            }
951            else if (g_xserver_be)
952            {
953                    while (out < end)
954                  {                  {
955                          *(out++) = value >> 24;                          value = g_colmap[*(data++)];
956                          *(out++) = value >> 16;                          BOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
957                  }                  }
958                  else          }
959            else
960            {
961                    while (out < end)
962                  {                  {
963                          *(out++) = value;                          value = g_colmap[*(data++)];
964                          *(out++) = value >> 8;                          LOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
965                  }                  }
966          }          }
967  }  }
968    
 /* todo the remaining translate function might need some big endian check ?? */  
   
969  static void  static void
970  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
971  {  {
972          uint16 pixel;          uint16 pixel;
973          uint16 value;          uint16 value;
974            PixelColour pc;
975    
976          while (out < end)          if (g_xserver_be)
977          {          {
978                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
979                  {                  {
980                          BSWAP16(pixel);                          pixel = *(data++);
981                  }                          if (g_host_be)
982                            {
983                  value = make_colour(split_colour15(pixel));                                  BSWAP16(pixel);
984                            }
985                  if (g_xserver_be)                          SPLITCOLOUR15(pixel, pc);
986                  {                          value = MAKECOLOUR(pc);
987                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
988                  }                  }
989                  else          }
990            else
991            {
992                    while (out < end)
993                  {                  {
994                          *(out++) = value;                          pixel = *(data++);
995                          *(out++) = value >> 8;                          if (g_host_be)
996                            {
997                                    BSWAP16(pixel);
998                            }
999                            SPLITCOLOUR15(pixel, pc);
1000                            value = MAKECOLOUR(pc);
1001                            LOUT16(out, value);
1002                  }                  }
1003          }          }
1004  }  }
1005    
1006  static void  static void
1007  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
1008  {  {
1009          uint32 value;          uint32 value;
1010          uint16 pixel;          uint16 pixel;
1011            PixelColour pc;
1012    
1013          while (out < end)          if (g_compatible_arch)
1014          {          {
1015                  pixel = *(data++);                  /* *INDENT-OFF* */
1016                    REPEAT3
1017                  if (g_host_be)                  (
1018                  {                          pixel = *(data++);
1019                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
1020                  }                          *(out++) = pc.blue;
1021                            *(out++) = pc.green;
1022                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
1023                  if (g_xserver_be)                  )
1024                    /* *INDENT-ON* */
1025            }
1026            else if (g_xserver_be)
1027            {
1028                    while (out < end)
1029                  {                  {
1030                          *(out++) = value >> 16;                          pixel = *(data++);
1031                          *(out++) = value >> 8;                          if (g_host_be)
1032                          *(out++) = value;                          {
1033                                    BSWAP16(pixel);
1034                            }
1035                            SPLITCOLOUR15(pixel, pc);
1036                            value = MAKECOLOUR(pc);
1037                            BOUT24(out, value);
1038                  }                  }
1039                  else          }
1040            else
1041            {
1042                    while (out < end)
1043                  {                  {
1044                          *(out++) = value;                          pixel = *(data++);
1045                          *(out++) = value >> 8;                          if (g_host_be)
1046                          *(out++) = value >> 16;                          {
1047                                    BSWAP16(pixel);
1048                            }
1049                            SPLITCOLOUR15(pixel, pc);
1050                            value = MAKECOLOUR(pc);
1051                            LOUT24(out, value);
1052                  }                  }
1053          }          }
1054  }  }
1055    
1056  static void  static void
1057  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
1058  {  {
1059          uint16 pixel;          uint16 pixel;
1060          uint32 value;          uint32 value;
1061            PixelColour pc;
1062    
1063          while (out < end)          if (g_compatible_arch)
1064          {          {
1065                  pixel = *(data++);                  /* *INDENT-OFF* */
1066                    REPEAT4
1067                  if (g_host_be)                  (
1068                  {                          pixel = *(data++);
1069                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
1070                  }                          *(out++) = pc.blue;
1071                            *(out++) = pc.green;
1072                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
1073                            *(out++) = 0;
1074                  if (g_xserver_be)                  )
1075                    /* *INDENT-ON* */
1076            }
1077            else if (g_xserver_be)
1078            {
1079                    while (out < end)
1080                  {                  {
1081                          *(out++) = value >> 24;                          pixel = *(data++);
1082                          *(out++) = value >> 16;                          if (g_host_be)
1083                          *(out++) = value >> 8;                          {
1084                          *(out++) = value;                                  BSWAP16(pixel);
1085                            }
1086                            SPLITCOLOUR15(pixel, pc);
1087                            value = MAKECOLOUR(pc);
1088                            BOUT32(out, value);
1089                  }                  }
1090                  else          }
1091            else
1092            {
1093                    while (out < end)
1094                  {                  {
1095                          *(out++) = value;                          pixel = *(data++);
1096                          *(out++) = value >> 8;                          if (g_host_be)
1097                          *(out++) = value >> 16;                          {
1098                          *(out++) = value >> 24;                                  BSWAP16(pixel);
1099                            }
1100                            SPLITCOLOUR15(pixel, pc);
1101                            value = MAKECOLOUR(pc);
1102                            LOUT32(out, value);
1103                  }                  }
1104          }          }
1105  }  }
1106    
1107  static void  static void
1108  translate16to16(uint16 * data, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
1109  {  {
1110          uint16 pixel;          uint16 pixel;
1111          uint16 value;          uint16 value;
1112            PixelColour pc;
1113    
1114          while (out < end)          if (g_xserver_be)
1115          {          {
                 pixel = *(data++);  
   
1116                  if (g_host_be)                  if (g_host_be)
1117                  {                  {
1118                          BSWAP16(pixel);                          while (out < end)
1119                            {
1120                                    pixel = *(data++);
1121                                    BSWAP16(pixel);
1122                                    SPLITCOLOUR16(pixel, pc);
1123                                    value = MAKECOLOUR(pc);
1124                                    BOUT16(out, value);
1125                            }
1126                  }                  }
1127                    else
1128                  value = make_colour(split_colour16(pixel));                  {
1129                            while (out < end)
1130                  if (g_xserver_be)                          {
1131                                    pixel = *(data++);
1132                                    SPLITCOLOUR16(pixel, pc);
1133                                    value = MAKECOLOUR(pc);
1134                                    BOUT16(out, value);
1135                            }
1136                    }
1137            }
1138            else
1139            {
1140                    if (g_host_be)
1141                  {                  {
1142                          *(out++) = value >> 8;                          while (out < end)
1143                          *(out++) = value;                          {
1144                                    pixel = *(data++);
1145                                    BSWAP16(pixel);
1146                                    SPLITCOLOUR16(pixel, pc);
1147                                    value = MAKECOLOUR(pc);
1148                                    LOUT16(out, value);
1149                            }
1150                  }                  }
1151                  else                  else
1152                  {                  {
1153                          *(out++) = value;                          while (out < end)
1154                          *(out++) = value >> 8;                          {
1155                                    pixel = *(data++);
1156                                    SPLITCOLOUR16(pixel, pc);
1157                                    value = MAKECOLOUR(pc);
1158                                    LOUT16(out, value);
1159                            }
1160                  }                  }
1161          }          }
1162  }  }
1163    
1164  static void  static void
1165  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
1166  {  {
1167          uint32 value;          uint32 value;
1168          uint16 pixel;          uint16 pixel;
1169            PixelColour pc;
1170    
1171          while (out < end)          if (g_compatible_arch)
1172            {
1173                    /* *INDENT-OFF* */
1174                    REPEAT3
1175                    (
1176                            pixel = *(data++);
1177                            SPLITCOLOUR16(pixel, pc);
1178                            *(out++) = pc.blue;
1179                            *(out++) = pc.green;
1180                            *(out++) = pc.red;
1181                    )
1182                    /* *INDENT-ON* */
1183            }
1184            else if (g_xserver_be)
1185          {          {
                 pixel = *(data++);  
   
1186                  if (g_host_be)                  if (g_host_be)
1187                  {                  {
1188                          BSWAP16(pixel);                          while (out < end)
1189                            {
1190                                    pixel = *(data++);
1191                                    BSWAP16(pixel);
1192                                    SPLITCOLOUR16(pixel, pc);
1193                                    value = MAKECOLOUR(pc);
1194                                    BOUT24(out, value);
1195                            }
1196                    }
1197                    else
1198                    {
1199                            while (out < end)
1200                            {
1201                                    pixel = *(data++);
1202                                    SPLITCOLOUR16(pixel, pc);
1203                                    value = MAKECOLOUR(pc);
1204                                    BOUT24(out, value);
1205                            }
1206                  }                  }
1207            }
1208                  value = make_colour(split_colour16(pixel));          else
1209            {
1210                  if (g_xserver_be)                  if (g_host_be)
1211                  {                  {
1212                          *(out++) = value >> 16;                          while (out < end)
1213                          *(out++) = value >> 8;                          {
1214                          *(out++) = value;                                  pixel = *(data++);
1215                                    BSWAP16(pixel);
1216                                    SPLITCOLOUR16(pixel, pc);
1217                                    value = MAKECOLOUR(pc);
1218                                    LOUT24(out, value);
1219                            }
1220                  }                  }
1221                  else                  else
1222                  {                  {
1223                          *(out++) = value;                          while (out < end)
1224                          *(out++) = value >> 8;                          {
1225                          *(out++) = value >> 16;                                  pixel = *(data++);
1226                                    SPLITCOLOUR16(pixel, pc);
1227                                    value = MAKECOLOUR(pc);
1228                                    LOUT24(out, value);
1229                            }
1230                  }                  }
1231          }          }
1232  }  }
1233    
1234  static void  static void
1235  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
1236  {  {
1237          uint16 pixel;          uint16 pixel;
1238          uint32 value;          uint32 value;
1239            PixelColour pc;
1240    
1241          while (out < end)          if (g_compatible_arch)
1242            {
1243                    /* *INDENT-OFF* */
1244                    REPEAT4
1245                    (
1246                            pixel = *(data++);
1247                            SPLITCOLOUR16(pixel, pc);
1248                            *(out++) = pc.blue;
1249                            *(out++) = pc.green;
1250                            *(out++) = pc.red;
1251                            *(out++) = 0;
1252                    )
1253                    /* *INDENT-ON* */
1254            }
1255            else if (g_xserver_be)
1256          {          {
                 pixel = *(data++);  
   
1257                  if (g_host_be)                  if (g_host_be)
1258                  {                  {
1259                  BSWAP16(pixel)}                          while (out < end)
1260                            {
1261                  value = make_colour(split_colour16(pixel));                                  pixel = *(data++);
1262                                    BSWAP16(pixel);
1263                  if (g_xserver_be)                                  SPLITCOLOUR16(pixel, pc);
1264                                    value = MAKECOLOUR(pc);
1265                                    BOUT32(out, value);
1266                            }
1267                    }
1268                    else
1269                    {
1270                            while (out < end)
1271                            {
1272                                    pixel = *(data++);
1273                                    SPLITCOLOUR16(pixel, pc);
1274                                    value = MAKECOLOUR(pc);
1275                                    BOUT32(out, value);
1276                            }
1277                    }
1278            }
1279            else
1280            {
1281                    if (g_host_be)
1282                  {                  {
1283                          *(out++) = value >> 24;                          while (out < end)
1284                          *(out++) = value >> 16;                          {
1285                          *(out++) = value >> 8;                                  pixel = *(data++);
1286                          *(out++) = value;                                  BSWAP16(pixel);
1287                                    SPLITCOLOUR16(pixel, pc);
1288                                    value = MAKECOLOUR(pc);
1289                                    LOUT32(out, value);
1290                            }
1291                  }                  }
1292                  else                  else
1293                  {                  {
1294                          *(out++) = value;                          while (out < end)
1295                          *(out++) = value >> 8;                          {
1296                          *(out++) = value >> 16;                                  pixel = *(data++);
1297                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
1298                                    value = MAKECOLOUR(pc);
1299                                    LOUT32(out, value);
1300                            }
1301                  }                  }
1302          }          }
1303  }  }
1304    
1305  static void  static void
1306  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1307  {  {
1308          uint32 pixel = 0;          uint32 pixel = 0;
1309          uint16 value;          uint16 value;
1310            PixelColour pc;
1311    
1312          while (out < end)          while (out < end)
1313          {          {
1314                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1315                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1316                  pixel |= *(data++);                  pixel |= *(data++);
1317                    SPLITCOLOUR24(pixel, pc);
1318                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1319                  if (g_xserver_be)                  if (g_xserver_be)
1320                  {                  {
1321                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1322                  }                  }
1323                  else                  else
1324                  {                  {
1325                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1326                  }                  }
1327          }          }
1328  }  }
1329    
1330  static void  static void
1331  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1332  {  {
1333          while (out < end)          uint32 pixel;
1334            uint32 value;
1335            PixelColour pc;
1336    
1337            if (g_xserver_be)
1338          {          {
1339                  *(out++) = (*(data++));                  while (out < end)
1340                    {
1341                            pixel = *(data++) << 16;
1342                            pixel |= *(data++) << 8;
1343                            pixel |= *(data++);
1344                            SPLITCOLOUR24(pixel, pc);
1345                            value = MAKECOLOUR(pc);
1346                            BOUT24(out, value);
1347                    }
1348            }
1349            else
1350            {
1351                    while (out < end)
1352                    {
1353                            pixel = *(data++) << 16;
1354                            pixel |= *(data++) << 8;
1355                            pixel |= *(data++);
1356                            SPLITCOLOUR24(pixel, pc);
1357                            value = MAKECOLOUR(pc);
1358                            LOUT24(out, value);
1359                    }
1360          }          }
1361  }  }
1362    
1363  static void  static void
1364  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1365  {  {
1366          while (out < end)          uint32 pixel;
1367            uint32 value;
1368            PixelColour pc;
1369    
1370            if (g_compatible_arch)
1371          {          {
1372                  if (g_xserver_be)                  /* *INDENT-OFF* */
1373                  {  #ifdef NEED_ALIGN
1374                          *(out++) = 0x00;                  REPEAT4
1375                    (
1376                          *(out++) = *(data++);                          *(out++) = *(data++);
1377                          *(out++) = *(data++);                          *(out++) = *(data++);
1378                          *(out++) = *(data++);                          *(out++) = *(data++);
1379                            *(out++) = 0;
1380                    )
1381    #else
1382                    REPEAT4
1383                    (
1384                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1385                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1386                     out += 4;
1387                     data += 3;
1388                    )
1389    #endif
1390                    /* *INDENT-ON* */
1391            }
1392            else if (g_xserver_be)
1393            {
1394                    while (out < end)
1395                    {
1396                            pixel = *(data++) << 16;
1397                            pixel |= *(data++) << 8;
1398                            pixel |= *(data++);
1399                            SPLITCOLOUR24(pixel, pc);
1400                            value = MAKECOLOUR(pc);
1401                            BOUT32(out, value);
1402                  }                  }
1403                  else          }
1404            else
1405            {
1406                    while (out < end)
1407                  {                  {
1408                          *(out++) = *(data++);                          pixel = *(data++) << 16;
1409                          *(out++) = *(data++);                          pixel |= *(data++) << 8;
1410                          *(out++) = *(data++);                          pixel |= *(data++);
1411                          *(out++) = 0x00;                          SPLITCOLOUR24(pixel, pc);
1412                            value = MAKECOLOUR(pc);
1413                            LOUT32(out, value);
1414                  }                  }
1415          }          }
1416  }  }
# Line 562  translate24to32(uint8 * data, uint8 * ou Line 1418  translate24to32(uint8 * data, uint8 * ou
1418  static uint8 *  static uint8 *
1419  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1420  {  {
1421          int size = width * height * g_bpp / 8;          int size;
1422          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1423          uint8 *end = out + size;          uint8 *end;
1424    
1425          switch (g_server_bpp)          /*
1426               If RDP depth and X Visual depths match,
1427               and arch(endian) matches, no need to translate:
1428               just return data.
1429               Note: select_visual should've already ensured g_no_translate
1430               is only set for compatible depths, but the RDP depth might've
1431               changed during connection negotiations.
1432             */
1433    
1434            /* todo */
1435            if (g_server_depth == 32 && g_depth == 24)
1436            {
1437                    return data;
1438            }
1439    
1440            if (g_no_translate_image)
1441            {
1442                    if ((g_depth == 15 && g_server_depth == 15) ||
1443                        (g_depth == 16 && g_server_depth == 16) ||
1444                        (g_depth == 24 && g_server_depth == 24))
1445                            return data;
1446            }
1447    
1448            size = width * height * (g_bpp / 8);
1449            out = (uint8 *) xmalloc(size);
1450            end = out + size;
1451    
1452            switch (g_server_depth)
1453          {          {
1454                  case 24:                  case 24:
1455                          switch (g_bpp)                          switch (g_bpp)
# Line 631  translate_image(int width, int height, u Line 1514  translate_image(int width, int height, u
1514          return out;          return out;
1515  }  }
1516    
1517  BOOL  static void
1518    xwin_refresh_pointer_map(void)
1519    {
1520            unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
1521            int i, pointer_buttons;
1522    
1523            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1524            for (i = 0; i < pointer_buttons; ++i)
1525            {
1526                    /* This might produce multiple logical buttons mapping
1527                       to a single physical one, but hey, that's
1528                       life... */
1529                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1530            }
1531    }
1532    
1533    RD_BOOL
1534  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1535  {  {
1536          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 664  calculate_shifts(uint32 mask, int *shift Line 1563  calculate_shifts(uint32 mask, int *shift
1563          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1564  }  }
1565    
1566  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1567  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1568     */
1569    static unsigned
1570    calculate_mask_weight(uint32 mask)
1571    {
1572            unsigned weight = 0;
1573            do
1574            {
1575                    weight += (mask & 1);
1576            }
1577            while (mask >>= 1);
1578            return weight;
1579    }
1580    
1581    static RD_BOOL
1582    select_visual(int screen_num)
1583  {  {
         XVisualInfo vi;  
1584          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1585          uint16 test;          int pixmap_formats_count, visuals_count;
1586          int i, screen_num;          XVisualInfo *vmatches = NULL;
1587            XVisualInfo template;
1588            int i;
1589            unsigned red_weight, blue_weight, green_weight;
1590    
1591          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1592          if (g_display == NULL)  
1593            if (g_server_depth == -1)
1594          {          {
1595                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1596            }
1597    
1598            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1599            if (pfm == NULL)
1600            {
1601                    error("Unable to get list of pixmap formats from display.\n");
1602                    XCloseDisplay(g_display);
1603                  return False;                  return False;
1604          }          }
1605    
1606          screen_num = DefaultScreen(g_display);          /* Search for best TrueColor visual */
1607          g_x_socket = ConnectionNumber(g_display);          template.class = TrueColor;
1608          g_screen = ScreenOfDisplay(g_display, screen_num);          template.screen = screen_num;
1609          g_depth = DefaultDepthOfScreen(g_screen);          vmatches =
1610                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1611                                   &visuals_count);
1612            g_visual = NULL;
1613            g_no_translate_image = False;
1614            g_compatible_arch = False;
1615            if (vmatches != NULL)
1616            {
1617                    for (i = 0; i < visuals_count; ++i)
1618                    {
1619                            XVisualInfo *visual_info = &vmatches[i];
1620                            RD_BOOL can_translate_to_bpp = False;
1621                            int j;
1622    
1623                            /* Try to find a no-translation visual that'll
1624                               allow us to use RDP bitmaps directly as ZPixmaps. */
1625                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1626                                                   /* R5G5B5 */
1627                                                   (visual_info->red_mask == 0x7c00) &&
1628                                                   (visual_info->green_mask == 0x3e0) &&
1629                                                   (visual_info->blue_mask == 0x1f)) ||
1630                                                  ((visual_info->depth == 16) &&
1631                                                   /* R5G6B5 */
1632                                                   (visual_info->red_mask == 0xf800) &&
1633                                                   (visual_info->green_mask == 0x7e0) &&
1634                                                   (visual_info->blue_mask == 0x1f)) ||
1635                                                  ((visual_info->depth == 24) &&
1636                                                   /* R8G8B8 */
1637                                                   (visual_info->red_mask == 0xff0000) &&
1638                                                   (visual_info->green_mask == 0xff00) &&
1639                                                   (visual_info->blue_mask == 0xff))))
1640                            {
1641                                    g_visual = visual_info->visual;
1642                                    g_depth = visual_info->depth;
1643                                    g_compatible_arch = !g_host_be;
1644                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1645                                    if (g_no_translate_image)
1646                                            /* We found the best visual */
1647                                            break;
1648                            }
1649                            else
1650                            {
1651                                    g_compatible_arch = False;
1652                            }
1653    
1654                            if (visual_info->depth > 24)
1655                            {
1656                                    /* Avoid 32-bit visuals and likes like the plague.
1657                                       They're either untested or proven to work bad
1658                                       (e.g. nvidia's Composite 32-bit visual).
1659                                       Most implementation offer a 24-bit visual anyway. */
1660                                    continue;
1661                            }
1662    
1663                            /* Only care for visuals, for whose BPPs (not depths!)
1664                               we have a translateXtoY function. */
1665                            for (j = 0; j < pixmap_formats_count; ++j)
1666                            {
1667                                    if (pfm[j].depth == visual_info->depth)
1668                                    {
1669                                            if ((pfm[j].bits_per_pixel == 16) ||
1670                                                (pfm[j].bits_per_pixel == 24) ||
1671                                                (pfm[j].bits_per_pixel == 32))
1672                                            {
1673                                                    can_translate_to_bpp = True;
1674                                            }
1675                                            break;
1676                                    }
1677                            }
1678    
1679                            /* Prefer formats which have the most colour depth.
1680                               We're being truly aristocratic here, minding each
1681                               weight on its own. */
1682                            if (can_translate_to_bpp)
1683                            {
1684                                    unsigned vis_red_weight =
1685                                            calculate_mask_weight(visual_info->red_mask);
1686                                    unsigned vis_green_weight =
1687                                            calculate_mask_weight(visual_info->green_mask);
1688                                    unsigned vis_blue_weight =
1689                                            calculate_mask_weight(visual_info->blue_mask);
1690                                    if ((vis_red_weight >= red_weight)
1691                                        && (vis_green_weight >= green_weight)
1692                                        && (vis_blue_weight >= blue_weight))
1693                                    {
1694                                            red_weight = vis_red_weight;
1695                                            green_weight = vis_green_weight;
1696                                            blue_weight = vis_blue_weight;
1697                                            g_visual = visual_info->visual;
1698                                            g_depth = visual_info->depth;
1699                                    }
1700                            }
1701                    }
1702                    XFree(vmatches);
1703            }
1704    
1705          if (g_server_bpp == 8)          if (g_visual != NULL)
1706          {          {
1707                  /* we use a colourmap, so any visual should do */                  g_owncolmap = False;
1708                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1709                    calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1710                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1711          }          }
1712          else          else
1713          {          {
1714                  /* need a truecolour visual */                  template.class = PseudoColor;
1715                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1716                  {                  template.colormap_size = 256;
1717                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1718                            XGetVisualInfo(g_display,
1719                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1720                                           &template, &visuals_count);
1721                    if (vmatches == NULL)
1722                    {
1723                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1724                            XCloseDisplay(g_display);
1725                            XFree(pfm);
1726                          return False;                          return False;
1727                  }                  }
1728    
1729                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1730                  g_owncolmap = False;                  g_owncolmap = True;
1731                  calculate_shifts(vi.red_mask,   &g_red_shift_r,   &g_red_shift_l);                  g_visual = vmatches[0].visual;
1732                  calculate_shifts(vi.blue_mask,  &g_blue_shift_r,  &g_blue_shift_l);                  g_depth = vmatches[0].depth;
                 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);  
1733          }          }
1734    
1735          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1736          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1737          {          {
1738                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1739                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1740                  {                  {
1741                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1742    
1743                            if (g_no_translate_image)
1744                          {                          {
1745                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1746                                    {
1747                                            case 15:
1748                                            case 16:
1749                                                    if (g_bpp != 16)
1750                                                            g_no_translate_image = False;
1751                                                    break;
1752                                            case 24:
1753                                                    /* Yes, this will force image translation
1754                                                       on most modern servers which use 32 bits
1755                                                       for R8G8B8. */
1756                                                    if (g_bpp != 24)
1757                                                            g_no_translate_image = False;
1758                                                    break;
1759                                            default:
1760                                                    g_no_translate_image = False;
1761                                                    break;
1762                                    }
1763                          }                          }
1764    
1765                            /* Pixmap formats list is a depth-to-bpp mapping --
1766                               there's just a single entry for every depth,
1767                               so we can safely break here */
1768                            break;
1769                  }                  }
1770                  XFree(pfm);          }
1771            XFree(pfm);
1772            pfm = NULL;
1773            return True;
1774    }
1775    
1776    static XErrorHandler g_old_error_handler;
1777    static RD_BOOL g_error_expected = False;
1778    
1779    /* Check if the X11 window corresponding to a seamless window with
1780       specified id exists. */
1781    RD_BOOL
1782    sw_window_exists(unsigned long id)
1783    {
1784            seamless_window *sw;
1785            char *name;
1786            Status sts = 0;
1787    
1788            sw = sw_get_window_by_id(id);
1789            if (!sw)
1790                    return False;
1791    
1792            g_error_expected = True;
1793            sts = XFetchName(g_display, sw->wnd, &name);
1794            g_error_expected = False;
1795            if (sts)
1796            {
1797                    XFree(name);
1798            }
1799    
1800            return sts;
1801    }
1802    
1803    static int
1804    error_handler(Display * dpy, XErrorEvent * eev)
1805    {
1806            if (g_error_expected)
1807                    return 0;
1808    
1809            return g_old_error_handler(dpy, eev);
1810    }
1811    
1812    RD_BOOL
1813    ui_init(void)
1814    {
1815            int screen_num;
1816    
1817            g_display = XOpenDisplay(NULL);
1818            if (g_display == NULL)
1819            {
1820                    error("Failed to open display: %s\n", XDisplayName(NULL));
1821                    return False;
1822          }          }
1823    
         if (g_bpp < 8)  
1824          {          {
1825                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1826                  XCloseDisplay(g_display);                  g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1827            }
1828    
1829            g_old_error_handler = XSetErrorHandler(error_handler);
1830            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1831            screen_num = DefaultScreen(g_display);
1832            g_x_socket = ConnectionNumber(g_display);
1833            g_screen = ScreenOfDisplay(g_display, screen_num);
1834            g_depth = DefaultDepthOfScreen(g_screen);
1835    
1836            if (!select_visual(screen_num))
1837                  return False;                  return False;
1838    
1839            if (g_no_translate_image)
1840            {
1841                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1842          }          }
1843    
1844            if (g_server_depth > g_bpp)
1845            {
1846                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1847                            g_server_depth, g_bpp);
1848            }
1849    
1850            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1851                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1852    
1853          if (!g_owncolmap)          if (!g_owncolmap)
1854          {          {
1855                  g_xcolmap = DefaultColormapOfScreen(g_screen);                  g_xcolmap =
1856                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1857                                            AllocNone);
1858                  if (g_depth <= 8)                  if (g_depth <= 8)
1859                          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);
1860          }          }
1861    
1862          g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1863            {
1864          if (DoesBackingStore(g_screen) != Always)                  warning("External BackingStore not available. Using internal.\n");
1865                  g_ownbackstore = True;                  g_ownbackstore = True;
1866            }
         test = 1;  
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
1867    
1868          /*          /*
1869           * Determine desktop size           * Determine desktop size
1870           */           */
1871          if (g_width < 0)          if (g_fullscreen)
1872            {
1873                    g_width = WidthOfScreen(g_screen);
1874                    g_height = HeightOfScreen(g_screen);
1875                    g_using_full_workarea = True;
1876            }
1877            else if (g_width < 0)
1878          {          {
1879                  /* Percent of screen */                  /* Percent of screen */
1880                    if (-g_width >= 100)
1881                            g_using_full_workarea = True;
1882                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1883                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1884          }          }
# Line 756  ui_init(void) Line 1886  ui_init(void)
1886          {          {
1887                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1888                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1889                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1890                  {                  {
1891                          g_width = cx;                          g_width = cx;
1892                          g_height = cy;                          g_height = cy;
1893                            g_using_full_workarea = True;
1894                  }                  }
1895                  else                  else
1896                  {                  {
1897                          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");
1898                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1899                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1900                  }                  }
1901          }          }
         else if (g_fullscreen)  
         {  
                 g_width = WidthOfScreen(g_screen);  
                 g_height = HeightOfScreen(g_screen);  
         }  
1902    
1903          /* make sure width is a multiple of 4 */          /* make sure width is a multiple of 4 */
1904          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1905    
         if (g_ownbackstore)  
         {  
                 g_backstore =  
                         XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,  
                                       g_depth);  
   
                 /* clear to prevent rubbish being exposed at startup */  
                 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));  
                 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);  
         }  
   
1906          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1907            xwin_refresh_pointer_map();
1908    
1909          xkeymap_init();          xkeymap_init();
1910    
# Line 797  ui_init(void) Line 1912  ui_init(void)
1912                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1913    
1914          xclip_init();          xclip_init();
1915            ewmh_init();
1916            if (g_seamless_rdp)
1917            {
1918                    seamless_restack_test();
1919                    seamless_init();
1920            }
1921    
1922          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));
1923    
1924          return True;          return True;
1925  }  }
# Line 806  ui_init(void) Line 1927  ui_init(void)
1927  void  void
1928  ui_deinit(void)  ui_deinit(void)
1929  {  {
1930            while (g_seamless_windows)
1931            {
1932                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1933                    sw_remove_window(g_seamless_windows);
1934            }
1935    
1936            xclip_deinit();
1937    
1938          if (g_IM != NULL)          if (g_IM != NULL)
1939                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1940    
1941            if (g_null_cursor != NULL)
1942                    ui_destroy_cursor(g_null_cursor);
1943    
1944          XFreeModifiermap(g_mod_map);          XFreeModifiermap(g_mod_map);
1945    
1946          if (g_ownbackstore)          if (g_ownbackstore)
# Line 819  ui_deinit(void) Line 1951  ui_deinit(void)
1951          g_display = NULL;          g_display = NULL;
1952  }  }
1953    
1954  #define NULL_POINTER_MASK       "\x80"  
1955  #define NULL_POINTER_DATA       "\x0\x0\x0"  static void
1956            get_window_attribs(XSetWindowAttributes * attribs)
1957  BOOL  {
1958            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1959            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1960            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1961            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1962            attribs->override_redirect = g_fullscreen;
1963            attribs->colormap = g_xcolmap;
1964    }
1965    
1966    static void
1967    get_input_mask(long *input_mask)
1968    {
1969            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1970                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1971    
1972            if (g_sendmotion)
1973                    *input_mask |= PointerMotionMask;
1974            if (g_ownbackstore)
1975                    *input_mask |= ExposureMask;
1976            if (g_fullscreen || g_grab_keyboard)
1977                    *input_mask |= EnterWindowMask;
1978            if (g_grab_keyboard)
1979                    *input_mask |= LeaveWindowMask;
1980    }
1981    
1982    RD_BOOL
1983  ui_create_window(void)  ui_create_window(void)
1984  {  {
1985            uint8 null_pointer_mask[1] = { 0x80 };
1986            uint8 null_pointer_data[24] = { 0x00 };
1987    
1988          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1989          XClassHint *classhints;          XClassHint *classhints;
1990          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 835  ui_create_window(void) Line 1995  ui_create_window(void)
1995          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1996          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1997    
1998          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1999          attribs.backing_store = g_ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
2000          attribs.override_redirect = g_fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
2001            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2002          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2003                                0, CopyFromParent, InputOutput, CopyFromParent,  
2004                                CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          get_window_attribs(&attribs);
2005    
2006            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
2007                                  wndheight, 0, g_depth, InputOutput, g_visual,
2008                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
2009                                  CWBorderPixel, &attribs);
2010    
2011            if (g_gc == NULL)
2012            {
2013                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2014                    ui_reset_clip();
2015            }
2016    
2017            if (g_create_bitmap_gc == NULL)
2018                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2019    
2020            if ((g_ownbackstore) && (g_backstore == 0))
2021            {
2022                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2023    
2024                    /* clear to prevent rubbish being exposed at startup */
2025                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
2026                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
2027            }
2028    
2029          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
2030            ewmh_set_wm_name(g_wnd, g_title);
2031    
2032          if (g_hide_decorations)          if (g_hide_decorations)
2033                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2034    
2035          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2036          if (classhints != NULL)          if (classhints != NULL)
# Line 860  ui_create_window(void) Line 2044  ui_create_window(void)
2044          if (sizehints)          if (sizehints)
2045          {          {
2046                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
2047                    if (g_pos)
2048                            sizehints->flags |= PPosition;
2049                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
2050                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
2051                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
2052                  XFree(sizehints);                  XFree(sizehints);
2053          }          }
2054    
2055          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          if (g_embed_wnd)
2056                  VisibilityChangeMask | FocusChangeMask;          {
2057                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2058            }
2059    
2060          if (g_sendmotion)          get_input_mask(&input_mask);
                 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;  
2061    
2062          if (g_IM != NULL)          if (g_IM != NULL)
2063          {          {
# Line 897  ui_create_window(void) Line 2078  ui_create_window(void)
2078                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
2079          }          }
2080          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
2081            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
2082    
2083          g_focused = False;          g_focused = False;
2084          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 907  ui_create_window(void) Line 2089  ui_create_window(void)
2089          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
2090    
2091          /* create invisible 1x1 cursor to be used as null cursor */          /* create invisible 1x1 cursor to be used as null cursor */
2092          g_null_cursor = ui_create_cursor(0, 0, 1, 1, NULL_POINTER_MASK, NULL_POINTER_DATA);          if (g_null_cursor == NULL)
2093                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
2094    
2095          return True;          return True;
2096  }  }
2097    
2098  void  void
2099    ui_resize_window()
2100    {
2101            XSizeHints *sizehints;
2102            Pixmap bs;
2103    
2104            sizehints = XAllocSizeHints();
2105            if (sizehints)
2106            {
2107                    sizehints->flags = PMinSize | PMaxSize;
2108                    sizehints->min_width = sizehints->max_width = g_width;
2109                    sizehints->min_height = sizehints->max_height = g_height;
2110                    XSetWMNormalHints(g_display, g_wnd, sizehints);
2111                    XFree(sizehints);
2112            }
2113    
2114            if (!(g_fullscreen || g_embed_wnd))
2115            {
2116                    XResizeWindow(g_display, g_wnd, g_width, g_height);
2117            }
2118    
2119            /* create new backstore pixmap */
2120            if (g_backstore != 0)
2121            {
2122                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2123                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
2124                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
2125                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
2126                    XFreePixmap(g_display, g_backstore);
2127                    g_backstore = bs;
2128            }
2129    }
2130    
2131    void
2132  ui_destroy_window(void)  ui_destroy_window(void)
2133  {  {
         ui_destroy_cursor(g_null_cursor);  
           
2134          if (g_IC != NULL)          if (g_IC != NULL)
2135                  XDestroyIC(g_IC);                  XDestroyIC(g_IC);
2136    
# Line 928  xwin_toggle_fullscreen(void) Line 2142  xwin_toggle_fullscreen(void)
2142  {  {
2143          Pixmap contents = 0;          Pixmap contents = 0;
2144    
2145            if (g_seamless_active)
2146                    /* Turn off SeamlessRDP mode */
2147                    ui_seamless_toggle();
2148    
2149          if (!g_ownbackstore)          if (!g_ownbackstore)
2150          {          {
2151                  /* need to save contents of window */                  /* need to save contents of window */
# Line 948  xwin_toggle_fullscreen(void) Line 2166  xwin_toggle_fullscreen(void)
2166          }          }
2167  }  }
2168    
2169  /* Process all events in Xlib queue  static void
2170    handle_button_event(XEvent xevent, RD_BOOL down)
2171    {
2172            uint16 button, flags = 0;
2173            g_last_gesturetime = xevent.xbutton.time;
2174            /* Reverse the pointer button mapping, e.g. in the case of
2175               "left-handed mouse mode"; the RDP session expects to
2176               receive physical buttons (true in mstsc as well) and
2177               logical button behavior depends on the remote desktop's own
2178               mouse settings */
2179            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
2180            button = xkeymap_translate_button(xevent.xbutton.button);
2181            if (button == 0)
2182                    return;
2183    
2184            if (down)
2185                    flags = MOUSE_FLAG_DOWN;
2186    
2187            /* Stop moving window when button is released, regardless of cursor position */
2188            if (g_moving_wnd && (xevent.type == ButtonRelease))
2189                    g_moving_wnd = False;
2190    
2191            /* If win_button_size is nonzero, enable single app mode */
2192            if (xevent.xbutton.y < g_win_button_size)
2193            {
2194                    /*  Check from right to left: */
2195                    if (xevent.xbutton.x >= g_width - g_win_button_size)
2196                    {
2197                            /* The close button, continue */
2198                            ;
2199                    }
2200                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
2201                    {
2202                            /* The maximize/restore button. Do not send to
2203                               server.  It might be a good idea to change the
2204                               cursor or give some other visible indication
2205                               that rdesktop inhibited this click */
2206                            if (xevent.type == ButtonPress)
2207                                    return;
2208                    }
2209                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
2210                    {
2211                            /* The minimize button. Iconify window. */
2212                            if (xevent.type == ButtonRelease)
2213                            {
2214                                    /* Release the mouse button outside the minimize button, to prevent the
2215                                       actual minimazation to happen */
2216                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
2217                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
2218                                    return;
2219                            }
2220                    }
2221                    else if (xevent.xbutton.x <= g_win_button_size)
2222                    {
2223                            /* The system menu. Ignore. */
2224                            if (xevent.type == ButtonPress)
2225                                    return;
2226                    }
2227                    else
2228                    {
2229                            /* The title bar. */
2230                            if (xevent.type == ButtonPress)
2231                            {
2232                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
2233                                    {
2234                                            g_moving_wnd = True;
2235                                            g_move_x_offset = xevent.xbutton.x;
2236                                            g_move_y_offset = xevent.xbutton.y;
2237                                    }
2238                                    return;
2239                            }
2240                    }
2241            }
2242    
2243            if (xevent.xmotion.window == g_wnd)
2244            {
2245                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2246                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
2247            }
2248            else
2249            {
2250                    /* SeamlessRDP */
2251                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2252                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
2253            }
2254    }
2255    
2256    
2257    /* Process events in Xlib queue
2258     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
2259  static int  static int
2260  xwin_process_events(void)  xwin_process_events(void)
2261  {  {
2262          XEvent xevent;          XEvent xevent;
2263          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
2264          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
2265          char str[256];          char str[256];
2266          Status status;          Status status;
2267          unsigned int state;          int events = 0;
2268          Window wdummy;          seamless_window *sw;
         int dummy;  
2269    
2270          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
2271          {          {
2272                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
2273    
# Line 974  xwin_process_events(void) Line 2277  xwin_process_events(void)
2277                          continue;                          continue;
2278                  }                  }
2279    
                 flags = 0;  
   
2280                  switch (xevent.type)                  switch (xevent.type)
2281                  {                  {
2282                            case VisibilityNotify:
2283                                    if (xevent.xvisibility.window == g_wnd)
2284                                            g_Unobscured =
2285                                                    xevent.xvisibility.state == VisibilityUnobscured;
2286    
2287                                    break;
2288                          case ClientMessage:                          case ClientMessage:
2289                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2290                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2291                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2292                                          /* Quit */                                  {
2293                                          return 0;                                          /* When killing a seamless window, close the window on the
2294                                               serverside instead of terminating rdesktop */
2295                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2296                                            if (!sw)
2297                                                    /* Otherwise, quit */
2298                                                    return 0;
2299                                            /* send seamless destroy process message */
2300                                            seamless_send_destroy(sw->id);
2301                                    }
2302                                  break;                                  break;
2303    
2304                          case KeyPress:                          case KeyPress:
# Line 1009  xwin_process_events(void) Line 2324  xwin_process_events(void)
2324                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2325                                  }                                  }
2326    
2327                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2328                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2329    
2330                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2331                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2332                                          break;                                          break;
2333    
2334                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2335                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
2336                                  break;                                  break;
2337    
2338                          case KeyRelease:                          case KeyRelease:
# Line 1034  xwin_process_events(void) Line 2340  xwin_process_events(void)
2340                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2341                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2342    
2343                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2344                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2345    
2346                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2347                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2348                                          break;                                          break;
2349    
2350                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2351                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2352                                  break;                                  break;
2353    
2354                          case ButtonPress:                          case ButtonPress:
2355                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2356                                  /* fall through */                                  break;
2357    
2358                          case ButtonRelease:                          case ButtonRelease:
2359                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
2360                                  break;                                  break;
2361    
2362                          case MotionNotify:                          case MotionNotify:
# Line 1127  xwin_process_events(void) Line 2371  xwin_process_events(void)
2371                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2372                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2373                                                         CurrentTime);                                                         CurrentTime);
2374                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2375                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2376                                    {
2377                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2378                                                           xevent.xmotion.x, xevent.xmotion.y);
2379                                    }
2380                                    else
2381                                    {
2382                                            /* SeamlessRDP */
2383                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2384                                                           xevent.xmotion.x_root,
2385                                                           xevent.xmotion.y_root);
2386                                    }
2387                                  break;                                  break;
2388    
2389                          case FocusIn:                          case FocusIn:
2390                                  if (xevent.xfocus.mode == NotifyGrab)                                  if (xevent.xfocus.mode == NotifyGrab)
2391                                          break;                                          break;
2392                                  g_focused = True;                                  g_focused = True;
2393                                  XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,                                  reset_modifier_keys();
                                               &dummy, &dummy, &state);  
                                 reset_modifier_keys(state);  
2394                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2395                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2396                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2397    
2398                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2399                                    if (!sw)
2400                                            break;
2401    
2402                                    /* Menu windows are real X11 windows,
2403                                       with focus. When such a window is
2404                                       destroyed, focus is reverted to the
2405                                       main application window, which
2406                                       would cause us to send FOCUS. This
2407                                       breaks window switching in, say,
2408                                       Seamonkey. We shouldn't need to
2409                                       send FOCUS: Windows should also
2410                                       revert focus to some other window
2411                                       when the menu window is
2412                                       destroyed. So, we only send FOCUS
2413                                       if the previous focus window still
2414                                       exists. */
2415                                    if (sw->id != g_seamless_focused)
2416                                    {
2417    
2418                                            if (sw_window_exists(g_seamless_focused))
2419                                                    seamless_send_focus(sw->id, 0);
2420                                            g_seamless_focused = sw->id;
2421                                    }
2422                                  break;                                  break;
2423    
2424                          case FocusOut:                          case FocusOut:
# Line 1173  xwin_process_events(void) Line 2451  xwin_process_events(void)
2451                                  break;                                  break;
2452    
2453                          case Expose:                          case Expose:
2454                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2455                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2456                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2457                                            xevent.xexpose.height,                                                    g_gc,
2458                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2459                                                      xevent.xexpose.width, xevent.xexpose.height,
2460                                                      xevent.xexpose.x, xevent.xexpose.y);
2461                                    }
2462                                    else
2463                                    {
2464                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2465                                            if (!sw)
2466                                                    break;
2467                                            XCopyArea(g_display, g_backstore,
2468                                                      xevent.xexpose.window, g_gc,
2469                                                      xevent.xexpose.x + sw->xoffset,
2470                                                      xevent.xexpose.y + sw->yoffset,
2471                                                      xevent.xexpose.width,
2472                                                      xevent.xexpose.height, xevent.xexpose.x,
2473                                                      xevent.xexpose.y);
2474                                    }
2475    
2476                                  break;                                  break;
2477    
2478                          case MappingNotify:                          case MappingNotify:
# Line 1192  xwin_process_events(void) Line 2487  xwin_process_events(void)
2487                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2488                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2489                                  }                                  }
2490    
2491                                    if (xevent.xmapping.request == MappingPointer)
2492                                    {
2493                                            xwin_refresh_pointer_map();
2494                                    }
2495    
2496                                  break;                                  break;
2497    
2498                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1206  xwin_process_events(void) Line 2507  xwin_process_events(void)
2507                                  break;                                  break;
2508                          case PropertyNotify:                          case PropertyNotify:
2509                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2510                                    if (xevent.xproperty.window == g_wnd)
2511                                            break;
2512                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2513                                            break;
2514    
2515                                    /* seamless */
2516                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2517                                    if (!sw)
2518                                            break;
2519    
2520                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2521                                        && (xevent.xproperty.state == PropertyNewValue))
2522                                    {
2523                                            sw->state = ewmh_get_window_state(sw->wnd);
2524                                            seamless_send_state(sw->id, sw->state, 0);
2525                                    }
2526    
2527                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2528                                        && (xevent.xproperty.state == PropertyNewValue))
2529                                    {
2530                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2531                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2532                                    }
2533    
2534                                    break;
2535                            case MapNotify:
2536                                    if (!g_seamless_active)
2537                                            rdp_send_client_window_status(1);
2538                                    break;
2539                            case UnmapNotify:
2540                                    if (!g_seamless_active)
2541                                            rdp_send_client_window_status(0);
2542                                    break;
2543                            case ConfigureNotify:
2544                                    if (!g_seamless_active)
2545                                            break;
2546    
2547                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2548                                    if (!sw)
2549                                            break;
2550    
2551                                    gettimeofday(sw->position_timer, NULL);
2552                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2553                                        1000000)
2554                                    {
2555                                            sw->position_timer->tv_usec +=
2556                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2557                                            sw->position_timer->tv_sec += 1;
2558                                    }
2559                                    else
2560                                    {
2561                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2562                                    }
2563    
2564                                    sw_handle_restack(sw);
2565                                  break;                                  break;
2566                  }                  }
2567          }          }
# Line 1217  xwin_process_events(void) Line 2573  xwin_process_events(void)
2573  int  int
2574  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2575  {  {
2576          int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;          int n;
2577          fd_set rfds, wfds;          fd_set rfds, wfds;
2578            struct timeval tv;
2579            RD_BOOL s_timeout = False;
2580    
2581          while (True)          while (True)
2582          {          {
2583                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2584                  /* Process any events already waiting */                  /* Process any events already waiting */
2585                  if (!xwin_process_events())                  if (!xwin_process_events())
2586                          /* User quit */                          /* User quit */
2587                          return 0;                          return 0;
2588    
2589                    if (g_seamless_active)
2590                            sw_check_timers();
2591    
2592                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2593                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2594                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2595                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2596    
2597                    /* default timeout */
2598                    tv.tv_sec = 60;
2599                    tv.tv_usec = 0;
2600    
2601  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
2602                  /* FIXME: there should be an API for registering fds */                  rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;  
                 }  
2603  #endif  #endif
2604    
2605                  switch (select(n, &rfds, &wfds, NULL, NULL))                  /* add redirection handles */
2606                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2607                    seamless_select_timeout(&tv);
2608    
2609                    n++;
2610    
2611                    switch (select(n, &rfds, &wfds, NULL, &tv))
2612                  {                  {
2613                          case -1:                          case -1:
2614                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2615    
2616                          case 0:                          case 0:
2617    #ifdef WITH_RDPSND
2618                                    rdpsnd_check_fds(&rfds, &wfds);
2619    #endif
2620    
2621                                    /* Abort serial read calls */
2622                                    if (s_timeout)
2623                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2624                                  continue;                                  continue;
2625                  }                  }
2626    
2627    #ifdef WITH_RDPSND
2628                    rdpsnd_check_fds(&rfds, &wfds);
2629    #endif
2630    
2631                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2632    
2633                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2634                          return 1;                          return 1;
2635    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2636          }          }
2637  }  }
2638    
# Line 1266  ui_move_pointer(int x, int y) Line 2642  ui_move_pointer(int x, int y)
2642          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);
2643  }  }
2644    
2645  HBITMAP  RD_HBITMAP
2646  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2647  {  {
2648          XImage *image;          XImage *image;
# Line 1274  ui_create_bitmap(int width, int height, Line 2650  ui_create_bitmap(int width, int height,
2650          uint8 *tdata;          uint8 *tdata;
2651          int bitmap_pad;          int bitmap_pad;
2652    
2653          if (g_server_bpp == 8)          if (g_server_depth == 8)
2654          {          {
2655                  bitmap_pad = 8;                  bitmap_pad = 8;
2656          }          }
# Line 1291  ui_create_bitmap(int width, int height, Line 2667  ui_create_bitmap(int width, int height,
2667          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2668                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2669    
2670          XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2671    
2672          XFree(image);          XFree(image);
2673          if (!g_owncolmap)          if (tdata != data)
2674                  xfree(tdata);                  xfree(tdata);
2675          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2676  }  }
2677    
2678  void  void
# Line 1306  ui_paint_bitmap(int x, int y, int cx, in Line 2682  ui_paint_bitmap(int x, int y, int cx, in
2682          uint8 *tdata;          uint8 *tdata;
2683          int bitmap_pad;          int bitmap_pad;
2684    
2685          if (g_server_bpp == 8)          if (g_server_depth == 8)
2686          {          {
2687                  bitmap_pad = 8;                  bitmap_pad = 8;
2688          }          }
# Line 1326  ui_paint_bitmap(int x, int y, int cx, in Line 2702  ui_paint_bitmap(int x, int y, int cx, in
2702          {          {
2703                  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);
2704                  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);
2705                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2706                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2707                                             x - sw->xoffset, y - sw->yoffset));
2708          }          }
2709          else          else
2710          {          {
2711                  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);
2712                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2713                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2714                                             x - sw->xoffset, y - sw->yoffset));
2715          }          }
2716    
2717          XFree(image);          XFree(image);
2718          if (!g_owncolmap)          if (tdata != data)
2719                  xfree(tdata);                  xfree(tdata);
2720  }  }
2721    
2722  void  void
2723  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2724  {  {
2725          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2726  }  }
2727    
2728  HGLYPH  RD_HGLYPH
2729  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2730  {  {
2731          XImage *image;          XImage *image;
2732          Pixmap bitmap;          Pixmap bitmap;
2733          int scanline;          int scanline;
         GC gc;  
2734    
2735          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2736    
2737          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2738          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2739                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2740    
2741          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2742                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1362  ui_create_glyph(int width, int height, u Line 2744  ui_create_glyph(int width, int height, u
2744          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2745          XInitImage(image);          XInitImage(image);
2746    
2747          XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2748    
2749          XFree(image);          XFree(image);
2750          XFreeGC(g_display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH) bitmap;  
2751  }  }
2752    
2753  void  void
2754  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2755  {  {
2756          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2757  }  }
2758    
2759  HCURSOR  RD_HCURSOR
2760  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,
2761                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2762  {  {
2763          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2764          XColor bg, fg;          XColor bg, fg;
2765          Cursor xcursor;          Cursor xcursor;
2766          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1443  ui_create_cursor(unsigned int x, unsigne Line 2824  ui_create_cursor(unsigned int x, unsigne
2824          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2825          xfree(mask);          xfree(mask);
2826          xfree(cursor);          xfree(cursor);
2827          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2828  }  }
2829    
2830  void  void
2831  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2832  {  {
2833          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2834          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2835            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2836  }  }
2837    
2838  void  void
2839  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2840  {  {
2841          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2842  }  }
# Line 1472  ui_set_null_cursor(void) Line 2854  ui_set_null_cursor(void)
2854                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2855    
2856    
2857  HCOLOURMAP  RD_HCOLOURMAP
2858  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2859  {  {
2860          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1568  ui_create_colourmap(COLOURMAP * colours) Line 2950  ui_create_colourmap(COLOURMAP * colours)
2950                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2951    
2952                  xfree(xcolours);                  xfree(xcolours);
2953                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2954          }          }
2955  }  }
2956    
2957  void  void
2958  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2959  {  {
2960          if (!g_owncolmap)          if (!g_owncolmap)
2961                  xfree(map);                  xfree(map);
# Line 1582  ui_destroy_colourmap(HCOLOURMAP map) Line 2964  ui_destroy_colourmap(HCOLOURMAP map)
2964  }  }
2965    
2966  void  void
2967  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2968  {  {
2969          if (!g_owncolmap)          if (!g_owncolmap)
2970          {          {
# Line 1592  ui_set_colourmap(HCOLOURMAP map) Line 2974  ui_set_colourmap(HCOLOURMAP map)
2974                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2975          }          }
2976          else          else
2977            {
2978                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2979                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2980            }
2981  }  }
2982    
2983  void  void
2984  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2985  {  {
2986          XRectangle rect;          g_clip_rectangle.x = x;
2987            g_clip_rectangle.y = y;
2988          rect.x = x;          g_clip_rectangle.width = cx;
2989          rect.y = y;          g_clip_rectangle.height = cy;
2990          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);  
2991  }  }
2992    
2993  void  void
2994  ui_reset_clip(void)  ui_reset_clip(void)
2995  {  {
2996          XRectangle rect;          g_clip_rectangle.x = 0;
2997            g_clip_rectangle.y = 0;
2998          rect.x = 0;          g_clip_rectangle.width = g_width;
2999          rect.y = 0;          g_clip_rectangle.height = g_height;
3000          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);  
3001  }  }
3002    
3003  void  void
# Line 1657  ui_patblt(uint8 opcode, Line 3038  ui_patblt(uint8 opcode,
3038          {          {
3039                  case 0: /* Solid */                  case 0: /* Solid */
3040                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
3041                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3042                          break;                          break;
3043    
3044                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1668  ui_patblt(uint8 opcode, Line 3049  ui_patblt(uint8 opcode,
3049                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3050                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
3051                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3052                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3053                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3054                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3055                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3056                          break;                          break;
3057    
3058                  case 3: /* Pattern */                  case 3: /* Pattern */
3059                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
3060                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
3061                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
3062                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
3063                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
3064                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3065                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
3066                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3067                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
3068                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3069                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3070                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3071                          break;                          break;
3072    
3073                  default:                  default:
# Line 1697  ui_patblt(uint8 opcode, Line 3075  ui_patblt(uint8 opcode,
3075          }          }
3076    
3077          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3078    
3079            if (g_ownbackstore)
3080                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3081            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3082                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3083                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3084  }  }
3085    
3086  void  void
# Line 1705  ui_screenblt(uint8 opcode, Line 3089  ui_screenblt(uint8 opcode,
3089               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
3090  {  {
3091          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
         XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
3092          if (g_ownbackstore)          if (g_ownbackstore)
3093            {
3094                    XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3095                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3096                  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);
3097            }
3098            else
3099            {
3100                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3101            }
3102    
3103            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3104                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3105                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3106    
3107          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3108  }  }
3109    
3110  void  void
3111  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3112            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3113            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3114  {  {
3115          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3116          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);
3117            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3118                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3119                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3120          if (g_ownbackstore)          if (g_ownbackstore)
3121                  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);
3122          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1726  ui_memblt(uint8 opcode, Line 3125  ui_memblt(uint8 opcode,
3125  void  void
3126  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3127            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3128            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3129            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3130  {  {
3131          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1764  ui_line(uint8 opcode, Line 3163  ui_line(uint8 opcode,
3163          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3164          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3165          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3166            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3167                                                startx - sw->xoffset, starty - sw->yoffset,
3168                                                endx - sw->xoffset, endy - sw->yoffset));
3169          if (g_ownbackstore)          if (g_ownbackstore)
3170                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3171          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1778  ui_rect( Line 3180  ui_rect(
3180          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
3181  }  }
3182    
3183    void
3184    ui_polygon(uint8 opcode,
3185               /* mode */ uint8 fillmode,
3186               /* dest */ RD_POINT * point, int npoints,
3187               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3188    {
3189            uint8 style, i, ipattern[8];
3190            Pixmap fill;
3191    
3192            SET_FUNCTION(opcode);
3193    
3194            switch (fillmode)
3195            {
3196                    case ALTERNATE:
3197                            XSetFillRule(g_display, g_gc, EvenOddRule);
3198                            break;
3199                    case WINDING:
3200                            XSetFillRule(g_display, g_gc, WindingRule);
3201                            break;
3202                    default:
3203                            unimpl("fill mode %d\n", fillmode);
3204            }
3205    
3206            if (brush)
3207                    style = brush->style;
3208            else
3209                    style = 0;
3210    
3211            switch (style)
3212            {
3213                    case 0: /* Solid */
3214                            SET_FOREGROUND(fgcolour);
3215                            FILL_POLYGON((XPoint *) point, npoints);
3216                            break;
3217    
3218                    case 2: /* Hatch */
3219                            fill = (Pixmap) ui_create_glyph(8, 8,
3220                                                            hatch_patterns + brush->pattern[0] * 8);
3221                            SET_FOREGROUND(fgcolour);
3222                            SET_BACKGROUND(bgcolour);
3223                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3224                            XSetStipple(g_display, g_gc, fill);
3225                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3226                            FILL_POLYGON((XPoint *) point, npoints);
3227                            XSetFillStyle(g_display, g_gc, FillSolid);
3228                            XSetTSOrigin(g_display, g_gc, 0, 0);
3229                            ui_destroy_glyph((RD_HGLYPH) fill);
3230                            break;
3231    
3232                    case 3: /* Pattern */
3233                            for (i = 0; i != 8; i++)
3234                                    ipattern[7 - i] = brush->pattern[i];
3235                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3236                            SET_FOREGROUND(bgcolour);
3237                            SET_BACKGROUND(fgcolour);
3238                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3239                            XSetStipple(g_display, g_gc, fill);
3240                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3241                            FILL_POLYGON((XPoint *) point, npoints);
3242                            XSetFillStyle(g_display, g_gc, FillSolid);
3243                            XSetTSOrigin(g_display, g_gc, 0, 0);
3244                            ui_destroy_glyph((RD_HGLYPH) fill);
3245                            break;
3246    
3247                    default:
3248                            unimpl("brush %d\n", brush->style);
3249            }
3250    
3251            RESET_FUNCTION(opcode);
3252    }
3253    
3254    void
3255    ui_polyline(uint8 opcode,
3256                /* dest */ RD_POINT * points, int npoints,
3257                /* pen */ PEN * pen)
3258    {
3259            /* TODO: set join style */
3260            SET_FUNCTION(opcode);
3261            SET_FOREGROUND(pen->colour);
3262            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
3263            if (g_ownbackstore)
3264                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3265                               CoordModePrevious);
3266    
3267            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3268                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3269    
3270            RESET_FUNCTION(opcode);
3271    }
3272    
3273    void
3274    ui_ellipse(uint8 opcode,
3275               /* mode */ uint8 fillmode,
3276               /* dest */ int x, int y, int cx, int cy,
3277               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3278    {
3279            uint8 style, i, ipattern[8];
3280            Pixmap fill;
3281    
3282            SET_FUNCTION(opcode);
3283    
3284            if (brush)
3285                    style = brush->style;
3286            else
3287                    style = 0;
3288    
3289            switch (style)
3290            {
3291                    case 0: /* Solid */
3292                            SET_FOREGROUND(fgcolour);
3293                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3294                            break;
3295    
3296                    case 2: /* Hatch */
3297                            fill = (Pixmap) ui_create_glyph(8, 8,
3298                                                            hatch_patterns + brush->pattern[0] * 8);
3299                            SET_FOREGROUND(fgcolour);
3300                            SET_BACKGROUND(bgcolour);
3301                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3302                            XSetStipple(g_display, g_gc, fill);
3303                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3304                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3305                            XSetFillStyle(g_display, g_gc, FillSolid);
3306                            XSetTSOrigin(g_display, g_gc, 0, 0);
3307                            ui_destroy_glyph((RD_HGLYPH) fill);
3308                            break;
3309    
3310                    case 3: /* Pattern */
3311                            for (i = 0; i != 8; i++)
3312                                    ipattern[7 - i] = brush->pattern[i];
3313                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3314                            SET_FOREGROUND(bgcolour);
3315                            SET_BACKGROUND(fgcolour);
3316                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3317                            XSetStipple(g_display, g_gc, fill);
3318                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3319                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3320                            XSetFillStyle(g_display, g_gc, FillSolid);
3321                            XSetTSOrigin(g_display, g_gc, 0, 0);
3322                            ui_destroy_glyph((RD_HGLYPH) fill);
3323                            break;
3324    
3325                    default:
3326                            unimpl("brush %d\n", brush->style);
3327            }
3328    
3329            RESET_FUNCTION(opcode);
3330    }
3331    
3332  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3333  void  void
3334  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3335                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3336                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3337                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3338  {  {
3339          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1802  ui_draw_glyph(int mixmode, Line 3353  ui_draw_glyph(int mixmode,
3353  {\  {\
3354    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3355    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3356      {\
3357        xyoffset = ttext[++idx];\
3358        if ((xyoffset & 0x80))\
3359      {\      {\
3360        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3361        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[idx+1] | (ttext[idx+2] << 8);\  
           else\  
             x += ttext[idx+1] | (ttext[idx+2] << 8);\  
           idx += 2;\  
         }\  
3362        else\        else\
3363          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3364            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3365      }\      }\
3366    if (glyph != NULL)\      else\
3367      {\      {\
3368        ui_draw_glyph (mixmode, x + glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3369                       y + glyph->baseline,\          y += xyoffset;\
3370                       glyph->width, glyph->height,\        else\
3371                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3372      }\      }\
3373      }\
3374      if (glyph != NULL)\
3375      {\
3376        x1 = x + glyph->offset;\
3377        y1 = y + glyph->baseline;\
3378        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3379        XSetTSOrigin(g_display, g_gc, x1, y1);\
3380        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3381        if (flags & TEXT2_IMPLICIT_X)\
3382          x += glyph->width;\
3383      }\
3384  }  }
3385    
3386  void  void
3387  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
3388               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3389               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3390               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3391  {  {
3392            /* TODO: use brush appropriately */
3393    
3394          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3395          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3396          DATABLOB *entry;          DATABLOB *entry;
3397    
3398          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3399    
3400            /* Sometimes, the boxcx value is something really large, like
3401               32691. This makes XCopyArea fail with Xvnc. The code below
3402               is a quick fix. */
3403            if (boxx + boxcx > g_width)
3404                    boxcx = g_width - boxx;
3405    
3406          if (boxcx > 1)          if (boxcx > 1)
3407          {          {
3408                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
# Line 1852  ui_draw_text(uint8 font, uint8 flags, in Line 3412  ui_draw_text(uint8 font, uint8 flags, in
3412                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3413          }          }
3414    
3415            SET_FOREGROUND(fgcolour);
3416            SET_BACKGROUND(bgcolour);
3417            XSetFillStyle(g_display, g_gc, FillStippled);
3418    
3419          /* Paint text, character by character */          /* Paint text, character by character */
3420          for (i = 0; i < length;)          for (i = 0; i < length;)
3421          {          {
3422                  switch (text[i])                  switch (text[i])
3423                  {                  {
3424                          case 0xff:                          case 0xff:
3425                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3426                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3427                                  {                                  {
3428                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3429                                          exit(1);                                          for (j = 0; j < length; j++)
3430                                                    fprintf(stderr, "%02x ", text[j]);
3431                                            fprintf(stderr, "\n");
3432                                            i = length = 0;
3433                                            break;
3434                                  }                                  }
3435                                    cache_put_text(text[i + 1], text, text[i + 2]);
3436                                    i += 3;
3437                                    length -= i;
3438                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3439                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3440                                  i = 0;                                  i = 0;
3441                                  break;                                  break;
3442    
3443                          case 0xfe:                          case 0xfe:
3444                                    /* At least one byte needs to follow */
3445                                    if (i + 2 > length)
3446                                    {
3447                                            warning("Skipping short 0xfe command:");
3448                                            for (j = 0; j < length; j++)
3449                                                    fprintf(stderr, "%02x ", text[j]);
3450                                            fprintf(stderr, "\n");
3451                                            i = length = 0;
3452                                            break;
3453                                    }
3454                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3455                                  if (entry != NULL)                                  if (entry->data != NULL)
3456                                  {                                  {
3457                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3458                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3459                                          {                                          {
3460                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3461                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 1902  ui_draw_text(uint8 font, uint8 flags, in Line 3481  ui_draw_text(uint8 font, uint8 flags, in
3481                                  break;                                  break;
3482                  }                  }
3483          }          }
3484    
3485            XSetFillStyle(g_display, g_gc, FillSolid);
3486    
3487          if (g_ownbackstore)          if (g_ownbackstore)
3488          {          {
3489                  if (boxcx > 1)                  if (boxcx > 1)
3490                    {
3491                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3492                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3493                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3494                                                    (g_display, g_backstore, sw->wnd, g_gc,
3495                                                     boxx, boxy,
3496                                                     boxcx, boxcy,
3497                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3498                    }
3499                  else                  else
3500                    {
3501                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3502                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3503                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3504                                                    (g_display, g_backstore, sw->wnd, g_gc,
3505                                                     clipx, clipy,
3506                                                     clipcx, clipcy, clipx - sw->xoffset,
3507                                                     clipy - sw->yoffset));
3508                    }
3509          }          }
3510  }  }
3511    
# Line 1922  ui_desktop_save(uint32 offset, int x, in Line 3518  ui_desktop_save(uint32 offset, int x, in
3518          if (g_ownbackstore)          if (g_ownbackstore)
3519          {          {
3520                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3521                    exit_if_null(image);
3522          }          }
3523          else          else
3524          {          {
3525                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3526                  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);
3527                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3528                    exit_if_null(image);
3529                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3530          }          }
3531    
# Line 1949  ui_desktop_restore(uint32 offset, int x, Line 3547  ui_desktop_restore(uint32 offset, int x,
3547                  return;                  return;
3548    
3549          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3550                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3551    
3552          if (g_ownbackstore)          if (g_ownbackstore)
3553          {          {
3554                  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);
3555                  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);
3556                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3557                                            (g_display, g_backstore, sw->wnd, g_gc,
3558                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3559          }          }
3560          else          else
3561          {          {
3562                  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);
3563                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3564                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3565                                             x - sw->xoffset, y - sw->yoffset));
3566          }          }
3567    
3568          XFree(image);          XFree(image);
3569  }  }
3570    
3571    /* these do nothing here but are used in uiports */
3572    void
3573    ui_begin_update(void)
3574    {
3575    }
3576    
3577    void
3578    ui_end_update(void)
3579    {
3580    }
3581    
3582    
3583    void
3584    ui_seamless_begin(RD_BOOL hidden)
3585    {
3586            if (!g_seamless_rdp)
3587                    return;
3588    
3589            if (g_seamless_started)
3590                    return;
3591    
3592            g_seamless_started = True;
3593            g_seamless_hidden = hidden;
3594    
3595            if (!hidden)
3596                    ui_seamless_toggle();
3597    }
3598    
3599    
3600    void
3601    ui_seamless_hide_desktop()
3602    {
3603            if (!g_seamless_rdp)
3604                    return;
3605    
3606            if (!g_seamless_started)
3607                    return;
3608    
3609            if (g_seamless_active)
3610                    ui_seamless_toggle();
3611    
3612            g_seamless_hidden = True;
3613    }
3614    
3615    
3616    void
3617    ui_seamless_unhide_desktop()
3618    {
3619            if (!g_seamless_rdp)
3620                    return;
3621    
3622            if (!g_seamless_started)
3623                    return;
3624    
3625            g_seamless_hidden = False;
3626    
3627            ui_seamless_toggle();
3628    }
3629    
3630    
3631    void
3632    ui_seamless_toggle()
3633    {
3634            if (!g_seamless_rdp)
3635                    return;
3636    
3637            if (!g_seamless_started)
3638                    return;
3639    
3640            if (g_seamless_hidden)
3641                    return;
3642    
3643            if (g_seamless_active)
3644            {
3645                    /* Deactivate */
3646                    while (g_seamless_windows)
3647                    {
3648                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3649                            sw_remove_window(g_seamless_windows);
3650                    }
3651                    XMapWindow(g_display, g_wnd);
3652            }
3653            else
3654            {
3655                    /* Activate */
3656                    XUnmapWindow(g_display, g_wnd);
3657                    seamless_send_sync();
3658            }
3659    
3660            g_seamless_active = !g_seamless_active;
3661    }
3662    
3663    
3664    void
3665    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3666                              unsigned long flags)
3667    {
3668            Window wnd;
3669            XSetWindowAttributes attribs;
3670            XClassHint *classhints;
3671            XSizeHints *sizehints;
3672            XWMHints *wmhints;
3673            long input_mask;
3674            seamless_window *sw, *sw_parent;
3675    
3676            if (!g_seamless_active)
3677                    return;
3678    
3679            /* Ignore CREATEs for existing windows */
3680            sw = sw_get_window_by_id(id);
3681            if (sw)
3682                    return;
3683    
3684            get_window_attribs(&attribs);
3685            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3686                                InputOutput, g_visual,
3687                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3688    
3689            XStoreName(g_display, wnd, "SeamlessRDP");
3690            ewmh_set_wm_name(wnd, "SeamlessRDP");
3691    
3692            mwm_hide_decorations(wnd);
3693    
3694            classhints = XAllocClassHint();
3695            if (classhints != NULL)
3696            {
3697                    classhints->res_name = "rdesktop";
3698                    classhints->res_class = "SeamlessRDP";
3699                    XSetClassHint(g_display, wnd, classhints);
3700                    XFree(classhints);
3701            }
3702    
3703            /* WM_NORMAL_HINTS */
3704            sizehints = XAllocSizeHints();
3705            if (sizehints != NULL)
3706            {
3707                    sizehints->flags = USPosition;
3708                    XSetWMNormalHints(g_display, wnd, sizehints);
3709                    XFree(sizehints);
3710            }
3711    
3712            /* Parent-less transient windows */
3713            if (parent == 0xFFFFFFFF)
3714            {
3715                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3716                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3717                       using some other hints. */
3718                    ewmh_set_window_popup(wnd);
3719            }
3720            /* Normal transient windows */
3721            else if (parent != 0x00000000)
3722            {
3723                    sw_parent = sw_get_window_by_id(parent);
3724                    if (sw_parent)
3725                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3726                    else
3727                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3728            }
3729    
3730            if (flags & SEAMLESSRDP_CREATE_MODAL)
3731            {
3732                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3733                       somewhat at least */
3734                    if (parent == 0x00000000)
3735                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3736                    ewmh_set_window_modal(wnd);
3737            }
3738    
3739            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3740            {
3741                    /* Make window always-on-top */
3742                    ewmh_set_window_above(wnd);
3743            }
3744    
3745            /* FIXME: Support for Input Context:s */
3746    
3747            get_input_mask(&input_mask);
3748            input_mask |= PropertyChangeMask;
3749    
3750            XSelectInput(g_display, wnd, input_mask);
3751    
3752            /* handle the WM_DELETE_WINDOW protocol. */
3753            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3754    
3755            sw = xmalloc(sizeof(seamless_window));
3756    
3757            memset(sw, 0, sizeof(seamless_window));
3758    
3759            sw->wnd = wnd;
3760            sw->id = id;
3761            sw->group = sw_find_group(group, False);
3762            sw->group->refcnt++;
3763            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3764            sw->desktop = 0;
3765            sw->position_timer = xmalloc(sizeof(struct timeval));
3766            timerclear(sw->position_timer);
3767    
3768            sw->outstanding_position = False;
3769            sw->outpos_serial = 0;
3770            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3771            sw->outpos_width = sw->outpos_height = 0;
3772    
3773            sw->next = g_seamless_windows;
3774            g_seamless_windows = sw;
3775    
3776            /* WM_HINTS */
3777            wmhints = XAllocWMHints();
3778            if (wmhints)
3779            {
3780                    wmhints->flags = WindowGroupHint;
3781                    wmhints->window_group = sw->group->wnd;
3782                    XSetWMHints(g_display, sw->wnd, wmhints);
3783                    XFree(wmhints);
3784            }
3785    }
3786    
3787    
3788    void
3789    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3790    {
3791            seamless_window *sw;
3792    
3793            if (!g_seamless_active)
3794                    return;
3795    
3796            sw = sw_get_window_by_id(id);
3797            if (!sw)
3798            {
3799                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3800                    return;
3801            }
3802    
3803            XDestroyWindow(g_display, sw->wnd);
3804            sw_remove_window(sw);
3805    }
3806    
3807    
3808    void
3809    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3810    {
3811            seamless_window *sw, *sw_next;
3812    
3813            if (!g_seamless_active)
3814                    return;
3815    
3816            for (sw = g_seamless_windows; sw; sw = sw_next)
3817            {
3818                    sw_next = sw->next;
3819    
3820                    if (sw->group->id == id)
3821                    {
3822                            XDestroyWindow(g_display, sw->wnd);
3823                            sw_remove_window(sw);
3824                    }
3825            }
3826    }
3827    
3828    
3829    void
3830    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3831                        const char *data, int chunk_len)
3832    {
3833            seamless_window *sw;
3834    
3835            if (!g_seamless_active)
3836                    return;
3837    
3838            sw = sw_get_window_by_id(id);
3839            if (!sw)
3840            {
3841                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3842                    return;
3843            }
3844    
3845            if (chunk == 0)
3846            {
3847                    if (sw->icon_size)
3848                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3849    
3850                    if (strcmp(format, "RGBA") != 0)
3851                    {
3852                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3853                            return;
3854                    }
3855    
3856                    sw->icon_size = width * height * 4;
3857                    if (sw->icon_size > 32 * 32 * 4)
3858                    {
3859                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3860                            sw->icon_size = 0;
3861                            return;
3862                    }
3863    
3864                    sw->icon_offset = 0;
3865            }
3866            else
3867            {
3868                    if (!sw->icon_size)
3869                            return;
3870            }
3871    
3872            if (chunk_len > (sw->icon_size - sw->icon_offset))
3873            {
3874                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3875                            chunk_len, sw->icon_size - sw->icon_offset);
3876                    sw->icon_size = 0;
3877                    return;
3878            }
3879    
3880            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3881            sw->icon_offset += chunk_len;
3882    
3883            if (sw->icon_offset == sw->icon_size)
3884            {
3885                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3886                    sw->icon_size = 0;
3887            }
3888    }
3889    
3890    
3891    void
3892    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3893    {
3894            seamless_window *sw;
3895    
3896            if (!g_seamless_active)
3897                    return;
3898    
3899            sw = sw_get_window_by_id(id);
3900            if (!sw)
3901            {
3902                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3903                    return;
3904            }
3905    
3906            if (strcmp(format, "RGBA") != 0)
3907            {
3908                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3909                    return;
3910            }
3911    
3912            ewmh_del_icon(sw->wnd, width, height);
3913    }
3914    
3915    
3916    void
3917    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3918    {
3919            seamless_window *sw;
3920    
3921            if (!g_seamless_active)
3922                    return;
3923    
3924            sw = sw_get_window_by_id(id);
3925            if (!sw)
3926            {
3927                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3928                    return;
3929            }
3930    
3931            /* We ignore server updates until it has handled our request. */
3932            if (sw->outstanding_position)
3933                    return;
3934    
3935            if (!width || !height)
3936                    /* X11 windows must be at least 1x1 */
3937                    return;
3938    
3939            sw->xoffset = x;
3940            sw->yoffset = y;
3941            sw->width = width;
3942            sw->height = height;
3943    
3944            /* If we move the window in a maximized state, then KDE won't
3945               accept restoration */
3946            switch (sw->state)
3947            {
3948                    case SEAMLESSRDP_MINIMIZED:
3949                    case SEAMLESSRDP_MAXIMIZED:
3950                            return;
3951            }
3952    
3953            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3954            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3955    }
3956    
3957    
3958    void
3959    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3960    {
3961            seamless_window *sw;
3962            XWindowChanges values;
3963            unsigned long restack_serial;
3964    
3965            if (!g_seamless_active)
3966                    return;
3967    
3968            sw = sw_get_window_by_id(id);
3969            if (!sw)
3970            {
3971                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3972                    return;
3973            }
3974    
3975            if (behind)
3976            {
3977                    seamless_window *sw_behind;
3978    
3979                    sw_behind = sw_get_window_by_id(behind);
3980                    if (!sw_behind)
3981                    {
3982                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
3983                            return;
3984                    }
3985    
3986                    if (!g_seamless_broken_restack)
3987                    {
3988                            values.stack_mode = Below;
3989                            values.sibling = sw_behind->wnd;
3990                            restack_serial = XNextRequest(g_display);
3991                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
3992                                                 CWStackMode | CWSibling, &values);
3993                            sw_wait_configurenotify(sw->wnd, restack_serial);
3994                    }
3995            }
3996            else
3997            {
3998                    values.stack_mode = Above;
3999                    restack_serial = XNextRequest(g_display);
4000                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4001                                         &values);
4002                    sw_wait_configurenotify(sw->wnd, restack_serial);
4003            }
4004    
4005            sw_restack_window(sw, behind);
4006    
4007            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4008            {
4009                    /* Make window always-on-top */
4010                    ewmh_set_window_above(sw->wnd);
4011            }
4012    }
4013    
4014    
4015    void
4016    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4017    {
4018            seamless_window *sw;
4019    
4020            if (!g_seamless_active)
4021                    return;
4022    
4023            sw = sw_get_window_by_id(id);
4024            if (!sw)
4025            {
4026                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4027                    return;
4028            }
4029    
4030            /* FIXME: Might want to convert the name for non-EWMH WMs */
4031            XStoreName(g_display, sw->wnd, title);
4032            ewmh_set_wm_name(sw->wnd, title);
4033    }
4034    
4035    
4036    void
4037    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
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_setstate: No information for window 0x%lx\n", id);
4048                    return;
4049            }
4050    
4051            switch (state)
4052            {
4053                    case SEAMLESSRDP_NORMAL:
4054                    case SEAMLESSRDP_MAXIMIZED:
4055                            ewmh_change_state(sw->wnd, state);
4056                            XMapWindow(g_display, sw->wnd);
4057                            break;
4058                    case SEAMLESSRDP_MINIMIZED:
4059                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4060                               the Window Manager should probably just ignore the request, since
4061                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4062                               such as minimization, rather than an independent state." Besides,
4063                               XIconifyWindow is easier. */
4064                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4065                            {
4066                                    XWMHints *hints;
4067                                    hints = XGetWMHints(g_display, sw->wnd);
4068                                    if (hints)
4069                                    {
4070                                            hints->flags |= StateHint;
4071                                            hints->initial_state = IconicState;
4072                                            XSetWMHints(g_display, sw->wnd, hints);
4073                                            XFree(hints);
4074                                    }
4075                                    XMapWindow(g_display, sw->wnd);
4076                            }
4077                            else
4078                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4079                            break;
4080                    default:
4081                            warning("SeamlessRDP: Invalid state %d\n", state);
4082                            break;
4083            }
4084    
4085            sw->state = state;
4086    }
4087    
4088    
4089    void
4090    ui_seamless_syncbegin(unsigned long flags)
4091    {
4092            if (!g_seamless_active)
4093                    return;
4094    
4095            /* Destroy all seamless windows */
4096            while (g_seamless_windows)
4097            {
4098                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4099                    sw_remove_window(g_seamless_windows);
4100            }
4101    }
4102    
4103    
4104    void
4105    ui_seamless_ack(unsigned int serial)
4106    {
4107            seamless_window *sw;
4108            for (sw = g_seamless_windows; sw; sw = sw->next)
4109            {
4110                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4111                    {
4112                            sw->xoffset = sw->outpos_xoffset;
4113                            sw->yoffset = sw->outpos_yoffset;
4114                            sw->width = sw->outpos_width;
4115                            sw->height = sw->outpos_height;
4116                            sw->outstanding_position = False;
4117    
4118                            /* Do a complete redraw of the window as part of the
4119                               completion of the move. This is to remove any
4120                               artifacts caused by our lack of synchronization. */
4121                            XCopyArea(g_display, g_backstore,
4122                                      sw->wnd, g_gc,
4123                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4124    
4125                            break;
4126                    }
4127            }
4128    }

Legend:
Removed from v.528  
changed lines
  Added in v.1459

  ViewVC Help
Powered by ViewVC 1.1.26