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

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

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

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

Legend:
Removed from v.69  
changed lines
  Added in v.1463

  ViewVC Help
Powered by ViewVC 1.1.26