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

Diff of /jpeg/rdesktop/trunk/xwin.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26