/[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 498 by astrand, Tue Oct 14 12:05:27 2003 UTC jpeg/rdesktop/trunk/xwin.c revision 1508 by dpavlin, Mon Jul 20 16:47:49 2009 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2008
5       Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB
6    
7     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 21 
21    
22  #include <X11/Xlib.h>  #include <X11/Xlib.h>
23  #include <X11/Xutil.h>  #include <X11/Xutil.h>
24    #include <X11/Xproto.h>
25    #include <unistd.h>
26    #include <sys/time.h>
27  #include <time.h>  #include <time.h>
28  #include <errno.h>  #include <errno.h>
29    #include <strings.h>
30  #include "rdesktop.h"  #include "rdesktop.h"
31  #include "xproto.h"  #include "xproto.h"
32    
33    /* DJ globals begin */
34    extern uint8 * g_bitmap_data;
35    extern uint8 * g_bitmap_data_last_write;
36    extern uint32 g_pixels_changed;
37    extern unsigned long long g_time_last_change;
38    /* DJ globals end */
39    
40  extern int g_width;  extern int g_width;
41  extern int g_height;  extern int g_height;
42  extern BOOL g_sendmotion;  extern int g_xpos;
43  extern BOOL g_fullscreen;  extern int g_ypos;
44  extern BOOL g_grab_keyboard;  extern int g_pos;
45  extern BOOL g_hide_decorations;  extern RD_BOOL g_sendmotion;
46    extern RD_BOOL g_fullscreen;
47    extern RD_BOOL g_grab_keyboard;
48    extern RD_BOOL g_hide_decorations;
49  extern char g_title[];  extern char g_title[];
50  extern int g_server_bpp;  /* Color depth of the RDP session.
51       As of RDP 5.1, it may be 8, 15, 16 or 24. */
52    extern int g_server_depth;
53  extern int g_win_button_size;  extern int g_win_button_size;
54    
55  Display *g_display;  Display *g_display;
# Line 40  Time g_last_gesturetime; Line 57  Time g_last_gesturetime;
57  static int g_x_socket;  static int g_x_socket;
58  static Screen *g_screen;  static Screen *g_screen;
59  Window g_wnd;  Window g_wnd;
60  BOOL g_enable_compose = False;  
61  static GC g_gc;  /* 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;  static Visual *g_visual;
107    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
108       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
109       as far as we're concerned. */
110  static int g_depth;  static int g_depth;
111    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
112       This may be larger than g_depth, in which case some of the bits would
113       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
114  static int g_bpp;  static int g_bpp;
115  static XIM g_IM;  static XIM g_IM;
116  static XIC g_IC;  static XIC g_IC;
117  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
118    /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
119       to physical (1-based) indices. */
120    static unsigned char g_pointer_log_to_phys_map[32];
121  static Cursor g_current_cursor;  static Cursor g_current_cursor;
122    static RD_HCURSOR g_null_cursor = NULL;
123  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
124  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
125  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
126    static RD_BOOL g_focused;
127    static RD_BOOL g_mouse_in_wnd;
128    /* Indicates that:
129       1) visual has 15, 16 or 24 depth and the same color channel masks
130          as its RDP equivalent (implies X server is LE),
131       2) host is LE
132       This will trigger an optimization whose real value is questionable.
133    */
134    static RD_BOOL g_compatible_arch;
135    /* Indicates whether RDP's bitmaps and our XImages have the same
136       binary format. If so, we can avoid an expensive translation.
137       Note that this can be true when g_compatible_arch is false,
138       e.g.:
139      
140         RDP(LE) <-> host(BE) <-> X-Server(LE)
141        
142       ('host' is the machine running rdesktop; the host simply memcpy's
143        so its endianess doesn't matter)
144     */
145    static RD_BOOL g_no_translate_image = False;
146    
147  /* endianness */  /* endianness */
148  static BOOL g_host_be;  static RD_BOOL g_host_be;
149  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
150    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
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 g_ownbackstore;  extern RD_BOOL g_ownbackstore;
155  static Pixmap g_backstore;  static Pixmap g_backstore = 0;
156    
157  /* Moving in single app mode */  /* Moving in single app mode */
158  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
159  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
160  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
161    static RD_BOOL g_using_full_workarea = False;
162    
163  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
164  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
165  #endif  #endif
166    
167  /* MWM decorations */  /* MWM decorations */
# Line 76  extern BOOL g_dsp_busy; Line 169  extern BOOL g_dsp_busy;
169  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
170  typedef struct  typedef struct
171  {  {
172          uint32 flags;          unsigned long flags;
173          uint32 functions;          unsigned long functions;
174          uint32 decorations;          unsigned long decorations;
175          sint32 inputMode;          long inputMode;
176          uint32 status;          unsigned long status;
177  }  }
178  PropMotifWmHints;  PropMotifWmHints;
179    
# Line 92  typedef struct Line 185  typedef struct
185  }  }
186  PixelColour;  PixelColour;
187    
188    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
189            do { \
190                    seamless_window *sw; \
191                    XRectangle rect; \
192                    if (!g_seamless_windows) break; \
193                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
194                        rect.x = g_clip_rectangle.x - sw->xoffset; \
195                        rect.y = g_clip_rectangle.y - sw->yoffset; \
196                        rect.width = g_clip_rectangle.width; \
197                        rect.height = g_clip_rectangle.height; \
198                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
199                        func args; \
200                    } \
201                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
202            } while (0)
203    
204    static void
205    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
206    {
207            points[0].x -= xoffset;
208            points[0].y -= yoffset;
209            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
210            points[0].x += xoffset;
211            points[0].y += yoffset;
212    }
213    
214    static void
215    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
216    {
217            points[0].x -= xoffset;
218            points[0].y -= yoffset;
219            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
220            points[0].x += xoffset;
221            points[0].y += yoffset;
222    }
223    
224  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
225  { \  { \
226          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
227            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
228          if (g_ownbackstore) \          if (g_ownbackstore) \
229                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
230  }  }
# Line 105  PixelColour; Line 234  PixelColour;
234          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
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  BOOL g_owncolmap = False;  extern RD_BOOL g_owncolmap;
266  static Colormap g_xcolmap;  static Colormap g_xcolmap;
267  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
268    
269  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : translate_colour(g_colmap[col]) )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
270  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
271  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
272    
# Line 136  static int rop2_map[] = { Line 292  static int rop2_map[] = {
292  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
293  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
294    
295    static seamless_window *
296    sw_get_window_by_id(unsigned long id)
297    {
298            seamless_window *sw;
299            for (sw = g_seamless_windows; sw; sw = sw->next)
300            {
301                    if (sw->id == id)
302                            return sw;
303            }
304            return NULL;
305    }
306    
307    
308    static seamless_window *
309    sw_get_window_by_wnd(Window wnd)
310    {
311            seamless_window *sw;
312            for (sw = g_seamless_windows; sw; sw = sw->next)
313            {
314                    if (sw->wnd == wnd)
315                            return sw;
316            }
317            return NULL;
318    }
319    
320    
321  static void  static void
322  mwm_hide_decorations(void)  sw_remove_window(seamless_window * win)
323    {
324            seamless_window *sw, **prevnext = &g_seamless_windows;
325            for (sw = g_seamless_windows; sw; sw = sw->next)
326            {
327                    if (sw == win)
328                    {
329                            *prevnext = sw->next;
330                            sw->group->refcnt--;
331                            if (sw->group->refcnt == 0)
332                            {
333                                    XDestroyWindow(g_display, sw->group->wnd);
334                                    xfree(sw->group);
335                            }
336                            xfree(sw->position_timer);
337                            xfree(sw);
338                            return;
339                    }
340                    prevnext = &sw->next;
341            }
342            return;
343    }
344    
345    
346    /* Move all windows except wnd to new desktop */
347    static void
348    sw_all_to_desktop(Window wnd, unsigned int desktop)
349    {
350            seamless_window *sw;
351            for (sw = g_seamless_windows; sw; sw = sw->next)
352            {
353                    if (sw->wnd == wnd)
354                            continue;
355                    if (sw->desktop != desktop)
356                    {
357                            ewmh_move_to_desktop(sw->wnd, desktop);
358                            sw->desktop = desktop;
359                    }
360            }
361    }
362    
363    
364    /* Send our position */
365    static void
366    sw_update_position(seamless_window * sw)
367    {
368            XWindowAttributes wa;
369            int x, y;
370            Window child_return;
371            unsigned int serial;
372    
373            XGetWindowAttributes(g_display, sw->wnd, &wa);
374            XTranslateCoordinates(g_display, sw->wnd, wa.root,
375                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
376    
377            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
378    
379            sw->outstanding_position = True;
380            sw->outpos_serial = serial;
381    
382            sw->outpos_xoffset = x;
383            sw->outpos_yoffset = y;
384            sw->outpos_width = wa.width;
385            sw->outpos_height = wa.height;
386    }
387    
388    
389    /* Check if it's time to send our position */
390    static void
391    sw_check_timers()
392    {
393            seamless_window *sw;
394            struct timeval now;
395    
396            gettimeofday(&now, NULL);
397            for (sw = g_seamless_windows; sw; sw = sw->next)
398            {
399                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
400                    {
401                            timerclear(sw->position_timer);
402                            sw_update_position(sw);
403                    }
404            }
405    }
406    
407    
408    static void
409    sw_restack_window(seamless_window * sw, unsigned long behind)
410    {
411            seamless_window *sw_above;
412    
413            /* Remove window from stack */
414            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
415            {
416                    if (sw_above->behind == sw->id)
417                            break;
418            }
419    
420            if (sw_above)
421                    sw_above->behind = sw->behind;
422    
423            /* And then add it at the new position */
424            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
425            {
426                    if (sw_above->behind == behind)
427                            break;
428            }
429    
430            if (sw_above)
431                    sw_above->behind = sw->id;
432    
433            sw->behind = behind;
434    }
435    
436    
437    static void
438    sw_handle_restack(seamless_window * sw)
439    {
440            Status status;
441            Window root, parent, *children;
442            unsigned int nchildren, i;
443            seamless_window *sw_below;
444    
445            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
446                                &root, &parent, &children, &nchildren);
447            if (!status || !nchildren)
448                    return;
449    
450            sw_below = NULL;
451    
452            i = 0;
453            while (children[i] != sw->wnd)
454            {
455                    i++;
456                    if (i >= nchildren)
457                            goto end;
458            }
459    
460            for (i++; i < nchildren; i++)
461            {
462                    sw_below = sw_get_window_by_wnd(children[i]);
463                    if (sw_below)
464                            break;
465            }
466    
467            if (!sw_below && !sw->behind)
468                    goto end;
469            if (sw_below && (sw_below->id == sw->behind))
470                    goto end;
471    
472            if (sw_below)
473            {
474                    seamless_send_zchange(sw->id, sw_below->id, 0);
475                    sw_restack_window(sw, sw_below->id);
476            }
477            else
478            {
479                    seamless_send_zchange(sw->id, 0, 0);
480                    sw_restack_window(sw, 0);
481            }
482    
483          end:
484            XFree(children);
485    }
486    
487    
488    static seamless_group *
489    sw_find_group(unsigned long id, RD_BOOL dont_create)
490    {
491            seamless_window *sw;
492            seamless_group *sg;
493            XSetWindowAttributes attribs;
494    
495            for (sw = g_seamless_windows; sw; sw = sw->next)
496            {
497                    if (sw->group->id == id)
498                            return sw->group;
499            }
500    
501            if (dont_create)
502                    return NULL;
503    
504            sg = xmalloc(sizeof(seamless_group));
505    
506            sg->wnd =
507                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
508                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
509    
510            sg->id = id;
511            sg->refcnt = 0;
512    
513            return sg;
514    }
515    
516    
517    static void
518    mwm_hide_decorations(Window wnd)
519  {  {
520          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
521          Atom hintsatom;          Atom hintsatom;
# Line 154  mwm_hide_decorations(void) Line 532  mwm_hide_decorations(void)
532                  return;                  return;
533          }          }
534    
535          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
536                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
537    
538  }  }
539    
540  static PixelColour  typedef struct _sw_configurenotify_context
541  split_colour15(uint32 colour)  {
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          PixelColour rv;          XEvent xevent;
575          rv.red = (colour & 0x7c00) >> 10;          sw_configurenotify_context context;
576          rv.red = (rv.red * 0xff) / 0x1f;          struct timeval now;
577          rv.green = (colour & 0x03e0) >> 5;          struct timeval nextsecond;
578          rv.green = (rv.green * 0xff) / 0x1f;          RD_BOOL got = False;
579          rv.blue = (colour & 0x1f);  
580          rv.blue = (rv.blue * 0xff) / 0x1f;          context.window = wnd;
581          return rv;          context.serial = serial;
582  }  
583            gettimeofday(&nextsecond, NULL);
584  static PixelColour          nextsecond.tv_sec += 1;
585  split_colour16(uint32 colour)  
586  {          do
587          PixelColour rv;          {
588          rv.red = (colour & 0xf800) >> 11;                  if (XCheckIfEvent(g_display, &xevent, sw_configurenotify_p, (XPointer) & context))
589          rv.red = (rv.red * 0xff) / 0x1f;                  {
590          rv.green = (colour & 0x07e0) >> 5;                          got = True;
591          rv.green = (rv.green * 0xff) / 0x3f;                          break;
592          rv.blue = (colour & 0x001f);                  }
593          rv.blue = (rv.blue * 0xff) / 0x1f;                  usleep(100000);
594          return rv;                  gettimeofday(&now, NULL);
595  }          }
596            while (timercmp(&now, &nextsecond, <));
597  static PixelColour  
598  split_colour24(uint32 colour)          if (!got)
599  {          {
600          PixelColour rv;                  warning("Broken Window Manager: Timeout while waiting for ConfigureNotify\n");
601          rv.blue = (colour & 0xff0000) >> 16;          }
         rv.green = (colour & 0xff00) >> 8;  
         rv.red = (colour & 0xff);  
         return rv;  
602  }  }
603    
604  static uint32  /* Get the toplevel window, in case of reparenting */
605  make_colour16(PixelColour pc)  static Window
606    sw_get_toplevel(Window wnd)
607  {  {
608          pc.red = (pc.red * 0x1f) / 0xff;          Window root, parent;
609          pc.green = (pc.green * 0x3f) / 0xff;          Window *child_list;
610          pc.blue = (pc.blue * 0x1f) / 0xff;          unsigned int num_children;
611          return (pc.red << 11) | (pc.green << 5) | pc.blue;  
612            while (1)
613            {
614                    XQueryTree(g_display, wnd, &root, &parent, &child_list, &num_children);
615                    if (root == parent)
616                    {
617                            break;
618                    }
619                    else if (!parent)
620                    {
621                            warning("Internal error: sw_get_toplevel called with root window\n");
622                    }
623    
624                    wnd = parent;
625            }
626    
627            return wnd;
628  }  }
629    
630  static uint32  
631  make_colour24(PixelColour pc)  /* 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          if (g_xserver_be)          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                  return pc.red | (pc.green << 8) | (pc.blue << 16);                  if (child_list[i] == behind)
651                    {
652                            found_behind = True;
653                    }
654                    else if (child_list[i] == wnd)
655                    {
656                            found_wnd = True;
657                            break;
658                    }
659          }          }
660          else  
661            if (child_list)
662                    XFree(child_list);
663    
664            if (!found_wnd)
665          {          {
666                  return (pc.red << 16) | (pc.green << 8) | pc.blue;                  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  static uint32  
679  make_colour32(PixelColour pc)  /* 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          if (g_xserver_be)          /* 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                  return pc.red | (pc.green << 8) | (pc.blue << 16);                  XWindowEvent(g_display, wnds[2], StructureNotifyMask, &xevent);
728          }          }
729          else          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                  return (pc.red << 16) | (pc.green << 8) | pc.blue;                  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 (g_server_bpp)          PixelColour pc;
826            switch (g_server_depth)
827          {          {
828                  case 15:                  case 15:
829                          switch (g_bpp)                          SPLITCOLOUR15(colour, pc);
                         {  
                                 case 16:  
                                         colour = make_colour16(split_colour15(colour));  
                                         break;  
                                 case 24:  
                                         colour = make_colour24(split_colour15(colour));  
                                         break;  
                                 case 32:  
                                         colour = make_colour32(split_colour15(colour));  
                                         break;  
                         }  
830                          break;                          break;
831                  case 16:                  case 16:
832                          switch (g_bpp)                          SPLITCOLOUR16(colour, pc);
                         {  
                                 case 16:  
                                         break;  
                                 case 24:  
                                         colour = make_colour24(split_colour16(colour));  
                                         break;  
                                 case 32:  
                                         colour = make_colour32(split_colour16(colour));  
                                         break;  
                         }  
833                          break;                          break;
834                  case 24:                  case 24:
835                          switch (g_bpp)                  case 32:
836                          {                          SPLITCOLOUR24(colour, pc);
837                                  case 16:                          break;
838                                          colour = make_colour16(split_colour24(colour));                  default:
839                                          break;                          /* Avoid warning */
840                                  case 24:                          pc.red = 0;
841                                          break;                          pc.green = 0;
842                                  case 32:                          pc.blue = 0;
                                         colour = make_colour32(split_colour24(colour));  
                                         break;  
                         }  
843                          break;                          break;
844          }          }
845          return colour;          return MAKECOLOUR(pc);
846    }
847    
848    /* indent is confused by UNROLL8 */
849    /* *INDENT-OFF* */
850    
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  static void
884  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
885  {  {
886          while (out < end)          while (out < end)
887                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
888  }  }
889    
890  static void  static void
891  translate8to16(uint8 * data, uint16 * out, uint16 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
892  {  {
893          while (out < end)          uint16 value;
894                  *(out++) = (uint16) g_colmap[*(data++)];  
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 */  /* little endian - conversion happens when colourmap is built */
924  static void  static void
925  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
926  {  {
927          uint32 value;          uint32 value;
928    
929          while (out < end)          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                  value = g_colmap[*(data++)];                  while (out < end)
940                  *(out++) = value;                  {
941                  *(out++) = value >> 8;                          value = g_colmap[*(data++)];
942                  *(out++) = value >> 16;                          LOUT24(out, value);
943                    }
944          }          }
945  }  }
946    
947  static void  static void
948  translate8to32(uint8 * data, uint32 * out, uint32 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
949  {  {
950          while (out < end)          uint32 value;
                 *(out++) = g_colmap[*(data++)];  
 }  
951    
952  /* todo the remaining translate function might need some big endian check ?? */          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  static void
981  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
982  {  {
983          uint16 pixel;          uint16 pixel;
984          uint16 value;          uint16 value;
985            PixelColour pc;
986    
987          while (out < end)          if (g_xserver_be)
988          {          {
989                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                         BSWAP16(pixel)  
                 }  
   
                 value = make_colour16(split_colour15(pixel));  
   
                 if (g_xserver_be)  
990                  {                  {
991                          *(out++) = value >> 8;                          pixel = *(data++);
992                          *(out++) = value;                          if (g_host_be)
993                            {
994                                    BSWAP16(pixel);
995                            }
996                            SPLITCOLOUR15(pixel, pc);
997                            value = MAKECOLOUR(pc);
998                            BOUT16(out, value);
999                  }                  }
1000                  else          }
1001            else
1002            {
1003                    while (out < end)
1004                  {                  {
1005                          *(out++) = value;                          pixel = *(data++);
1006                          *(out++) = value >> 8;                          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  static void
1018  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
1019  {  {
1020          uint32 value;          uint32 value;
1021          uint16 pixel;          uint16 pixel;
1022            PixelColour pc;
1023    
1024          while (out < end)          if (g_compatible_arch)
1025          {          {
1026                  pixel = *(data++);                  /* *INDENT-OFF* */
1027                    REPEAT3
1028                  if (g_host_be)                  (
1029                  {                          pixel = *(data++);
1030                          BSWAP16(pixel)                          SPLITCOLOUR15(pixel, pc);
1031                  }                          *(out++) = pc.blue;
1032                            *(out++) = pc.green;
1033                  value = make_colour24(split_colour15(pixel));                          *(out++) = pc.red;
1034                  if (g_xserver_be)                  )
1035                    /* *INDENT-ON* */
1036            }
1037            else if (g_xserver_be)
1038            {
1039                    while (out < end)
1040                  {                  {
1041                          *(out++) = value >> 16;                          pixel = *(data++);
1042                          *(out++) = value >> 8;                          if (g_host_be)
1043                          *(out++) = value;                          {
1044                                    BSWAP16(pixel);
1045                            }
1046                            SPLITCOLOUR15(pixel, pc);
1047                            value = MAKECOLOUR(pc);
1048                            BOUT24(out, value);
1049                  }                  }
1050                  else          }
1051            else
1052            {
1053                    while (out < end)
1054                  {                  {
1055                          *(out++) = value;                          pixel = *(data++);
1056                          *(out++) = value >> 8;                          if (g_host_be)
1057                          *(out++) = value >> 16;                          {
1058                                    BSWAP16(pixel);
1059                            }
1060                            SPLITCOLOUR15(pixel, pc);
1061                            value = MAKECOLOUR(pc);
1062                            LOUT24(out, value);
1063                  }                  }
1064          }          }
1065  }  }
1066    
1067  static void  static void
1068  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
1069  {  {
1070          uint16 pixel;          uint16 pixel;
1071          uint32 value;          uint32 value;
1072            PixelColour pc;
1073    
1074          while (out < end)          if (g_compatible_arch)
1075          {          {
1076                  pixel = *(data++);                  /* *INDENT-OFF* */
1077                    REPEAT4
1078                  if (g_host_be)                  (
1079                  {                          pixel = *(data++);
1080                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
1081                  }                          *(out++) = pc.blue;
1082                            *(out++) = pc.green;
1083                  value = make_colour32(split_colour15(pixel));                          *(out++) = pc.red;
1084                            *(out++) = 0;
1085                  if (g_xserver_be)                  )
1086                    /* *INDENT-ON* */
1087            }
1088            else if (g_xserver_be)
1089            {
1090                    while (out < end)
1091                  {                  {
1092                          *(out++) = value >> 24;                          pixel = *(data++);
1093                          *(out++) = value >> 16;                          if (g_host_be)
1094                          *(out++) = value >> 8;                          {
1095                          *(out++) = value;                                  BSWAP16(pixel);
1096                            }
1097                            SPLITCOLOUR15(pixel, pc);
1098                            value = MAKECOLOUR(pc);
1099                            BOUT32(out, value);
1100                  }                  }
1101                  else          }
1102            else
1103            {
1104                    while (out < end)
1105                  {                  {
1106                          *(out++) = value;                          pixel = *(data++);
1107                          *(out++) = value >> 8;                          if (g_host_be)
1108                          *(out++) = value >> 16;                          {
1109                          *(out++) = value >> 24;                                  BSWAP16(pixel);
1110                            }
1111                            SPLITCOLOUR15(pixel, pc);
1112                            value = MAKECOLOUR(pc);
1113                            LOUT32(out, value);
1114                  }                  }
1115          }          }
1116  }  }
1117    
1118  static void  static void
1119  translate16to16(uint16 * data, uint16 * out, uint16 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
1120  {  {
1121            uint16 pixel;
1122          uint16 value;          uint16 value;
1123            PixelColour pc;
1124    
1125          if (g_xserver_be)          if (g_xserver_be)
1126          {          {
1127                  while (out < end)                  if (g_host_be)
1128                  {                  {
1129                          value = *data;                          while (out < end)
1130                          BSWAP16(value);                          {
1131                          *out = value;                                  pixel = *(data++);
1132                          data++;                                  BSWAP16(pixel);
1133                          out++;                                  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          else
1150          {          {
1151                  while (out < end)                  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                          *out = *data;                          while (out < end)
1165                          out++;                          {
1166                          data++;                                  pixel = *(data++);
1167                                    SPLITCOLOUR16(pixel, pc);
1168                                    value = MAKECOLOUR(pc);
1169                                    LOUT16(out, value);
1170                            }
1171                  }                  }
1172          }          }
1173  }  }
1174    
   
1175  static void  static void
1176  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
1177  {  {
1178          uint32 value;          uint32 value;
1179          uint16 pixel;          uint16 pixel;
1180            PixelColour pc;
1181    
1182          while (out < end)          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          {          {
                 pixel = *(data++);  
   
1197                  if (g_host_be)                  if (g_host_be)
1198                  {                  {
1199                          BSWAP16(pixel)                          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                  value = make_colour24(split_colour16(pixel));                  {
1210                            while (out < end)
1211                  if (g_xserver_be)                          {
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                          *(out++) = value >> 16;                          while (out < end)
1224                          *(out++) = value >> 8;                          {
1225                          *(out++) = value;                                  pixel = *(data++);
1226                                    BSWAP16(pixel);
1227                                    SPLITCOLOUR16(pixel, pc);
1228                                    value = MAKECOLOUR(pc);
1229                                    LOUT24(out, value);
1230                            }
1231                  }                  }
1232                  else                  else
1233                  {                  {
1234                          *(out++) = value;                          while (out < end)
1235                          *(out++) = value >> 8;                          {
1236                          *(out++) = value >> 16;                                  pixel = *(data++);
1237                                    SPLITCOLOUR16(pixel, pc);
1238                                    value = MAKECOLOUR(pc);
1239                                    LOUT24(out, value);
1240                            }
1241                  }                  }
1242          }          }
1243  }  }
1244    
1245  static void  static void
1246  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
1247  {  {
1248          uint16 pixel;          uint16 pixel;
1249          uint32 value;          uint32 value;
1250            PixelColour pc;
1251    
1252          while (out < end)          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          {          {
                 pixel = *(data++);  
   
1268                  if (g_host_be)                  if (g_host_be)
1269                  {                  {
1270                          BSWAP16(pixel)                          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
                 value = make_colour32(split_colour16(pixel));  
   
                 if (g_xserver_be)  
1280                  {                  {
1281                          *(out++) = value >> 24;                          while (out < end)
1282                          *(out++) = value >> 16;                          {
1283                          *(out++) = value >> 8;                                  pixel = *(data++);
1284                          *(out++) = value;                                  SPLITCOLOUR16(pixel, pc);
1285                  }                                  value = MAKECOLOUR(pc);
1286                  else                                  BOUT32(out, value);
1287                  {                          }
1288                          *(out++) = value;                  }
1289                          *(out++) = value >> 8;          }
1290                          *(out++) = value >> 16;          else
1291                          *(out++) = value >> 24;          {
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  static void
1317  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1318  {  {
1319          uint32 pixel = 0;          uint32 pixel = 0;
1320          uint16 value;          uint16 value;
1321            PixelColour pc;
1322    
1323          while (out < end)          while (out < end)
1324          {          {
1325                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1326                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1327                  pixel |= *(data++);                  pixel |= *(data++);
1328                    SPLITCOLOUR24(pixel, pc);
1329                  value = (uint16) make_colour16(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1330                  if (g_xserver_be)                  if (g_xserver_be)
1331                  {                  {
1332                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1333                  }                  }
1334                  else                  else
1335                  {                  {
1336                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1337                  }                  }
1338          }          }
1339  }  }
1340    
1341  static void  static void
1342  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1343  {  {
1344          while (out < end)          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                  *(out++) = (*(data++));                  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  static void
1375  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1376  {  {
1377          while (out < end)          uint32 pixel;
1378            uint32 value;
1379            PixelColour pc;
1380    
1381            if (g_compatible_arch)
1382          {          {
1383                  if (g_xserver_be)                  /* *INDENT-OFF* */
1384                  {  #ifdef NEED_ALIGN
1385                          *(out++) = 0x00;                  REPEAT4
1386                    (
1387                          *(out++) = *(data++);                          *(out++) = *(data++);
1388                          *(out++) = *(data++);                          *(out++) = *(data++);
1389                          *(out++) = *(data++);                          *(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                  else          }
1415            else
1416            {
1417                    while (out < end)
1418                  {                  {
1419                          *(out++) = *(data++);                          pixel = *(data++) << 16;
1420                          *(out++) = *(data++);                          pixel |= *(data++) << 8;
1421                          *(out++) = *(data++);                          pixel |= *(data++);
1422                          *(out++) = 0x00;                          SPLITCOLOUR24(pixel, pc);
1423                            value = MAKECOLOUR(pc);
1424                            LOUT32(out, value);
1425                  }                  }
1426          }          }
1427  }  }
# Line 571  translate24to32(uint8 * data, uint8 * ou Line 1429  translate24to32(uint8 * data, uint8 * ou
1429  static uint8 *  static uint8 *
1430  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1431  {  {
1432          int size = width * height * g_bpp / 8;          int size;
1433          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1434          uint8 *end = out + size;          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_bpp)          switch (g_server_depth)
1464          {          {
1465                  case 24:                  case 24:
1466                          switch (g_bpp)                          switch (g_bpp)
# Line 601  translate_image(int width, int height, u Line 1486  translate_image(int width, int height, u
1486                                          translate16to24((uint16 *) data, out, end);                                          translate16to24((uint16 *) data, out, end);
1487                                          break;                                          break;
1488                                  case 16:                                  case 16:
1489                                          translate16to16((uint16 *) data, (uint16 *) out,                                          translate16to16((uint16 *) data, out, end);
                                                         (uint16 *) end);  
1490                                          break;                                          break;
1491                          }                          }
1492                          break;                          break;
# Line 627  translate_image(int width, int height, u Line 1511  translate_image(int width, int height, u
1511                                          translate8to8(data, out, end);                                          translate8to8(data, out, end);
1512                                          break;                                          break;
1513                                  case 16:                                  case 16:
1514                                          translate8to16(data, (uint16 *) out, (uint16 *) end);                                          translate8to16(data, out, end);
1515                                          break;                                          break;
1516                                  case 24:                                  case 24:
1517                                          translate8to24(data, out, end);                                          translate8to24(data, out, end);
1518                                          break;                                          break;
1519                                  case 32:                                  case 32:
1520                                          translate8to32(data, (uint32 *) out, (uint32 *) end);                                          translate8to32(data, out, end);
1521                                          break;                                          break;
1522                          }                          }
1523                          break;                          break;
# Line 641  translate_image(int width, int height, u Line 1525  translate_image(int width, int height, u
1525          return out;          return out;
1526  }  }
1527    
1528  BOOL  static void
1529    xwin_refresh_pointer_map(void)
1530    {
1531            unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
1532            int i, pointer_buttons;
1533    
1534            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1535            if (pointer_buttons > sizeof(phys_to_log_map))
1536                    pointer_buttons = sizeof(phys_to_log_map);
1537    
1538            /* if multiple physical buttons map to the same logical button, then
1539             * use the lower numbered physical one */
1540            for (i = pointer_buttons - 1; i >= 0; i--)
1541            {
1542                    /* a user could specify arbitrary values for the logical button
1543                     * number, ignore any that are abnormally large */
1544                    if (phys_to_log_map[i] > sizeof(g_pointer_log_to_phys_map))
1545                            continue;
1546                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1547            }
1548    }
1549    
1550    RD_BOOL
1551  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1552  {  {
1553          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 666  get_key_state(unsigned int state, uint32 Line 1572  get_key_state(unsigned int state, uint32
1572          return (state & keysymMask) ? True : False;          return (state & keysymMask) ? True : False;
1573  }  }
1574    
1575  BOOL  static void
1576  ui_init(void)  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  {  {
1601          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1602          uint16 test;          int pixmap_formats_count, visuals_count;
1603            XVisualInfo *vmatches = NULL;
1604            XVisualInfo template;
1605          int i;          int i;
1606            unsigned red_weight, blue_weight, green_weight;
1607    
1608          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1609          if (g_display == NULL)  
1610            if (g_server_depth == -1)
1611          {          {
1612                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
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          g_x_socket = ConnectionNumber(g_display);          /* Search for best TrueColor visual */
1624          g_screen = DefaultScreenOfDisplay(g_display);          template.class = TrueColor;
1625          g_visual = DefaultVisualOfScreen(g_screen);          template.screen = screen_num;
1626          g_depth = DefaultDepthOfScreen(g_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                    /* we use a colourmap, so the default visual should do */
1747                    g_owncolmap = True;
1748                    g_visual = vmatches[0].visual;
1749                    g_depth = vmatches[0].depth;
1750            }
1751    
1752          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1753          if (pfm != NULL)          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 == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1759    
1760                            if (g_no_translate_image)
1761                          {                          {
1762                                  g_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                  }                  }
                 XFree(pfm);  
1787          }          }
1788            XFree(pfm);
1789            pfm = NULL;
1790            return True;
1791    }
1792    
1793          if (g_bpp < 8)  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                  error("Less than 8 bpp not currently supported.\n");                  XFree(name);
1815                  XCloseDisplay(g_display);          }
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;                  return False;
1839          }          }
1840    
         if (g_owncolmap != True)  
1841          {          {
1842                  g_xcolmap = DefaultColormapOfScreen(g_screen);                  uint16 endianess_test = 1;
1843                  if (g_depth <= 8)                  g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1844                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");          }
1845    
1846            g_old_error_handler = XSetErrorHandler(error_handler);
1847            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1848            screen_num = DefaultScreen(g_display);
1849            g_x_socket = ConnectionNumber(g_display);
1850            g_screen = ScreenOfDisplay(g_display, screen_num);
1851            g_depth = DefaultDepthOfScreen(g_screen);
1852    
1853            if (!select_visual(screen_num))
1854                    return False;
1855    
1856            if (g_no_translate_image)
1857            {
1858                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1859          }          }
1860    
1861          g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);          if (g_server_depth > g_bpp)
1862            {
1863                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1864                            g_server_depth, g_bpp);
1865            }
1866    
1867          if (DoesBackingStore(g_screen) != Always)          DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1868                  g_ownbackstore = True;                 g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1869    
1870          test = 1;          if (!g_owncolmap)
1871          g_host_be = !(BOOL) (*(uint8 *) (&test));          {
1872          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);                  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 ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1880            {
1881                    warning("External BackingStore not available. Using internal.\n");
1882                    g_ownbackstore = True;
1883            }
1884    
1885          if ((g_width == 0) || (g_height == 0))          /*
1886             * Determine desktop size
1887             */
1888            if (g_fullscreen)
1889            {
1890                    g_width = WidthOfScreen(g_screen);
1891                    g_height = HeightOfScreen(g_screen);
1892                    g_using_full_workarea = True;
1893            }
1894            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 */                  /* Fetch geometry from _NET_WORKAREA */
1905                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1906                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1907                  {                  {
1908                          g_width = cx;                          g_width = cx;
1909                          g_height = cy;                          g_height = cy;
1910                            g_using_full_workarea = True;
1911                  }                  }
1912                  else                  else
1913                  {                  {
1914                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1915                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1916                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1917                  }                  }
1918          }          }
1919    
         if (g_fullscreen)  
         {  
                 g_width = WidthOfScreen(g_screen);  
                 g_height = HeightOfScreen(g_screen);  
         }  
   
1920          /* make sure width is a multiple of 4 */          /* make sure width is a multiple of 4 */
1921          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1922    
         if (g_ownbackstore)  
         {  
                 g_backstore =  
                         XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,  
                                       g_depth);  
   
                 /* clear to prevent rubbish being exposed at startup */  
                 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));  
                 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);  
         }  
   
1923          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1924            xwin_refresh_pointer_map();
1925    
1926          xkeymap_init();          xkeymap_init();
1927    
# Line 769  ui_init(void) Line 1929  ui_init(void)
1929                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1930    
1931          xclip_init();          xclip_init();
1932            ewmh_init();
1933            if (g_seamless_rdp)
1934            {
1935                    seamless_init();
1936            }
1937    
1938          /* todo take this out when high colour is done */          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
         printf("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth);  
1939    
1940          return True;          return True;
1941  }  }
# Line 779  ui_init(void) Line 1943  ui_init(void)
1943  void  void
1944  ui_deinit(void)  ui_deinit(void)
1945  {  {
1946            while (g_seamless_windows)
1947            {
1948                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1949                    sw_remove_window(g_seamless_windows);
1950            }
1951    
1952            xclip_deinit();
1953    
1954          if (g_IM != NULL)          if (g_IM != NULL)
1955                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1956    
1957            if (g_null_cursor != NULL)
1958                    ui_destroy_cursor(g_null_cursor);
1959    
1960          XFreeModifiermap(g_mod_map);          XFreeModifiermap(g_mod_map);
1961    
1962          if (g_ownbackstore)          if (g_ownbackstore)
# Line 792  ui_deinit(void) Line 1967  ui_deinit(void)
1967          g_display = NULL;          g_display = NULL;
1968  }  }
1969    
1970  BOOL  
1971    static void
1972    get_window_attribs(XSetWindowAttributes * attribs)
1973    {
1974            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1975            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1976            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1977            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1978            attribs->override_redirect = g_fullscreen;
1979            attribs->colormap = g_xcolmap;
1980    }
1981    
1982    static void
1983    get_input_mask(long *input_mask)
1984    {
1985            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1986                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1987    
1988            if (g_sendmotion)
1989                    *input_mask |= PointerMotionMask;
1990            if (g_ownbackstore)
1991                    *input_mask |= ExposureMask;
1992            if (g_fullscreen || g_grab_keyboard)
1993                    *input_mask |= EnterWindowMask;
1994            if (g_grab_keyboard)
1995                    *input_mask |= LeaveWindowMask;
1996    }
1997    
1998    RD_BOOL
1999  ui_create_window(void)  ui_create_window(void)
2000  {  {
2001            uint8 null_pointer_mask[1] = { 0x80 };
2002            uint8 null_pointer_data[24] = { 0x00 };
2003    
2004          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
2005          XClassHint *classhints;          XClassHint *classhints;
2006          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 805  ui_create_window(void) Line 2011  ui_create_window(void)
2011          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
2012          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
2013    
2014          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
2015          attribs.backing_store = g_ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
2016          attribs.override_redirect = g_fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
2017            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2018          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2019                                0, CopyFromParent, InputOutput, CopyFromParent,  
2020                                CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          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                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2030                    ui_reset_clip();
2031            }
2032    
2033            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          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
2046            ewmh_set_wm_name(g_wnd, g_title);
2047    
2048          if (g_hide_decorations)          if (g_hide_decorations)
2049                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
2050    
2051          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2052          if (classhints != NULL)          if (classhints != NULL)
# Line 830  ui_create_window(void) Line 2060  ui_create_window(void)
2060          if (sizehints)          if (sizehints)
2061          {          {
2062                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
2063                    if (g_pos)
2064                            sizehints->flags |= PPosition;
2065                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
2066                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
2067                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
2068                  XFree(sizehints);                  XFree(sizehints);
2069          }          }
2070    
2071          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          if (g_embed_wnd)
2072                  VisibilityChangeMask | FocusChangeMask;          {
2073                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2074            }
2075    
2076          if (g_sendmotion)          get_input_mask(&input_mask);
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
2077    
2078          if (g_IM != NULL)          if (g_IM != NULL)
2079          {          {
# Line 867  ui_create_window(void) Line 2094  ui_create_window(void)
2094                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
2095          }          }
2096          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
2097            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
2098    
2099          g_focused = False;          g_focused = False;
2100          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 876  ui_create_window(void) Line 2104  ui_create_window(void)
2104          g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);          g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
2105          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);          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    
2116          return True;          return True;
2117  }  }
2118    
2119  void  void
2120    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)  ui_destroy_window(void)
2154  {  {
2155          if (g_IC != NULL)          if (g_IC != NULL)
# Line 893  xwin_toggle_fullscreen(void) Line 2163  xwin_toggle_fullscreen(void)
2163  {  {
2164          Pixmap contents = 0;          Pixmap contents = 0;
2165    
2166            if (g_seamless_active)
2167                    /* Turn off SeamlessRDP mode */
2168                    ui_seamless_toggle();
2169    
2170          if (!g_ownbackstore)          if (!g_ownbackstore)
2171          {          {
2172                  /* need to save contents of window */                  /* need to save contents of window */
# Line 913  xwin_toggle_fullscreen(void) Line 2187  xwin_toggle_fullscreen(void)
2187          }          }
2188  }  }
2189    
2190  /* Process all events in Xlib queue  static void
2191    handle_button_event(XEvent xevent, RD_BOOL down)
2192    {
2193            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 */     Returns 0 after user quit, 1 otherwise */
2280  static int  static int
2281  xwin_process_events(void)  xwin_process_events(void)
2282  {  {
2283          XEvent xevent;          XEvent xevent;
2284          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
2285          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
2286          char str[256];          char str[256];
2287          Status status;          Status status;
2288          unsigned int state;          int events = 0;
2289          Window wdummy;          seamless_window *sw;
         int dummy;  
2290    
2291          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
2292          {          {
2293                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
2294    
# Line 939  xwin_process_events(void) Line 2298  xwin_process_events(void)
2298                          continue;                          continue;
2299                  }                  }
2300    
                 flags = 0;  
   
2301                  switch (xevent.type)                  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:                          case ClientMessage:
2310                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2311                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
2312                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))                                      && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2313                                          /* Quit */                                  {
2314                                          return 0;                                          /* When killing a seamless window, close the window on the
2315                                               serverside instead of terminating rdesktop */
2316                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2317                                            if (!sw)
2318                                                    /* Otherwise, quit */
2319                                                    return 0;
2320                                            /* send seamless destroy process message */
2321                                            seamless_send_destroy(sw->id);
2322                                    }
2323                                  break;                                  break;
2324    
2325                          case KeyPress:                          case KeyPress:
# Line 974  xwin_process_events(void) Line 2345  xwin_process_events(void)
2345                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2346                                  }                                  }
2347    
2348                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2349                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2350    
2351                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2352                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2353                                          break;                                          break;
2354    
2355                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2356                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
2357                                  break;                                  break;
2358    
2359                          case KeyRelease:                          case KeyRelease:
# Line 999  xwin_process_events(void) Line 2361  xwin_process_events(void)
2361                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2362                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2363    
2364                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2365                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2366    
2367                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2368                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2369                                          break;                                          break;
2370    
2371                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2372                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2373                                  break;                                  break;
2374    
2375                          case ButtonPress:                          case ButtonPress:
2376                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2377                                  /* fall through */                                  break;
2378    
2379                          case ButtonRelease:                          case ButtonRelease:
2380                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
2381                                  break;                                  break;
2382    
2383                          case MotionNotify:                          case MotionNotify:
# Line 1092  xwin_process_events(void) Line 2392  xwin_process_events(void)
2392                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2393                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2394                                                         CurrentTime);                                                         CurrentTime);
2395                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2396                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2397                                    {
2398                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2399                                                           xevent.xmotion.x, xevent.xmotion.y);
2400                                    }
2401                                    else
2402                                    {
2403                                            /* SeamlessRDP */
2404                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2405                                                           xevent.xmotion.x_root,
2406                                                           xevent.xmotion.y_root);
2407                                    }
2408                                  break;                                  break;
2409    
2410                          case FocusIn:                          case FocusIn:
2411                                  if (xevent.xfocus.mode == NotifyGrab)                                  if (xevent.xfocus.mode == NotifyGrab)
2412                                          break;                                          break;
2413                                  g_focused = True;                                  g_focused = True;
2414                                  XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,                                  reset_modifier_keys();
                                               &dummy, &dummy, &state);  
                                 reset_modifier_keys(state);  
2415                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2416                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2417                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2418    
2419                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2420                                    if (!sw)
2421                                            break;
2422    
2423                                    /* Menu windows are real X11 windows,
2424                                       with focus. When such a window is
2425                                       destroyed, focus is reverted to the
2426                                       main application window, which
2427                                       would cause us to send FOCUS. This
2428                                       breaks window switching in, say,
2429                                       Seamonkey. We shouldn't need to
2430                                       send FOCUS: Windows should also
2431                                       revert focus to some other window
2432                                       when the menu window is
2433                                       destroyed. So, we only send FOCUS
2434                                       if the previous focus window still
2435                                       exists. */
2436                                    if (sw->id != g_seamless_focused)
2437                                    {
2438    
2439                                            if (sw_window_exists(g_seamless_focused))
2440                                                    seamless_send_focus(sw->id, 0);
2441                                            g_seamless_focused = sw->id;
2442                                    }
2443                                  break;                                  break;
2444    
2445                          case FocusOut:                          case FocusOut:
# Line 1138  xwin_process_events(void) Line 2472  xwin_process_events(void)
2472                                  break;                                  break;
2473    
2474                          case Expose:                          case Expose:
2475                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2476                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2477                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2478                                            xevent.xexpose.height,                                                    g_gc,
2479                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2480                                                      xevent.xexpose.width, xevent.xexpose.height,
2481                                                      xevent.xexpose.x, xevent.xexpose.y);
2482                                    }
2483                                    else
2484                                    {
2485                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2486                                            if (!sw)
2487                                                    break;
2488                                            XCopyArea(g_display, g_backstore,
2489                                                      xevent.xexpose.window, g_gc,
2490                                                      xevent.xexpose.x + sw->xoffset,
2491                                                      xevent.xexpose.y + sw->yoffset,
2492                                                      xevent.xexpose.width,
2493                                                      xevent.xexpose.height, xevent.xexpose.x,
2494                                                      xevent.xexpose.y);
2495                                    }
2496    
2497                                  break;                                  break;
2498    
2499                          case MappingNotify:                          case MappingNotify:
# Line 1157  xwin_process_events(void) Line 2508  xwin_process_events(void)
2508                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2509                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2510                                  }                                  }
2511    
2512                                    if (xevent.xmapping.request == MappingPointer)
2513                                    {
2514                                            xwin_refresh_pointer_map();
2515                                    }
2516    
2517                                  break;                                  break;
2518    
2519                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1171  xwin_process_events(void) Line 2528  xwin_process_events(void)
2528                                  break;                                  break;
2529                          case PropertyNotify:                          case PropertyNotify:
2530                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2531                                    if (xevent.xproperty.window == g_wnd)
2532                                            break;
2533                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2534                                            break;
2535    
2536                                    /* seamless */
2537                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2538                                    if (!sw)
2539                                            break;
2540    
2541                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2542                                        && (xevent.xproperty.state == PropertyNewValue))
2543                                    {
2544                                            sw->state = ewmh_get_window_state(sw->wnd);
2545                                            seamless_send_state(sw->id, sw->state, 0);
2546                                    }
2547    
2548                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2549                                        && (xevent.xproperty.state == PropertyNewValue))
2550                                    {
2551                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2552                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2553                                    }
2554    
2555                                    break;
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          }          }
# Line 1182  xwin_process_events(void) Line 2594  xwin_process_events(void)
2594  int  int
2595  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2596  {  {
2597          int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;          int n;
2598          fd_set rfds, wfds;          fd_set rfds, wfds;
2599            struct timeval tv;
2600            RD_BOOL s_timeout = False;
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 */                  /* Process any events already waiting */
2606                  if (!xwin_process_events())                  if (!xwin_process_events())
2607                          /* User quit */                          /* User quit */
2608                          return 0;                          return 0;
2609    
2610                    if (g_seamless_active)
2611                            sw_check_timers();
2612    
2613                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2614                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2615                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2616                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2617    
2618                    /* default timeout */
2619                    tv.tv_sec = 60;
2620                    tv.tv_usec = 0;
2621    
2622  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
2623                  /* FIXME: there should be an API for registering fds */                  rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;  
                 }  
2624  #endif  #endif
2625    
2626                  switch (select(n, &rfds, &wfds, NULL, NULL))                  /* 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    #ifdef WITH_RDPSND
2649                    rdpsnd_check_fds(&rfds, &wfds);
2650    #endif
2651    
2652                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2653    
2654                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2655                          return 1;                          return 1;
2656    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2657          }          }
2658  }  }
2659    
# Line 1231  ui_move_pointer(int x, int y) Line 2663  ui_move_pointer(int x, int y)
2663          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2664  }  }
2665    
2666  HBITMAP  RD_HBITMAP
2667  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2668  {  {
2669          XImage *image;          XImage *image;
2670          Pixmap bitmap;          Pixmap bitmap;
2671          uint8 *tdata;          uint8 *tdata;
2672            int bitmap_pad;
2673    
2674            if (g_server_depth == 8)
2675            {
2676                    bitmap_pad = 8;
2677            }
2678            else
2679            {
2680                    bitmap_pad = g_bpp;
2681    
2682                    if (g_bpp == 24)
2683                            bitmap_pad = 32;
2684            }
2685    
2686          tdata = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2687          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2688          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2689                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2690    
2691          XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2692    
2693          XFree(image);          XFree(image);
2694          if (!g_owncolmap)          if (tdata != data)
2695                  xfree(tdata);                  xfree(tdata);
2696          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2697    }
2698    
2699    void
2700    update_bitmap(int x, int y, int width, int height, uint8 * data)
2701    {
2702            int size;
2703            uint8 *out;
2704            uint8 *end;
2705            uint8 *c_current;
2706            uint8 *c_update;
2707            uint8 *c_written;
2708            int col;
2709            int row;
2710            BOOL matches_written;
2711            BOOL matches_current;
2712    
2713            size = width * height * 3;   /* force 24-bit color for libjpeg: R G B */
2714            out = (uint8 *) xmalloc(size);
2715            end = out + size;
2716    
2717            switch (g_server_depth)
2718            {
2719                    case 24:
2720                            translate24to24(data, out, end);
2721                            break;
2722                    case 16:
2723                            translate16to24((uint16 *) data, out, end);
2724                            break;
2725                    case 15:
2726                            translate15to24((uint16 *) data, out, end);
2727                            break;
2728                    case 8:
2729                            translate8to24(data, out, end);
2730                            break;
2731            }
2732    
2733            for (row=0; row<height; row++)
2734            {
2735                    /* truncate if out of bounds */
2736                    if (g_height <= (y + row))
2737                            break;
2738    
2739                    c_update = out + row * width * 3;
2740                    c_current = g_bitmap_data + (row + y) * g_width * 3 + x * 3;
2741                    c_written = g_bitmap_data_last_write + (row + y) * g_width * 3 + x * 3;
2742    
2743                    for (col = 0; col < width; col++)
2744                    {
2745                            /* truncate if out of bounds */
2746                            if (g_width <= (x + col))
2747                                    break;
2748    
2749                            matches_written = True;
2750                            matches_current = True;
2751    
2752                            /* updates come in as BGR order... force RGB */
2753                            if (*c_current != *(c_update+2))
2754                            {
2755                                    if (*(c_update+2) != *c_written)
2756                                            matches_written = False;
2757                                    matches_current = False;
2758                                    *c_current = *(c_update+2);
2759                            }
2760    
2761                            c_written++;
2762    
2763                            if (*(++c_current) != *(++c_update))
2764                            {
2765                                    if (*c_update != *c_written)
2766                                            matches_written = False;
2767                                    matches_current = False;
2768                                    *c_current = *c_update;
2769                            }
2770    
2771                            c_written++;
2772    
2773                            if (*(++c_current) != *(++c_update-2))
2774                            {
2775                                    if (*(c_update-2) != *c_written)
2776                                            matches_written = False;
2777                                    matches_current = False;
2778                                    *c_current = *(c_update-2);
2779                            }
2780    
2781                            c_written++;
2782                            c_current++;
2783                            c_update++;
2784    
2785                            if (!matches_current)
2786                            {
2787                                    if (matches_written)
2788                                            g_pixels_changed--;
2789                                    else
2790                                            g_pixels_changed++;
2791                            }
2792                    }
2793            }
2794    
2795            //printf("g_pixels_changed=%d\n", g_pixels_changed);
2796    
2797            xfree(out);
2798            g_time_last_change = tod();
2799  }  }
2800    
2801  void  void
# Line 1256  ui_paint_bitmap(int x, int y, int cx, in Line 2803  ui_paint_bitmap(int x, int y, int cx, in
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 = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2823          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2824                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2825    
2826          if (g_ownbackstore)          if (g_ownbackstore)
2827          {          {
2828                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2829                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2830                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2831                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2832                                             x - sw->xoffset, y - sw->yoffset));
2833          }          }
2834          else          else
2835          {          {
2836                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2837                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2838                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2839                                             x - sw->xoffset, y - sw->yoffset));
2840          }          }
2841    
2842          XFree(image);          XFree(image);
2843          if (!g_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(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2851  }  }
2852    
2853  HGLYPH  RD_HGLYPH
2854  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2855  {  {
2856          XImage *image;          XImage *image;
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(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2863          gc = XCreateGC(g_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(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2867                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1300  ui_create_glyph(int width, int height, u Line 2869  ui_create_glyph(int width, int height, u
2869          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2870          XInitImage(image);          XInitImage(image);
2871    
2872          XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2873    
2874          XFree(image);          XFree(image);
2875          XFreeGC(g_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(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2882  }  }
2883    
2884  HCURSOR  RD_HCURSOR
2885  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2886                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2887  {  {
2888          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2889          XColor bg, fg;          XColor bg, fg;
2890          Cursor xcursor;          Cursor xcursor;
2891          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1381  ui_create_cursor(unsigned int x, unsigne Line 2949  ui_create_cursor(unsigned int x, unsigne
2949          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2950          xfree(mask);          xfree(mask);
2951          xfree(cursor);          xfree(cursor);
2952          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2953  }  }
2954    
2955  void  void
2956  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2957  {  {
2958          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2959          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2960            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2961  }  }
2962    
2963  void  void
2964  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2965  {  {
2966          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2967  }  }
2968    
2969    void
2970    ui_set_null_cursor(void)
2971    {
2972            ui_set_cursor(g_null_cursor);
2973    }
2974    
2975  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
2976                  (xc)->red   = ((c)->red   << 8) | (c)->red; \                  (xc)->red   = ((c)->red   << 8) | (c)->red; \
2977                  (xc)->green = ((c)->green << 8) | (c)->green; \                  (xc)->green = ((c)->green << 8) | (c)->green; \
# Line 1404  ui_destroy_cursor(HCURSOR cursor) Line 2979  ui_destroy_cursor(HCURSOR cursor)
2979                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2980    
2981    
2982  HCOLOURMAP  RD_HCOLOURMAP
2983  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2984  {  {
2985          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1478  ui_create_colourmap(COLOURMAP * colours) Line 3053  ui_create_colourmap(COLOURMAP * colours)
3053    
3054                          }                          }
3055    
3056                            map[i] = colour;
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
3057                  }                  }
3058                  return map;                  return map;
3059          }          }
# Line 1502  ui_create_colourmap(COLOURMAP * colours) Line 3075  ui_create_colourmap(COLOURMAP * colours)
3075                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
3076    
3077                  xfree(xcolours);                  xfree(xcolours);
3078                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
3079          }          }
3080  }  }
3081    
3082  void  void
3083  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
3084  {  {
3085          if (!g_owncolmap)          if (!g_owncolmap)
3086                  xfree(map);                  xfree(map);
# Line 1516  ui_destroy_colourmap(HCOLOURMAP map) Line 3089  ui_destroy_colourmap(HCOLOURMAP map)
3089  }  }
3090    
3091  void  void
3092  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
3093  {  {
3094          if (!g_owncolmap)          if (!g_owncolmap)
3095          {          {
# Line 1526  ui_set_colourmap(HCOLOURMAP map) Line 3099  ui_set_colourmap(HCOLOURMAP map)
3099                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
3100          }          }
3101          else          else
3102            {
3103                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
3104                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
3105            }
3106  }  }
3107    
3108  void  void
3109  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
3110  {  {
3111          XRectangle rect;          g_clip_rectangle.x = x;
3112            g_clip_rectangle.y = y;
3113          rect.x = x;          g_clip_rectangle.width = cx;
3114          rect.y = y;          g_clip_rectangle.height = cy;
3115          rect.width = cx;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = cy;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
3116  }  }
3117    
3118  void  void
3119  ui_reset_clip(void)  ui_reset_clip(void)
3120  {  {
3121          XRectangle rect;          g_clip_rectangle.x = 0;
3122            g_clip_rectangle.y = 0;
3123          rect.x = 0;          g_clip_rectangle.width = g_width;
3124          rect.y = 0;          g_clip_rectangle.height = g_height;
3125          rect.width = g_width;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = g_height;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
3126  }  }
3127    
3128  void  void
# Line 1591  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 2: /* Hatch */                  case 2: /* Hatch */
# Line 1602  ui_patblt(uint8 opcode, Line 3174  ui_patblt(uint8 opcode,
3174                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3175                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
3176                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3177                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3178                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
3179                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3180                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
3181                          break;                          break;
3182    
3183                  case 3: /* Pattern */                  case 3: /* Pattern */
3184                          for (i = 0; i != 8; i++)                          if (brush->bd == 0)     /* rdp4 brush */
3185                                  ipattern[7 - i] = brush->pattern[i];                          {
3186                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                                  for (i = 0; i != 8; i++)
3187                                            ipattern[7 - i] = brush->pattern[i];
3188                          SET_FOREGROUND(bgcolour);                                  fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3189                          SET_BACKGROUND(fgcolour);                                  SET_FOREGROUND(bgcolour);
3190                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                                  SET_BACKGROUND(fgcolour);
3191                          XSetStipple(g_display, g_gc, fill);                                  XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3192                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                                  XSetStipple(g_display, g_gc, fill);
3193                                    XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3194                          FILL_RECTANGLE(x, y, cx, cy);                                  FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3195                                    XSetFillStyle(g_display, g_gc, FillSolid);
3196                          XSetFillStyle(g_display, g_gc, FillSolid);                                  XSetTSOrigin(g_display, g_gc, 0, 0);
3197                          XSetTSOrigin(g_display, g_gc, 0, 0);                                  ui_destroy_glyph((RD_HGLYPH) fill);
3198                          ui_destroy_glyph((HGLYPH) fill);                          }
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 1631  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 1639  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);
         XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
3244          if (g_ownbackstore)          if (g_ownbackstore)
3245            {
3246                    XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3247                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3248                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
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(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3269            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3270                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
3271                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3272          if (g_ownbackstore)          if (g_ownbackstore)
3273                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3274          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1660  ui_memblt(uint8 opcode, Line 3277  ui_memblt(uint8 opcode,
3277  void  void
3278  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3279            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3280            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3281            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3282  {  {
3283          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1698  ui_line(uint8 opcode, Line 3315  ui_line(uint8 opcode,
3315          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3316          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3317          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3318            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3319                                                startx - sw->xoffset, starty - sw->yoffset,
3320                                                endx - sw->xoffset, endy - sw->yoffset));
3321          if (g_ownbackstore)          if (g_ownbackstore)
3322                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3323          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1712  ui_rect( Line 3332  ui_rect(
3332          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
3333  }  }
3334    
3335    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 */  /* warning, this function only draws on wnd or backstore, not both */
3539  void  void
3540  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3541                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3542                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3543                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3544  {  {
3545          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1736  ui_draw_glyph(int mixmode, Line 3559  ui_draw_glyph(int mixmode,
3559  {\  {\
3560    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3561    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3562      {\
3563        xyoffset = ttext[++idx];\
3564        if ((xyoffset & 0x80))\
3565      {\      {\
3566        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3567        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[idx+1] | (ttext[idx+2] << 8);\  
           else\  
             x += ttext[idx+1] | (ttext[idx+2] << 8);\  
           idx += 2;\  
         }\  
3568        else\        else\
3569          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3570            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3571      }\      }\
3572    if (glyph != NULL)\      else\
3573      {\      {\
3574        ui_draw_glyph (mixmode, x + glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3575                       y + glyph->baseline,\          y += xyoffset;\
3576                       glyph->width, glyph->height,\        else\
3577                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
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 bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3596               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, j, xyoffset;          int i, j, xyoffset, x1, y1;
3602          DATABLOB *entry;          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_BACKSTORE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
# Line 1786  ui_draw_text(uint8 font, uint8 flags, in Line 3618  ui_draw_text(uint8 font, uint8 flags, in
3618                  FILL_RECTANGLE_BACKSTORE(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;)          for (i = 0; i < length;)
3627          {          {
3628                  switch (text[i])                  switch (text[i])
3629                  {                  {
3630                          case 0xff:                          case 0xff:
3631                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3632                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3633                                  {                                  {
3634                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3635                                          exit(1);                                          for (j = 0; j < length; j++)
3636                                                    fprintf(stderr, "%02x ", text[j]);
3637                                            fprintf(stderr, "\n");
3638                                            i = length = 0;
3639                                            break;
3640                                  }                                  }
3641                                    cache_put_text(text[i + 1], text, text[i + 2]);
3642                                    i += 3;
3643                                    length -= i;
3644                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3645                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3646                                  i = 0;                                  i = 0;
3647                                  break;                                  break;
3648    
3649                          case 0xfe:                          case 0xfe:
3650                                    /* At least one byte needs to follow */
3651                                    if (i + 2 > length)
3652                                    {
3653                                            warning("Skipping short 0xfe command:");
3654                                            for (j = 0; j < length; j++)
3655                                                    fprintf(stderr, "%02x ", text[j]);
3656                                            fprintf(stderr, "\n");
3657                                            i = length = 0;
3658                                            break;
3659                                    }
3660                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3661                                  if (entry != NULL)                                  if (entry->data != NULL)
3662                                  {                                  {
3663                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3664                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3665                                          {                                          {
3666                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3667                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 1836  ui_draw_text(uint8 font, uint8 flags, in Line 3687  ui_draw_text(uint8 font, uint8 flags, in
3687                                  break;                                  break;
3688                  }                  }
3689          }          }
3690    
3691            XSetFillStyle(g_display, g_gc, FillSolid);
3692    
3693          if (g_ownbackstore)          if (g_ownbackstore)
3694          {          {
3695                  if (boxcx > 1)                  if (boxcx > 1)
3696                    {
3697                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3698                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3699                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3700                                                    (g_display, g_backstore, sw->wnd, g_gc,
3701                                                     boxx, boxy,
3702                                                     boxcx, boxcy,
3703                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3704                    }
3705                  else                  else
3706                    {
3707                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3708                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3709                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3710                                                    (g_display, g_backstore, sw->wnd, g_gc,
3711                                                     clipx, clipy,
3712                                                     clipcx, clipcy, clipx - sw->xoffset,
3713                                                     clipy - sw->yoffset));
3714                    }
3715          }          }
3716  }  }
3717    
# Line 1856  ui_desktop_save(uint32 offset, int x, in Line 3724  ui_desktop_save(uint32 offset, int x, in
3724          if (g_ownbackstore)          if (g_ownbackstore)
3725          {          {
3726                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3727                    exit_if_null(image);
3728          }          }
3729          else          else
3730          {          {
3731                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3732                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3733                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3734                    exit_if_null(image);
3735                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3736          }          }
3737    
# Line 1883  ui_desktop_restore(uint32 offset, int x, Line 3753  ui_desktop_restore(uint32 offset, int x,
3753                  return;                  return;
3754    
3755          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3756                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3757    
3758          if (g_ownbackstore)          if (g_ownbackstore)
3759          {          {
3760                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3761                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3762                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3763                                            (g_display, g_backstore, sw->wnd, g_gc,
3764                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3765          }          }
3766          else          else
3767          {          {
3768                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3769                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3770                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3771                                             x - sw->xoffset, y - sw->yoffset));
3772          }          }
3773    
3774          XFree(image);          XFree(image);
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.498  
changed lines
  Added in v.1508

  ViewVC Help
Powered by ViewVC 1.1.26