/[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 66 by astrand, Thu Jul 18 18:28:12 2002 UTC revision 1461 by astrand, Wed Mar 26 17:16:32 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    /* 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          return colour;  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                    while (out < end)
901                    {
902                            value = (uint16) g_colmap[*(data++)];
903                            BOUT16(out, value);
904                    }
905            }
906            else
907          {          {
908                  error("Failed to open input method\n");                  while (out < end)
909                    {
910                            value = (uint16) g_colmap[*(data++)];
911                            LOUT16(out, value);
912                    }
913          }          }
914    }
915    
916    /* 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 (IM != NULL)          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          /* For correct Multi_key/Compose processing, I guess.  static void
974             It seems to work alright anyway, though. */  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
975          if (IC != NULL)  {
976            uint16 pixel;
977            uint16 value;
978            PixelColour pc;
979    
980            if (g_xserver_be)
981            {
982                    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                  XDestroyIC(IC);                  /* *INDENT-OFF* */
1020                  if (IM != NULL)                  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                    while (out < end)
1033                    {
1034                            pixel = *(data++);
1035                            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                          XCloseIM(IM);                          pixel = *(data++);
1049                          IM = NULL;                          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          display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1596    
1597          if (display == NULL)          if (g_server_depth == -1)
1598          {          {
1599                  error("Failed to open display\n");                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1600            }
1601    
1602            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1603            if (pfm == NULL)
1604            {
1605                    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                            if (visual_info->depth > 24)
1659                            {
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          pfm = XListPixmapFormats(display, &i);          g_bpp = 0;
1740          if (pfm != NULL)          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_restack_test();
1923                    seamless_init();
1924            }
1925    
1926            DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1927    
1928            return True;
1929    }
1930    
1931    void
1932    ui_deinit(void)
1933    {
1934            while (g_seamless_windows)
1935            {
1936                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1937                    sw_remove_window(g_seamless_windows);
1938            }
1939    
1940            xclip_deinit();
1941    
1942            if (g_IM != NULL)
1943                    XCloseIM(g_IM);
1944    
1945            if (g_null_cursor != NULL)
1946                    ui_destroy_cursor(g_null_cursor);
1947    
1948            XFreeModifiermap(g_mod_map);
1949    
1950            if (g_ownbackstore)
1951                    XFreePixmap(g_display, g_backstore);
1952    
1953            XFreeGC(g_display, g_gc);
1954            XCloseDisplay(g_display);
1955            g_display = NULL;
1956    }
1957    
1958    
1959    static void
1960    get_window_attribs(XSetWindowAttributes * attribs)
1961    {
1962            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1963            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1964            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1965            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1966            attribs->override_redirect = g_fullscreen;
1967            attribs->colormap = g_xcolmap;
1968    }
1969    
1970    static void
1971    get_input_mask(long *input_mask)
1972    {
1973            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1974                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1975    
1976            if (g_sendmotion)
1977                    *input_mask |= PointerMotionMask;
1978            if (g_ownbackstore)
1979                    *input_mask |= ExposureMask;
1980            if (g_fullscreen || g_grab_keyboard)
1981                    *input_mask |= EnterWindowMask;
1982            if (g_grab_keyboard)
1983                    *input_mask |= LeaveWindowMask;
1984    }
1985    
1986    RD_BOOL
1987    ui_create_window(void)
1988    {
1989            uint8 null_pointer_mask[1] = { 0x80 };
1990            uint8 null_pointer_data[24] = { 0x00 };
1991    
1992            XSetWindowAttributes attribs;
1993            XClassHint *classhints;
1994            XSizeHints *sizehints;
1995            int wndwidth, wndheight;
1996            long input_mask, ic_input_mask;
1997            XEvent xevent;
1998    
1999            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
2000            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
2001    
2002            /* Handle -x-y portion of geometry string */
2003            if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
2004                    g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
2005            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
2006                    g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
2007    
2008            get_window_attribs(&attribs);
2009    
2010            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
2011                                  wndheight, 0, g_depth, InputOutput, g_visual,
2012                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
2013                                  CWBorderPixel, &attribs);
2014    
2015            if (g_gc == NULL)
2016          {          {
2017                  attribs.override_redirect = False;                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2018                    ui_reset_clip();
2019          }          }
2020    
2021          width = (width + 3) & ~3;       /* make width a multiple of 32 bits */          if (g_create_bitmap_gc == NULL)
2022                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2023    
2024          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          if ((g_ownbackstore) && (g_backstore == 0))
2025                              0, 0, width, height, 0, CopyFromParent,          {
2026                              InputOutput, CopyFromParent,                  g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2027                              CWBackingStore | CWBackPixel | CWOverrideRedirect,  
2028                              &attribs);                  /* clear to prevent rubbish being exposed at startup */
2029                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
2030                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
2031            }
2032    
2033          XStoreName(display, wnd, title);          XStoreName(g_display, g_wnd, g_title);
2034            ewmh_set_wm_name(g_wnd, g_title);
2035    
2036            if (g_hide_decorations)
2037                    mwm_hide_decorations(g_wnd);
2038    
2039          classhints = XAllocClassHint();          classhints = XAllocClassHint();
2040          if (classhints != NULL)          if (classhints != NULL)
2041          {          {
2042                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = classhints->res_class = "rdesktop";
2043                  XSetClassHint(display, wnd, classhints);                  XSetClassHint(g_display, g_wnd, classhints);
2044                  XFree(classhints);                  XFree(classhints);
2045          }          }
2046    
# Line 335  ui_create_window(char *title) Line 2048  ui_create_window(char *title)
2048          if (sizehints)          if (sizehints)
2049          {          {
2050                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
2051                  sizehints->min_width = sizehints->max_width = width;                  if (g_pos)
2052                  sizehints->min_height = sizehints->max_height = height;                          sizehints->flags |= PPosition;
2053                  XSetWMNormalHints(display, wnd, sizehints);                  sizehints->min_width = sizehints->max_width = g_width;
2054                    sizehints->min_height = sizehints->max_height = g_height;
2055                    XSetWMNormalHints(g_display, g_wnd, sizehints);
2056                  XFree(sizehints);                  XFree(sizehints);
2057          }          }
2058    
2059          xkeymap_init2();          if (g_embed_wnd)
2060            {
2061                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2062            }
2063    
2064          input_mask =          get_input_mask(&input_mask);
                 KeyPressMask | KeyReleaseMask | ButtonPressMask |  
                 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;  
         if (sendmotion)  
                 input_mask |= PointerMotionMask;  
2065    
2066          if (ownbackstore)          if (g_IM != NULL)
2067                  input_mask |= ExposureMask;          {
2068                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
2069                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
2070    
2071          filtered_events = init_inputmethod();                  if ((g_IC != NULL)
2072                        && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
2073                            input_mask |= ic_input_mask;
2074            }
2075    
2076          XSelectInput(display, wnd, input_mask | filtered_events);          XSelectInput(g_display, g_wnd, input_mask);
2077            XMapWindow(g_display, g_wnd);
2078    
2079          gc = XCreateGC(display, wnd, 0, NULL);          /* wait for VisibilityNotify */
2080            do
2081            {
2082                    XMaskEvent(g_display, VisibilityChangeMask, &xevent);
2083            }
2084            while (xevent.type != VisibilityNotify);
2085            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
2086    
2087          if (ownbackstore)          g_focused = False;
2088                  backstore = XCreatePixmap(display, wnd, width, height, depth);          g_mouse_in_wnd = False;
2089    
2090          XMapWindow(display, wnd);          /* handle the WM_DELETE_WINDOW protocol */
2091            g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
2092            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
2093            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
2094    
2095            /* create invisible 1x1 cursor to be used as null cursor */
2096            if (g_null_cursor == NULL)
2097                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
2098    
2099          return True;          return True;
2100  }  }
2101    
2102  void  void
2103  ui_destroy_window()  ui_resize_window()
2104  {  {
2105          if (ownbackstore)          XSizeHints *sizehints;
2106                  XFreePixmap(display, backstore);          Pixmap bs;
2107    
2108          XFreeGC(display, gc);          sizehints = XAllocSizeHints();
2109            if (sizehints)
2110            {
2111                    sizehints->flags = PMinSize | PMaxSize;
2112                    sizehints->min_width = sizehints->max_width = g_width;
2113                    sizehints->min_height = sizehints->max_height = g_height;
2114                    XSetWMNormalHints(g_display, g_wnd, sizehints);
2115                    XFree(sizehints);
2116            }
2117    
2118          close_inputmethod();          if (!(g_fullscreen || g_embed_wnd))
2119            {
2120                    XResizeWindow(g_display, g_wnd, g_width, g_height);
2121            }
2122    
2123            /* create new backstore pixmap */
2124            if (g_backstore != 0)
2125            {
2126                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2127                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
2128                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
2129                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
2130                    XFreePixmap(g_display, g_backstore);
2131                    g_backstore = bs;
2132            }
2133    }
2134    
2135    void
2136    ui_destroy_window(void)
2137    {
2138            if (g_IC != NULL)
2139                    XDestroyIC(g_IC);
2140    
2141            XDestroyWindow(g_display, g_wnd);
2142    }
2143    
2144          XDestroyWindow(display, wnd);  void
2145          XCloseDisplay(display);  xwin_toggle_fullscreen(void)
2146          display = NULL;  {
2147            Pixmap contents = 0;
2148    
2149            if (g_seamless_active)
2150                    /* Turn off SeamlessRDP mode */
2151                    ui_seamless_toggle();
2152    
2153            if (!g_ownbackstore)
2154            {
2155                    /* need to save contents of window */
2156                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2157                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
2158            }
2159    
2160            ui_destroy_window();
2161            g_fullscreen = !g_fullscreen;
2162            ui_create_window();
2163    
2164            XDefineCursor(g_display, g_wnd, g_current_cursor);
2165    
2166            if (!g_ownbackstore)
2167            {
2168                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
2169                    XFreePixmap(g_display, contents);
2170            }
2171  }  }
2172    
2173  static void  static void
2174  xwin_process_events()  handle_button_event(XEvent xevent, RD_BOOL down)
2175  {  {
2176          XEvent xevent;          uint16 button, flags = 0;
2177            g_last_gesturetime = xevent.xbutton.time;
2178            /* Reverse the pointer button mapping, e.g. in the case of
2179               "left-handed mouse mode"; the RDP session expects to
2180               receive physical buttons (true in mstsc as well) and
2181               logical button behavior depends on the remote desktop's own
2182               mouse settings */
2183            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
2184            button = xkeymap_translate_button(xevent.xbutton.button);
2185            if (button == 0)
2186                    return;
2187    
2188            if (down)
2189                    flags = MOUSE_FLAG_DOWN;
2190    
2191            /* Stop moving window when button is released, regardless of cursor position */
2192            if (g_moving_wnd && (xevent.type == ButtonRelease))
2193                    g_moving_wnd = False;
2194    
2195            /* If win_button_size is nonzero, enable single app mode */
2196            if (xevent.xbutton.y < g_win_button_size)
2197            {
2198                    /*  Check from right to left: */
2199                    if (xevent.xbutton.x >= g_width - g_win_button_size)
2200                    {
2201                            /* The close button, continue */
2202                            ;
2203                    }
2204                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
2205                    {
2206                            /* The maximize/restore button. Do not send to
2207                               server.  It might be a good idea to change the
2208                               cursor or give some other visible indication
2209                               that rdesktop inhibited this click */
2210                            if (xevent.type == ButtonPress)
2211                                    return;
2212                    }
2213                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
2214                    {
2215                            /* The minimize button. Iconify window. */
2216                            if (xevent.type == ButtonRelease)
2217                            {
2218                                    /* Release the mouse button outside the minimize button, to prevent the
2219                                       actual minimazation to happen */
2220                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
2221                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
2222                                    return;
2223                            }
2224                    }
2225                    else if (xevent.xbutton.x <= g_win_button_size)
2226                    {
2227                            /* The system menu. Ignore. */
2228                            if (xevent.type == ButtonPress)
2229                                    return;
2230                    }
2231                    else
2232                    {
2233                            /* The title bar. */
2234                            if (xevent.type == ButtonPress)
2235                            {
2236                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
2237                                    {
2238                                            g_moving_wnd = True;
2239                                            g_move_x_offset = xevent.xbutton.x;
2240                                            g_move_y_offset = xevent.xbutton.y;
2241                                    }
2242                                    return;
2243                            }
2244                    }
2245            }
2246    
2247            if (xevent.xmotion.window == g_wnd)
2248            {
2249                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2250                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
2251            }
2252            else
2253            {
2254                    /* SeamlessRDP */
2255                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
2256                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
2257            }
2258    }
2259    
2260    
2261    /* Process events in Xlib queue
2262       Returns 0 after user quit, 1 otherwise */
2263    static int
2264    xwin_process_events(void)
2265    {
2266            XEvent xevent;
2267          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
2268          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
         char *ksname = NULL;  
2269          char str[256];          char str[256];
2270          Status status;          Status status;
2271            int events = 0;
2272            seamless_window *sw;
2273    
2274          /* 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))  
2275          {          {
2276                  if (xevent.xmapping.request == MappingKeyboard                  XNextEvent(g_display, &xevent);
                     || xevent.xmapping.request == MappingModifier)  
                         XRefreshKeyboardMapping(&xevent.xmapping);  
         }  
2277    
2278          while (XCheckMaskEvent(display, ~0, &xevent))                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
         {  
                 if (XFilterEvent(&xevent, None) == True)  
2279                  {                  {
2280                          DEBUG_KBD("Filtering event\n");                          DEBUG_KBD(("Filtering event\n"));
2281                          continue;                          continue;
2282                  }                  }
2283    
                 ev_time = time(NULL);  
                 flags = 0;  
   
2284                  switch (xevent.type)                  switch (xevent.type)
2285                  {                  {
2286                            case VisibilityNotify:
2287                                    if (xevent.xvisibility.window == g_wnd)
2288                                            g_Unobscured =
2289                                                    xevent.xvisibility.state == VisibilityUnobscured;
2290    
2291                                    break;
2292                            case ClientMessage:
2293                                    /* the window manager told us to quit */
2294                                    if ((xevent.xclient.message_type == g_protocol_atom)
2295                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2296                                    {
2297                                            /* When killing a seamless window, close the window on the
2298                                               serverside instead of terminating rdesktop */
2299                                            sw = sw_get_window_by_wnd(xevent.xclient.window);
2300                                            if (!sw)
2301                                                    /* Otherwise, quit */
2302                                                    return 0;
2303                                            /* send seamless destroy process message */
2304                                            seamless_send_destroy(sw->id);
2305                                    }
2306                                    break;
2307    
2308                          case KeyPress:                          case KeyPress:
2309                                  if (IC != NULL)                                  g_last_gesturetime = xevent.xkey.time;
2310                                    if (g_IC != NULL)
2311                                          /* Multi_key compatible version */                                          /* Multi_key compatible version */
2312                                  {                                  {
2313                                          XmbLookupString(IC,                                          XmbLookupString(g_IC,
2314                                                          (XKeyPressedEvent *) &                                                          &xevent.xkey, str, sizeof(str), &keysym,
                                                         xevent, str,  
                                                         sizeof(str), &keysym,  
2315                                                          &status);                                                          &status);
2316                                          if (!                                          if (!((status == XLookupKeySym) || (status == XLookupBoth)))
                                             ((status == XLookupKeySym)  
                                              || (status == XLookupBoth)))  
2317                                          {                                          {
2318                                                  error("XmbLookupString failed with status 0x%x\n", status);                                                  error("XmbLookupString failed with status 0x%x\n",
2319                                                          status);
2320                                                  break;                                                  break;
2321                                          }                                          }
2322                                  }                                  }
2323                                  else                                  else
2324                                  {                                  {
2325                                          /* Plain old XLookupString */                                          /* Plain old XLookupString */
2326                                          DEBUG_KBD                                          DEBUG_KBD(("\nNo input context, using XLookupString\n"));
                                                 ("No input context, using XLookupString\n");  
2327                                          XLookupString((XKeyEvent *) & xevent,                                          XLookupString((XKeyEvent *) & xevent,
2328                                                        str, sizeof(str),                                                        str, sizeof(str), &keysym, NULL);
                                                       &keysym, NULL);  
2329                                  }                                  }
2330    
2331                                  ksname = get_ksname(keysym);                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2332                                  DEBUG_KBD                                             get_ksname(keysym)));
                                         ("\nKeyPress for (keysym 0x%lx, %s)\n",  
                                          keysym, ksname);  
2333    
2334                                  if (inhibit_key(keysym))                                  ev_time = time(NULL);
2335                                  {                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
                                         DEBUG_KBD("Inhibiting key\n");  
2336                                          break;                                          break;
                                 }  
   
                                 tr = xkeymap_translate_key(keysym,  
                                                            xevent.xkey.  
                                                            keycode);  
                                 ensure_remote_modifiers(ev_time, tr);  
2337    
2338                                  if (tr.scancode == 0)                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2339                                          break;                                                    ev_time, True, 0);
   
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS,  
                                                   tr.scancode);  
2340                                  break;                                  break;
2341    
2342                          case KeyRelease:                          case KeyRelease:
2343                                    g_last_gesturetime = xevent.xkey.time;
2344                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2345                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2346    
2347                                  ksname = get_ksname(keysym);                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2348                                  DEBUG_KBD                                             get_ksname(keysym)));
                                         ("\nKeyRelease for (keysym 0x%lx, %s)\n",  
                                          keysym, ksname);  
2349    
2350                                  if (inhibit_key(keysym))                                  ev_time = time(NULL);
2351                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2352                                          break;                                          break;
2353    
2354                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2355                                                             xevent.xkey.                                                    ev_time, False, 0);
2356                                                             keycode);                                  break;
2357    
2358                                  if (tr.scancode == 0)                          case ButtonPress:
2359                                    handle_button_event(xevent, True);
2360                                    break;
2361    
2362                            case ButtonRelease:
2363                                    handle_button_event(xevent, False);
2364                                    break;
2365    
2366                            case MotionNotify:
2367                                    if (g_moving_wnd)
2368                                    {
2369                                            XMoveWindow(g_display, g_wnd,
2370                                                        xevent.xmotion.x_root - g_move_x_offset,
2371                                                        xevent.xmotion.y_root - g_move_y_offset);
2372                                          break;                                          break;
2373                                    }
2374    
2375                                    if (g_fullscreen && !g_focused)
2376                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2377                                                           CurrentTime);
2378    
2379                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE,                                  if (xevent.xmotion.window == g_wnd)
2380                                                    tr.scancode);                                  {
2381                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2382                                                           xevent.xmotion.x, xevent.xmotion.y);
2383                                    }
2384                                    else
2385                                    {
2386                                            /* SeamlessRDP */
2387                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2388                                                           xevent.xmotion.x_root,
2389                                                           xevent.xmotion.y_root);
2390                                    }
2391                                  break;                                  break;
2392    
2393                          case ButtonPress:                          case FocusIn:
2394                                  flags = MOUSE_FLAG_DOWN;                                  if (xevent.xfocus.mode == NotifyGrab)
2395                                  /* fall through */                                          break;
2396                                    g_focused = True;
2397                                    reset_modifier_keys();
2398                                    if (g_grab_keyboard && g_mouse_in_wnd)
2399                                            XGrabKeyboard(g_display, g_wnd, True,
2400                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2401    
2402                          case ButtonRelease:                                  sw = sw_get_window_by_wnd(xevent.xfocus.window);
2403                                  button = xkeymap_translate_button(xevent.                                  if (!sw)
                                                                   xbutton.  
                                                                   button);  
                                 if (button == 0)  
2404                                          break;                                          break;
2405    
2406                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  /* Menu windows are real X11 windows,
2407                                                 flags | button,                                     with focus. When such a window is
2408                                                 xevent.xbutton.x,                                     destroyed, focus is reverted to the
2409                                                 xevent.xbutton.y);                                     main application window, which
2410                                       would cause us to send FOCUS. This
2411                                       breaks window switching in, say,
2412                                       Seamonkey. We shouldn't need to
2413                                       send FOCUS: Windows should also
2414                                       revert focus to some other window
2415                                       when the menu window is
2416                                       destroyed. So, we only send FOCUS
2417                                       if the previous focus window still
2418                                       exists. */
2419                                    if (sw->id != g_seamless_focused)
2420                                    {
2421    
2422                                            if (sw_window_exists(g_seamless_focused))
2423                                                    seamless_send_focus(sw->id, 0);
2424                                            g_seamless_focused = sw->id;
2425                                    }
2426                                  break;                                  break;
2427    
2428                          case MotionNotify:                          case FocusOut:
2429                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (xevent.xfocus.mode == NotifyUngrab)
2430                                                 MOUSE_FLAG_MOVE,                                          break;
2431                                                 xevent.xmotion.x,                                  g_focused = False;
2432                                                 xevent.xmotion.y);                                  if (xevent.xfocus.mode == NotifyWhileGrabbed)
2433                                            XUngrabKeyboard(g_display, CurrentTime);
2434                                  break;                                  break;
2435    
2436                          case EnterNotify:                          case EnterNotify:
2437                                  XGrabKeyboard(display, wnd, True,                                  /* we only register for this event when in fullscreen mode */
2438                                                GrabModeAsync, GrabModeAsync,                                  /* or grab_keyboard */
2439                                                CurrentTime);                                  g_mouse_in_wnd = True;
2440                                    if (g_fullscreen)
2441                                    {
2442                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2443                                                           CurrentTime);
2444                                            break;
2445                                    }
2446                                    if (g_focused)
2447                                            XGrabKeyboard(g_display, g_wnd, True,
2448                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2449                                  break;                                  break;
2450    
2451                          case LeaveNotify:                          case LeaveNotify:
2452                                  XUngrabKeyboard(display, CurrentTime);                                  /* we only register for this event when grab_keyboard */
2453                                    g_mouse_in_wnd = False;
2454                                    XUngrabKeyboard(g_display, CurrentTime);
2455                                  break;                                  break;
2456    
2457                          case Expose:                          case Expose:
2458                                  XCopyArea(display, backstore, wnd, gc,                                  if (xevent.xexpose.window == g_wnd)
2459                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2460                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2461                                            xevent.xexpose.height,                                                    g_gc,
2462                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2463                                                      xevent.xexpose.width, xevent.xexpose.height,
2464                                                      xevent.xexpose.x, xevent.xexpose.y);
2465                                    }
2466                                    else
2467                                    {
2468                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2469                                            if (!sw)
2470                                                    break;
2471                                            XCopyArea(g_display, g_backstore,
2472                                                      xevent.xexpose.window, g_gc,
2473                                                      xevent.xexpose.x + sw->xoffset,
2474                                                      xevent.xexpose.y + sw->yoffset,
2475                                                      xevent.xexpose.width,
2476                                                      xevent.xexpose.height, xevent.xexpose.x,
2477                                                      xevent.xexpose.y);
2478                                    }
2479    
2480                                    break;
2481    
2482                            case MappingNotify:
2483                                    /* Refresh keyboard mapping if it has changed. This is important for
2484                                       Xvnc, since it allocates keycodes dynamically */
2485                                    if (xevent.xmapping.request == MappingKeyboard
2486                                        || xevent.xmapping.request == MappingModifier)
2487                                            XRefreshKeyboardMapping(&xevent.xmapping);
2488    
2489                                    if (xevent.xmapping.request == MappingModifier)
2490                                    {
2491                                            XFreeModifiermap(g_mod_map);
2492                                            g_mod_map = XGetModifierMapping(g_display);
2493                                    }
2494    
2495                                    if (xevent.xmapping.request == MappingPointer)
2496                                    {
2497                                            xwin_refresh_pointer_map();
2498                                    }
2499    
2500                                    break;
2501    
2502                                    /* clipboard stuff */
2503                            case SelectionNotify:
2504                                    xclip_handle_SelectionNotify(&xevent.xselection);
2505                                    break;
2506                            case SelectionRequest:
2507                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2508                                    break;
2509                            case SelectionClear:
2510                                    xclip_handle_SelectionClear();
2511                                    break;
2512                            case PropertyNotify:
2513                                    xclip_handle_PropertyNotify(&xevent.xproperty);
2514                                    if (xevent.xproperty.window == g_wnd)
2515                                            break;
2516                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2517                                            break;
2518    
2519                                    /* seamless */
2520                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2521                                    if (!sw)
2522                                            break;
2523    
2524                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2525                                        && (xevent.xproperty.state == PropertyNewValue))
2526                                    {
2527                                            sw->state = ewmh_get_window_state(sw->wnd);
2528                                            seamless_send_state(sw->id, sw->state, 0);
2529                                    }
2530    
2531                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2532                                        && (xevent.xproperty.state == PropertyNewValue))
2533                                    {
2534                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2535                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2536                                    }
2537    
2538                                    break;
2539                            case MapNotify:
2540                                    if (!g_seamless_active)
2541                                            rdp_send_client_window_status(1);
2542                                    break;
2543                            case UnmapNotify:
2544                                    if (!g_seamless_active)
2545                                            rdp_send_client_window_status(0);
2546                                    break;
2547                            case ConfigureNotify:
2548                                    if (!g_seamless_active)
2549                                            break;
2550    
2551                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2552                                    if (!sw)
2553                                            break;
2554    
2555                                    gettimeofday(sw->position_timer, NULL);
2556                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2557                                        1000000)
2558                                    {
2559                                            sw->position_timer->tv_usec +=
2560                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2561                                            sw->position_timer->tv_sec += 1;
2562                                    }
2563                                    else
2564                                    {
2565                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2566                                    }
2567    
2568                                    sw_handle_restack(sw);
2569                                  break;                                  break;
2570                  }                  }
2571          }          }
2572            /* Keep going */
2573            return 1;
2574  }  }
2575    
2576  void  /* Returns 0 after user quit, 1 otherwise */
2577    int
2578  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2579  {  {
2580          int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;          int n;
2581          fd_set rfds;          fd_set rfds, wfds;
2582            struct timeval tv;
2583          FD_ZERO(&rfds);          RD_BOOL s_timeout = False;
2584    
2585          while (True)          while (True)
2586          {          {
2587                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2588                    /* Process any events already waiting */
2589                    if (!xwin_process_events())
2590                            /* User quit */
2591                            return 0;
2592    
2593                    if (g_seamless_active)
2594                            sw_check_timers();
2595    
2596                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2597                    FD_ZERO(&wfds);
2598                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2599                  if (display != NULL)                  FD_SET(g_x_socket, &rfds);
2600                  {  
2601                          FD_SET(x_socket, &rfds);                  /* default timeout */
2602                          XFlush(display);                  tv.tv_sec = 60;
2603                  }                  tv.tv_usec = 0;
2604    
2605                  switch (select(n, &rfds, NULL, NULL, NULL))  #ifdef WITH_RDPSND
2606                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2607    #endif
2608    
2609                    /* add redirection handles */
2610                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2611                    seamless_select_timeout(&tv);
2612    
2613                    n++;
2614    
2615                    switch (select(n, &rfds, &wfds, NULL, &tv))
2616                  {                  {
2617                          case -1:                          case -1:
2618                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2619    
2620                          case 0:                          case 0:
2621    #ifdef WITH_RDPSND
2622                                    rdpsnd_check_fds(&rfds, &wfds);
2623    #endif
2624    
2625                                    /* Abort serial read calls */
2626                                    if (s_timeout)
2627                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2628                                  continue;                                  continue;
2629                  }                  }
2630    
2631                  if (FD_ISSET(x_socket, &rfds))  #ifdef WITH_RDPSND
2632                          xwin_process_events();                  rdpsnd_check_fds(&rfds, &wfds);
2633    #endif
2634    
2635                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2636    
2637                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2638                          return;                          return 1;
2639    
2640          }          }
2641  }  }
2642    
2643  void  void
2644  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
2645  {  {
2646          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2647  }  }
2648    
2649  HBITMAP  RD_HBITMAP
2650  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2651  {  {
2652          XImage *image;          XImage *image;
2653          Pixmap bitmap;          Pixmap bitmap;
2654          uint8 *tdata;          uint8 *tdata;
2655            int bitmap_pad;
2656    
2657            if (g_server_depth == 8)
2658            {
2659                    bitmap_pad = 8;
2660            }
2661            else
2662            {
2663                    bitmap_pad = g_bpp;
2664    
2665                    if (g_bpp == 24)
2666                            bitmap_pad = 32;
2667            }
2668    
2669          tdata = (owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2670          bitmap = XCreatePixmap(display, wnd, width, height, depth);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2671          image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2672                               height, 8, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2673    
2674          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);
2675    
2676          XFree(image);          XFree(image);
2677          if (!owncolmap)          if (tdata != data)
2678                  xfree(tdata);                  xfree(tdata);
2679          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2680  }  }
2681    
2682  void  void
2683  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)  
2684  {  {
2685          XImage *image;          XImage *image;
2686          uint8 *tdata;          uint8 *tdata;
2687            int bitmap_pad;
2688    
2689          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2690          image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width,          {
2691                               height, 8, 0);                  bitmap_pad = 8;
2692            }
2693            else
2694            {
2695                    bitmap_pad = g_bpp;
2696    
2697                    if (g_bpp == 24)
2698                            bitmap_pad = 32;
2699            }
2700    
2701            tdata = (g_owncolmap ? data : translate_image(width, height, data));
2702            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2703                                 (char *) tdata, width, height, bitmap_pad, 0);
2704    
2705          if (ownbackstore)          if (g_ownbackstore)
2706          {          {
2707                  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);
2708                  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);
2709                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2710                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2711                                             x - sw->xoffset, y - sw->yoffset));
2712          }          }
2713          else          else
2714          {          {
2715                  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);
2716                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2717                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2718                                             x - sw->xoffset, y - sw->yoffset));
2719          }          }
2720    
2721          XFree(image);          XFree(image);
2722          if (!owncolmap)          if (tdata != data)
2723                  xfree(tdata);                  xfree(tdata);
2724  }  }
2725    
2726  void  void
2727  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2728  {  {
2729          XFreePixmap(display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2730  }  }
2731    
2732  HGLYPH  RD_HGLYPH
2733  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2734  {  {
2735          XImage *image;          XImage *image;
2736          Pixmap bitmap;          Pixmap bitmap;
2737          int scanline;          int scanline;
         GC gc;  
2738    
2739          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2740    
2741          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2742          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2743                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2744    
2745          image = XCreateImage(display, visual, 1, ZPixmap, 0, data, width,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2746                               height, 8, scanline);                               width, height, 8, scanline);
2747          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2748          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2749          XInitImage(image);          XInitImage(image);
2750    
2751          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);
2752    
2753          XFree(image);          XFree(image);
2754          XFreeGC(display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH) bitmap;  
2755  }  }
2756    
2757  void  void
2758  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2759  {  {
2760          XFreePixmap(display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2761  }  }
2762    
2763  HCURSOR  RD_HCURSOR
2764  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,
2765                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2766  {  {
2767          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2768          XColor bg, fg;          XColor bg, fg;
2769          Cursor xcursor;          Cursor xcursor;
2770          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 674  ui_create_cursor(unsigned int x, unsigne Line 2776  ui_create_cursor(unsigned int x, unsigne
2776          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2777          offset = scanline * height;          offset = scanline * height;
2778    
2779          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
2780          memset(cursor, 0, offset);          memset(cursor, 0, offset);
2781    
2782          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
2783          memset(mask, 0, offset);          memset(mask, 0, offset);
2784    
2785          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 719  ui_create_cursor(unsigned int x, unsigne Line 2821  ui_create_cursor(unsigned int x, unsigne
2821          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2822    
2823          xcursor =          xcursor =
2824                  XCreatePixmapCursor(display, (Pixmap) cursorglyph,                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2825                                      (Pixmap) maskglyph, &fg, &bg, x, y);                                      (Pixmap) maskglyph, &fg, &bg, x, y);
2826    
2827          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
2828          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2829          xfree(mask);          xfree(mask);
2830          xfree(cursor);          xfree(cursor);
2831          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2832  }  }
2833    
2834  void  void
2835  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2836  {  {
2837          XDefineCursor(display, wnd, (Cursor) cursor);          g_current_cursor = (Cursor) cursor;
2838            XDefineCursor(g_display, g_wnd, g_current_cursor);
2839            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2840  }  }
2841    
2842  void  void
2843  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2844  {  {
2845          XFreeCursor(display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2846    }
2847    
2848    void
2849    ui_set_null_cursor(void)
2850    {
2851            ui_set_cursor(g_null_cursor);
2852  }  }
2853    
2854  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 747  ui_destroy_cursor(HCURSOR cursor) Line 2857  ui_destroy_cursor(HCURSOR cursor)
2857                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2858                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2859    
2860  HCOLOURMAP  
2861    RD_HCOLOURMAP
2862  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2863  {  {
2864          COLOURENTRY *entry;          COLOURENTRY *entry;
2865          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2866            if (!g_owncolmap)
         if (owncolmap)  
2867          {          {
2868                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2869                  Colormap map;                  XColor xentry;
2870                    XColor xc_cache[256];
2871                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
2872                    int colLookup = 256;
2873                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2874                  {                  {
2875                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2876                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
                         xentry->pixel = i;  
                         MAKE_XCOLOR(xentry, entry);  
                 }  
2877    
2878                  map = XCreateColormap(display, wnd, visual, AllocAll);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2879                  XStoreColors(display, map, xcolours, ncolours);                          {
2880                                    /* Allocation failed, find closest match. */
2881                                    int j = 256;
2882                                    int nMinDist = 3 * 256 * 256;
2883                                    long nDist = nMinDist;
2884    
2885                  xfree(xcolours);                                  /* only get the colors once */
2886                  return (HCOLOURMAP) map;                                  while (colLookup--)
2887                                    {
2888                                            xc_cache[colLookup].pixel = colLookup;
2889                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2890                                                    xc_cache[colLookup].blue = 0;
2891                                            xc_cache[colLookup].flags = 0;
2892                                            XQueryColor(g_display,
2893                                                        DefaultColormap(g_display,
2894                                                                        DefaultScreen(g_display)),
2895                                                        &xc_cache[colLookup]);
2896                                    }
2897                                    colLookup = 0;
2898    
2899                                    /* approximate the pixel */
2900                                    while (j--)
2901                                    {
2902                                            if (xc_cache[j].flags)
2903                                            {
2904                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2905                                                             (long) (xentry.red >> 8)) *
2906                                                            ((long) (xc_cache[j].red >> 8) -
2907                                                             (long) (xentry.red >> 8)) +
2908                                                            ((long) (xc_cache[j].green >> 8) -
2909                                                             (long) (xentry.green >> 8)) *
2910                                                            ((long) (xc_cache[j].green >> 8) -
2911                                                             (long) (xentry.green >> 8)) +
2912                                                            ((long) (xc_cache[j].blue >> 8) -
2913                                                             (long) (xentry.blue >> 8)) *
2914                                                            ((long) (xc_cache[j].blue >> 8) -
2915                                                             (long) (xentry.blue >> 8));
2916                                            }
2917                                            if (nDist < nMinDist)
2918                                            {
2919                                                    nMinDist = nDist;
2920                                                    xentry.pixel = j;
2921                                            }
2922                                    }
2923                            }
2924                            colour = xentry.pixel;
2925    
2926                            /* update our cache */
2927                            if (xentry.pixel < 256)
2928                            {
2929                                    xc_cache[xentry.pixel].red = xentry.red;
2930                                    xc_cache[xentry.pixel].green = xentry.green;
2931                                    xc_cache[xentry.pixel].blue = xentry.blue;
2932    
2933                            }
2934    
2935                            map[i] = colour;
2936                    }
2937                    return map;
2938          }          }
2939          else          else
2940          {          {
2941                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
2942                  XColor xentry;                  Colormap map;
                 uint32 colour;  
2943    
2944                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2945                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2946                  {                  {
2947                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2948                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
2949                            xentry->pixel = i;
2950                          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);  
2951                  }                  }
2952    
2953                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2954                    XStoreColors(g_display, map, xcolours, ncolours);
2955    
2956                    xfree(xcolours);
2957                    return (RD_HCOLOURMAP) map;
2958          }          }
2959  }  }
2960    
2961  void  void
2962  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2963  {  {
2964          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap) map);  
         else  
2965                  xfree(map);                  xfree(map);
2966            else
2967                    XFreeColormap(g_display, (Colormap) map);
2968  }  }
2969    
2970  void  void
2971  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2972  {  {
2973          if (owncolmap)          if (!g_owncolmap)
2974                  XSetWindowColormap(display, wnd, (Colormap) map);          {
2975                    if (g_colmap)
2976                            xfree(g_colmap);
2977    
2978                    g_colmap = (uint32 *) map;
2979            }
2980          else          else
2981                  colmap = map;          {
2982                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2983                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2984            }
2985  }  }
2986    
2987  void  void
2988  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2989  {  {
2990          XRectangle rect;          g_clip_rectangle.x = x;
2991            g_clip_rectangle.y = y;
2992          rect.x = x;          g_clip_rectangle.width = cx;
2993          rect.y = y;          g_clip_rectangle.height = cy;
2994          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);  
2995  }  }
2996    
2997  void  void
2998  ui_reset_clip()  ui_reset_clip(void)
2999  {  {
3000          XRectangle rect;          g_clip_rectangle.x = 0;
3001            g_clip_rectangle.y = 0;
3002          rect.x = 0;          g_clip_rectangle.width = g_width;
3003          rect.y = 0;          g_clip_rectangle.height = g_height;
3004          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);  
3005  }  }
3006    
3007  void  void
3008  ui_bell()  ui_bell(void)
3009  {  {
3010          XBell(display, 0);          XBell(g_display, 0);
3011  }  }
3012    
3013  void  void
# Line 854  ui_destblt(uint8 opcode, Line 3019  ui_destblt(uint8 opcode,
3019          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3020  }  }
3021    
3022    static uint8 hatch_patterns[] = {
3023            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
3024            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
3025            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
3026            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
3027            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
3028            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
3029    };
3030    
3031  void  void
3032  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
3033            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
# Line 868  ui_patblt(uint8 opcode, Line 3042  ui_patblt(uint8 opcode,
3042          {          {
3043                  case 0: /* Solid */                  case 0: /* Solid */
3044                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
3045                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3046                            break;
3047    
3048                    case 2: /* Hatch */
3049                            fill = (Pixmap) ui_create_glyph(8, 8,
3050                                                            hatch_patterns + brush->pattern[0] * 8);
3051                            SET_FOREGROUND(fgcolour);
3052                            SET_BACKGROUND(bgcolour);
3053                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3054                            XSetStipple(g_display, g_gc, fill);
3055                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3056                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3057                            XSetFillStyle(g_display, g_gc, FillSolid);
3058                            XSetTSOrigin(g_display, g_gc, 0, 0);
3059                            ui_destroy_glyph((RD_HGLYPH) fill);
3060                          break;                          break;
3061    
3062                  case 3: /* Pattern */                  case 3: /* Pattern */
3063                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
3064                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
3065                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
3066                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
3067                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
3068                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3069                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
3070                          XSetTSOrigin(display, gc, brush->xorigin,                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3071                                       brush->yorigin);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3072                            XSetFillStyle(g_display, g_gc, FillSolid);
3073                          FILL_RECTANGLE(x, y, cx, cy);                          XSetTSOrigin(g_display, g_gc, 0, 0);
3074                            ui_destroy_glyph((RD_HGLYPH) fill);
                         XSetFillStyle(display, gc, FillSolid);  
                         ui_destroy_glyph((HGLYPH) fill);  
3075                          break;                          break;
3076    
3077                  default:                  default:
# Line 894  ui_patblt(uint8 opcode, Line 3079  ui_patblt(uint8 opcode,
3079          }          }
3080    
3081          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3082    
3083            if (g_ownbackstore)
3084                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3085            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3086                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
3087                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3088  }  }
3089    
3090  void  void
# Line 902  ui_screenblt(uint8 opcode, Line 3093  ui_screenblt(uint8 opcode,
3093               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
3094  {  {
3095          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3096          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
3097          if (ownbackstore)          {
3098                  XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
3099                            cy, x, y);                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3100                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3101            }
3102            else
3103            {
3104                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3105            }
3106    
3107            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3108                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
3109                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3110    
3111          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3112  }  }
3113    
3114  void  void
3115  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
3116            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3117            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
3118  {  {
3119          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3120          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);
3121          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3122                  XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
3123                            cx, cy, x, y);                                   srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
3124            if (g_ownbackstore)
3125                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3126          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3127  }  }
3128    
3129  void  void
3130  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
3131            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
3132            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
3133            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3134  {  {
3135          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 935  ui_triblt(uint8 opcode, Line 3139  ui_triblt(uint8 opcode,
3139          {          {
3140                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
3141                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
3142                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
3143                          break;                          break;
3144    
3145                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
3146                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
3147                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
3148                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
3149                          break;                          break;
3150    
3151                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
3152                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
3153                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
3154                          break;                          break;
3155    
3156                  default:                  default:
# Line 966  ui_line(uint8 opcode, Line 3166  ui_line(uint8 opcode,
3166  {  {
3167          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
3168          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
3169          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3170          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
3171                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
3172                                                endx - sw->xoffset, endy - sw->yoffset));
3173            if (g_ownbackstore)
3174                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3175          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
3176  }  }
3177    
# Line 982  ui_rect( Line 3185  ui_rect(
3185  }  }
3186    
3187  void  void
3188    ui_polygon(uint8 opcode,
3189               /* mode */ uint8 fillmode,
3190               /* dest */ RD_POINT * point, int npoints,
3191               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3192    {
3193            uint8 style, i, ipattern[8];
3194            Pixmap fill;
3195    
3196            SET_FUNCTION(opcode);
3197    
3198            switch (fillmode)
3199            {
3200                    case ALTERNATE:
3201                            XSetFillRule(g_display, g_gc, EvenOddRule);
3202                            break;
3203                    case WINDING:
3204                            XSetFillRule(g_display, g_gc, WindingRule);
3205                            break;
3206                    default:
3207                            unimpl("fill mode %d\n", fillmode);
3208            }
3209    
3210            if (brush)
3211                    style = brush->style;
3212            else
3213                    style = 0;
3214    
3215            switch (style)
3216            {
3217                    case 0: /* Solid */
3218                            SET_FOREGROUND(fgcolour);
3219                            FILL_POLYGON((XPoint *) point, npoints);
3220                            break;
3221    
3222                    case 2: /* Hatch */
3223                            fill = (Pixmap) ui_create_glyph(8, 8,
3224                                                            hatch_patterns + brush->pattern[0] * 8);
3225                            SET_FOREGROUND(fgcolour);
3226                            SET_BACKGROUND(bgcolour);
3227                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3228                            XSetStipple(g_display, g_gc, fill);
3229                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3230                            FILL_POLYGON((XPoint *) point, npoints);
3231                            XSetFillStyle(g_display, g_gc, FillSolid);
3232                            XSetTSOrigin(g_display, g_gc, 0, 0);
3233                            ui_destroy_glyph((RD_HGLYPH) fill);
3234                            break;
3235    
3236                    case 3: /* Pattern */
3237                            for (i = 0; i != 8; i++)
3238                                    ipattern[7 - i] = brush->pattern[i];
3239                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3240                            SET_FOREGROUND(bgcolour);
3241                            SET_BACKGROUND(fgcolour);
3242                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3243                            XSetStipple(g_display, g_gc, fill);
3244                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3245                            FILL_POLYGON((XPoint *) point, npoints);
3246                            XSetFillStyle(g_display, g_gc, FillSolid);
3247                            XSetTSOrigin(g_display, g_gc, 0, 0);
3248                            ui_destroy_glyph((RD_HGLYPH) fill);
3249                            break;
3250    
3251                    default:
3252                            unimpl("brush %d\n", brush->style);
3253            }
3254    
3255            RESET_FUNCTION(opcode);
3256    }
3257    
3258    void
3259    ui_polyline(uint8 opcode,
3260                /* dest */ RD_POINT * points, int npoints,
3261                /* pen */ PEN * pen)
3262    {
3263            /* TODO: set join style */
3264            SET_FUNCTION(opcode);
3265            SET_FOREGROUND(pen->colour);
3266            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
3267            if (g_ownbackstore)
3268                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
3269                               CoordModePrevious);
3270    
3271            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3272                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3273    
3274            RESET_FUNCTION(opcode);
3275    }
3276    
3277    void
3278    ui_ellipse(uint8 opcode,
3279               /* mode */ uint8 fillmode,
3280               /* dest */ int x, int y, int cx, int cy,
3281               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3282    {
3283            uint8 style, i, ipattern[8];
3284            Pixmap fill;
3285    
3286            SET_FUNCTION(opcode);
3287    
3288            if (brush)
3289                    style = brush->style;
3290            else
3291                    style = 0;
3292    
3293            switch (style)
3294            {
3295                    case 0: /* Solid */
3296                            SET_FOREGROUND(fgcolour);
3297                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3298                            break;
3299    
3300                    case 2: /* Hatch */
3301                            fill = (Pixmap) ui_create_glyph(8, 8,
3302                                                            hatch_patterns + brush->pattern[0] * 8);
3303                            SET_FOREGROUND(fgcolour);
3304                            SET_BACKGROUND(bgcolour);
3305                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3306                            XSetStipple(g_display, g_gc, fill);
3307                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3308                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3309                            XSetFillStyle(g_display, g_gc, FillSolid);
3310                            XSetTSOrigin(g_display, g_gc, 0, 0);
3311                            ui_destroy_glyph((RD_HGLYPH) fill);
3312                            break;
3313    
3314                    case 3: /* Pattern */
3315                            for (i = 0; i != 8; i++)
3316                                    ipattern[7 - i] = brush->pattern[i];
3317                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3318                            SET_FOREGROUND(bgcolour);
3319                            SET_BACKGROUND(fgcolour);
3320                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3321                            XSetStipple(g_display, g_gc, fill);
3322                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3323                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3324                            XSetFillStyle(g_display, g_gc, FillSolid);
3325                            XSetTSOrigin(g_display, g_gc, 0, 0);
3326                            ui_destroy_glyph((RD_HGLYPH) fill);
3327                            break;
3328    
3329                    default:
3330                            unimpl("brush %d\n", brush->style);
3331            }
3332    
3333            RESET_FUNCTION(opcode);
3334    }
3335    
3336    /* warning, this function only draws on wnd or backstore, not both */
3337    void
3338  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3339                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3340                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3341                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3342  {  {
3343          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
3344          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
3345    
3346          XSetFillStyle(display, gc,          XSetFillStyle(g_display, g_gc,
3347                        (mixmode ==                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3348                         MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
3349          XSetStipple(display, gc, (Pixmap) glyph);          XSetTSOrigin(g_display, g_gc, x, y);
         XSetTSOrigin(display, gc, x, y);  
3350    
3351          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3352    
3353          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
3354  }  }
3355    
3356  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
3357  {\  {\
3358    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3359    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3360      {\
3361        xyoffset = ttext[++idx];\
3362        if ((xyoffset & 0x80))\
3363      {\      {\
3364        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3365        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);\  
         }\  
3366        else\        else\
3367          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3368            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3369      }\      }\
3370    if (glyph != NULL)\      else\
3371      {\      {\
3372        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3373                       y + (short) glyph->baseline,\          y += xyoffset;\
3374                       glyph->width, glyph->height,\        else\
3375                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3376      }\      }\
3377      }\
3378      if (glyph != NULL)\
3379      {\
3380        x1 = x + glyph->offset;\
3381        y1 = y + glyph->baseline;\
3382        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3383        XSetTSOrigin(g_display, g_gc, x1, y1);\
3384        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3385        if (flags & TEXT2_IMPLICIT_X)\
3386          x += glyph->width;\
3387      }\
3388  }  }
3389    
3390  void  void
3391  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,
3392               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3393               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3394               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3395  {  {
3396            /* TODO: use brush appropriately */
3397    
3398          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3399          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3400          DATABLOB *entry;          DATABLOB *entry;
3401    
3402          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3403    
3404            /* Sometimes, the boxcx value is something really large, like
3405               32691. This makes XCopyArea fail with Xvnc. The code below
3406               is a quick fix. */
3407            if (boxx + boxcx > g_width)
3408                    boxcx = g_width - boxx;
3409    
3410          if (boxcx > 1)          if (boxcx > 1)
3411          {          {
3412                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3413          }          }
3414          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
3415          {          {
3416                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3417          }          }
3418    
3419            SET_FOREGROUND(fgcolour);
3420            SET_BACKGROUND(bgcolour);
3421            XSetFillStyle(g_display, g_gc, FillStippled);
3422    
3423          /* Paint text, character by character */          /* Paint text, character by character */
3424          for (i = 0; i < length;)          for (i = 0; i < length;)
3425          {          {
3426                  switch (text[i])                  switch (text[i])
3427                  {                  {
3428                          case 0xff:                          case 0xff:
3429                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3430                                          cache_put_text(text[i + 1], text,                                  if (i + 3 > length)
                                                        text[i + 2]);  
                                 else  
3431                                  {                                  {
3432                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3433                                            for (j = 0; j < length; j++)
3434                                                    fprintf(stderr, "%02x ", text[j]);
3435                                            fprintf(stderr, "\n");
3436                                            i = length = 0;
3437                                          break;                                          break;
3438                                  }                                  }
3439                                    cache_put_text(text[i + 1], text, text[i + 2]);
3440                                    i += 3;
3441                                    length -= i;
3442                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3443                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3444                                  i = 0;                                  i = 0;
3445                                  break;                                  break;
3446    
3447                          case 0xfe:                          case 0xfe:
3448                                    /* At least one byte needs to follow */
3449                                    if (i + 2 > length)
3450                                    {
3451                                            warning("Skipping short 0xfe command:");
3452                                            for (j = 0; j < length; j++)
3453                                                    fprintf(stderr, "%02x ", text[j]);
3454                                            fprintf(stderr, "\n");
3455                                            i = length = 0;
3456                                            break;
3457                                    }
3458                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3459                                  if (entry != NULL)                                  if (entry->data != NULL)
3460                                  {                                  {
3461                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3462                                               0)                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
                                             && (!(flags & TEXT2_IMPLICIT_X)))  
3463                                          {                                          {
3464                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3465                                                          y += text[i + 2];                                                          y += text[i + 2];
3466                                                  else                                                  else
3467                                                          x += text[i + 2];                                                          x += text[i + 2];
3468                                          }                                          }
                                         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;  
3469                                          for (j = 0; j < entry->size; j++)                                          for (j = 0; j < entry->size; j++)
3470                                                  DO_GLYPH(((uint8 *) (entry->                                                  DO_GLYPH(((uint8 *) (entry->data)), j);
                                                                      data)),  
                                                          j);  
3471                                  }                                  }
3472                                    if (i + 2 < length)
3473                                            i += 3;
3474                                    else
3475                                            i += 2;
3476                                    length -= i;
3477                                    /* this will move pointer from start to first character after FE command */
3478                                    text = &(text[i]);
3479                                    i = 0;
3480                                  break;                                  break;
3481    
3482                          default:                          default:
# Line 1109  ui_draw_text(uint8 font, uint8 flags, in Line 3486  ui_draw_text(uint8 font, uint8 flags, in
3486                  }                  }
3487          }          }
3488    
3489            XSetFillStyle(g_display, g_gc, FillSolid);
3490    
3491            if (g_ownbackstore)
3492            {
3493                    if (boxcx > 1)
3494                    {
3495                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3496                                      boxy, boxcx, boxcy, boxx, boxy);
3497                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3498                                                    (g_display, g_backstore, sw->wnd, g_gc,
3499                                                     boxx, boxy,
3500                                                     boxcx, boxcy,
3501                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3502                    }
3503                    else
3504                    {
3505                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3506                                      clipy, clipcx, clipcy, clipx, clipy);
3507                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3508                                                    (g_display, g_backstore, sw->wnd, g_gc,
3509                                                     clipx, clipy,
3510                                                     clipcx, clipcy, clipx - sw->xoffset,
3511                                                     clipy - sw->yoffset));
3512                    }
3513            }
3514  }  }
3515    
3516  void  void
# Line 1118  ui_desktop_save(uint32 offset, int x, in Line 3519  ui_desktop_save(uint32 offset, int x, in
3519          Pixmap pix;          Pixmap pix;
3520          XImage *image;          XImage *image;
3521    
3522          if (ownbackstore)          if (g_ownbackstore)
3523          {          {
3524                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3525                                    ZPixmap);                  exit_if_null(image);
3526          }          }
3527          else          else
3528          {          {
3529                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3530                  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);
3531                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3532                                    ZPixmap);                  exit_if_null(image);
3533                  XFreePixmap(display, pix);                  XFreePixmap(g_display, pix);
3534          }          }
3535    
3536          offset *= bpp / 8;          offset *= g_bpp / 8;
3537          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);  
3538    
3539          XDestroyImage(image);          XDestroyImage(image);
3540  }  }
# Line 1145  ui_desktop_restore(uint32 offset, int x, Line 3545  ui_desktop_restore(uint32 offset, int x,
3545          XImage *image;          XImage *image;
3546          uint8 *data;          uint8 *data;
3547    
3548          offset *= bpp / 8;          offset *= g_bpp / 8;
3549          data = cache_get_desktop(offset, cx, cy, bpp / 8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3550          if (data == NULL)          if (data == NULL)
3551                  return;                  return;
3552    
3553          image = XCreateImage(display, visual, depth, ZPixmap, 0, data, cx, cy,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3554                               BitmapPad(display), cx * bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3555    
3556          if (ownbackstore)          if (g_ownbackstore)
3557          {          {
3558                  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);
3559                  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);
3560                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3561                                            (g_display, g_backstore, sw->wnd, g_gc,
3562                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3563          }          }
3564          else          else
3565          {          {
3566                  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);
3567                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3568                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3569                                             x - sw->xoffset, y - sw->yoffset));
3570          }          }
3571    
3572          XFree(image);          XFree(image);
3573  }  }
3574    
3575    /* these do nothing here but are used in uiports */
3576    void
3577    ui_begin_update(void)
3578    {
3579    }
3580    
3581    void
3582    ui_end_update(void)
3583    {
3584    }
3585    
3586    
3587    void
3588    ui_seamless_begin(RD_BOOL hidden)
3589    {
3590            if (!g_seamless_rdp)
3591                    return;
3592    
3593            if (g_seamless_started)
3594                    return;
3595    
3596            g_seamless_started = True;
3597            g_seamless_hidden = hidden;
3598    
3599            if (!hidden)
3600                    ui_seamless_toggle();
3601    }
3602    
3603    
3604    void
3605    ui_seamless_hide_desktop()
3606    {
3607            if (!g_seamless_rdp)
3608                    return;
3609    
3610            if (!g_seamless_started)
3611                    return;
3612    
3613            if (g_seamless_active)
3614                    ui_seamless_toggle();
3615    
3616            g_seamless_hidden = True;
3617    }
3618    
3619    
3620    void
3621    ui_seamless_unhide_desktop()
3622    {
3623            if (!g_seamless_rdp)
3624                    return;
3625    
3626            if (!g_seamless_started)
3627                    return;
3628    
3629            g_seamless_hidden = False;
3630    
3631            ui_seamless_toggle();
3632    }
3633    
3634    
3635    void
3636    ui_seamless_toggle()
3637    {
3638            if (!g_seamless_rdp)
3639                    return;
3640    
3641            if (!g_seamless_started)
3642                    return;
3643    
3644            if (g_seamless_hidden)
3645                    return;
3646    
3647            if (g_seamless_active)
3648            {
3649                    /* Deactivate */
3650                    while (g_seamless_windows)
3651                    {
3652                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3653                            sw_remove_window(g_seamless_windows);
3654                    }
3655                    XMapWindow(g_display, g_wnd);
3656            }
3657            else
3658            {
3659                    /* Activate */
3660                    XUnmapWindow(g_display, g_wnd);
3661                    seamless_send_sync();
3662            }
3663    
3664            g_seamless_active = !g_seamless_active;
3665    }
3666    
3667    
3668    void
3669    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3670                              unsigned long flags)
3671    {
3672            Window wnd;
3673            XSetWindowAttributes attribs;
3674            XClassHint *classhints;
3675            XSizeHints *sizehints;
3676            XWMHints *wmhints;
3677            long input_mask;
3678            seamless_window *sw, *sw_parent;
3679    
3680            if (!g_seamless_active)
3681                    return;
3682    
3683            /* Ignore CREATEs for existing windows */
3684            sw = sw_get_window_by_id(id);
3685            if (sw)
3686                    return;
3687    
3688            get_window_attribs(&attribs);
3689            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3690                                InputOutput, g_visual,
3691                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3692    
3693            XStoreName(g_display, wnd, "SeamlessRDP");
3694            ewmh_set_wm_name(wnd, "SeamlessRDP");
3695    
3696            mwm_hide_decorations(wnd);
3697    
3698            classhints = XAllocClassHint();
3699            if (classhints != NULL)
3700            {
3701                    classhints->res_name = "rdesktop";
3702                    classhints->res_class = "SeamlessRDP";
3703                    XSetClassHint(g_display, wnd, classhints);
3704                    XFree(classhints);
3705            }
3706    
3707            /* WM_NORMAL_HINTS */
3708            sizehints = XAllocSizeHints();
3709            if (sizehints != NULL)
3710            {
3711                    sizehints->flags = USPosition;
3712                    XSetWMNormalHints(g_display, wnd, sizehints);
3713                    XFree(sizehints);
3714            }
3715    
3716            /* Parent-less transient windows */
3717            if (parent == 0xFFFFFFFF)
3718            {
3719                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3720                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3721                       using some other hints. */
3722                    ewmh_set_window_popup(wnd);
3723            }
3724            /* Normal transient windows */
3725            else if (parent != 0x00000000)
3726            {
3727                    sw_parent = sw_get_window_by_id(parent);
3728                    if (sw_parent)
3729                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3730                    else
3731                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3732            }
3733    
3734            if (flags & SEAMLESSRDP_CREATE_MODAL)
3735            {
3736                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3737                       somewhat at least */
3738                    if (parent == 0x00000000)
3739                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3740                    ewmh_set_window_modal(wnd);
3741            }
3742    
3743            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3744            {
3745                    /* Make window always-on-top */
3746                    ewmh_set_window_above(wnd);
3747            }
3748    
3749            /* FIXME: Support for Input Context:s */
3750    
3751            get_input_mask(&input_mask);
3752            input_mask |= PropertyChangeMask;
3753    
3754            XSelectInput(g_display, wnd, input_mask);
3755    
3756            /* handle the WM_DELETE_WINDOW protocol. */
3757            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3758    
3759            sw = xmalloc(sizeof(seamless_window));
3760    
3761            memset(sw, 0, sizeof(seamless_window));
3762    
3763            sw->wnd = wnd;
3764            sw->id = id;
3765            sw->group = sw_find_group(group, False);
3766            sw->group->refcnt++;
3767            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3768            sw->desktop = 0;
3769            sw->position_timer = xmalloc(sizeof(struct timeval));
3770            timerclear(sw->position_timer);
3771    
3772            sw->outstanding_position = False;
3773            sw->outpos_serial = 0;
3774            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3775            sw->outpos_width = sw->outpos_height = 0;
3776    
3777            sw->next = g_seamless_windows;
3778            g_seamless_windows = sw;
3779    
3780            /* WM_HINTS */
3781            wmhints = XAllocWMHints();
3782            if (wmhints)
3783            {
3784                    wmhints->flags = WindowGroupHint;
3785                    wmhints->window_group = sw->group->wnd;
3786                    XSetWMHints(g_display, sw->wnd, wmhints);
3787                    XFree(wmhints);
3788            }
3789    }
3790    
3791    
3792    void
3793    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3794    {
3795            seamless_window *sw;
3796    
3797            if (!g_seamless_active)
3798                    return;
3799    
3800            sw = sw_get_window_by_id(id);
3801            if (!sw)
3802            {
3803                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3804                    return;
3805            }
3806    
3807            XDestroyWindow(g_display, sw->wnd);
3808            sw_remove_window(sw);
3809    }
3810    
3811    
3812    void
3813    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3814    {
3815            seamless_window *sw, *sw_next;
3816    
3817            if (!g_seamless_active)
3818                    return;
3819    
3820            for (sw = g_seamless_windows; sw; sw = sw_next)
3821            {
3822                    sw_next = sw->next;
3823    
3824                    if (sw->group->id == id)
3825                    {
3826                            XDestroyWindow(g_display, sw->wnd);
3827                            sw_remove_window(sw);
3828                    }
3829            }
3830    }
3831    
3832    
3833    void
3834    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3835                        const char *data, int chunk_len)
3836    {
3837            seamless_window *sw;
3838    
3839            if (!g_seamless_active)
3840                    return;
3841    
3842            sw = sw_get_window_by_id(id);
3843            if (!sw)
3844            {
3845                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3846                    return;
3847            }
3848    
3849            if (chunk == 0)
3850            {
3851                    if (sw->icon_size)
3852                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3853    
3854                    if (strcmp(format, "RGBA") != 0)
3855                    {
3856                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3857                            return;
3858                    }
3859    
3860                    sw->icon_size = width * height * 4;
3861                    if (sw->icon_size > 32 * 32 * 4)
3862                    {
3863                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3864                            sw->icon_size = 0;
3865                            return;
3866                    }
3867    
3868                    sw->icon_offset = 0;
3869            }
3870            else
3871            {
3872                    if (!sw->icon_size)
3873                            return;
3874            }
3875    
3876            if (chunk_len > (sw->icon_size - sw->icon_offset))
3877            {
3878                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3879                            chunk_len, sw->icon_size - sw->icon_offset);
3880                    sw->icon_size = 0;
3881                    return;
3882            }
3883    
3884            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3885            sw->icon_offset += chunk_len;
3886    
3887            if (sw->icon_offset == sw->icon_size)
3888            {
3889                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3890                    sw->icon_size = 0;
3891            }
3892    }
3893    
3894    
3895    void
3896    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3897    {
3898            seamless_window *sw;
3899    
3900            if (!g_seamless_active)
3901                    return;
3902    
3903            sw = sw_get_window_by_id(id);
3904            if (!sw)
3905            {
3906                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3907                    return;
3908            }
3909    
3910            if (strcmp(format, "RGBA") != 0)
3911            {
3912                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3913                    return;
3914            }
3915    
3916            ewmh_del_icon(sw->wnd, width, height);
3917    }
3918    
3919    
3920    void
3921    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3922    {
3923            seamless_window *sw;
3924    
3925            if (!g_seamless_active)
3926                    return;
3927    
3928            sw = sw_get_window_by_id(id);
3929            if (!sw)
3930            {
3931                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3932                    return;
3933            }
3934    
3935            /* We ignore server updates until it has handled our request. */
3936            if (sw->outstanding_position)
3937                    return;
3938    
3939            if (!width || !height)
3940                    /* X11 windows must be at least 1x1 */
3941                    return;
3942    
3943            sw->xoffset = x;
3944            sw->yoffset = y;
3945            sw->width = width;
3946            sw->height = height;
3947    
3948            /* If we move the window in a maximized state, then KDE won't
3949               accept restoration */
3950            switch (sw->state)
3951            {
3952                    case SEAMLESSRDP_MINIMIZED:
3953                    case SEAMLESSRDP_MAXIMIZED:
3954                            return;
3955            }
3956    
3957            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3958            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3959    }
3960    
3961    
3962    void
3963    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3964    {
3965            seamless_window *sw;
3966            XWindowChanges values;
3967            unsigned long restack_serial;
3968    
3969            if (!g_seamless_active)
3970                    return;
3971    
3972            sw = sw_get_window_by_id(id);
3973            if (!sw)
3974            {
3975                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3976                    return;
3977            }
3978    
3979            if (behind)
3980            {
3981                    seamless_window *sw_behind;
3982    
3983                    sw_behind = sw_get_window_by_id(behind);
3984                    if (!sw_behind)
3985                    {
3986                            warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
3987                            return;
3988                    }
3989    
3990                    if (!g_seamless_broken_restack)
3991                    {
3992                            values.stack_mode = Below;
3993                            values.sibling = sw_behind->wnd;
3994                            restack_serial = XNextRequest(g_display);
3995                            XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display),
3996                                                 CWStackMode | CWSibling, &values);
3997                            sw_wait_configurenotify(sw->wnd, restack_serial);
3998                    }
3999            }
4000            else
4001            {
4002                    values.stack_mode = Above;
4003                    restack_serial = XNextRequest(g_display);
4004                    XReconfigureWMWindow(g_display, sw->wnd, DefaultScreen(g_display), CWStackMode,
4005                                         &values);
4006                    sw_wait_configurenotify(sw->wnd, restack_serial);
4007            }
4008    
4009            sw_restack_window(sw, behind);
4010    
4011            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4012            {
4013                    /* Make window always-on-top */
4014                    ewmh_set_window_above(sw->wnd);
4015            }
4016    }
4017    
4018    
4019    void
4020    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
4021    {
4022            seamless_window *sw;
4023    
4024            if (!g_seamless_active)
4025                    return;
4026    
4027            sw = sw_get_window_by_id(id);
4028            if (!sw)
4029            {
4030                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
4031                    return;
4032            }
4033    
4034            /* FIXME: Might want to convert the name for non-EWMH WMs */
4035            XStoreName(g_display, sw->wnd, title);
4036            ewmh_set_wm_name(sw->wnd, title);
4037    }
4038    
4039    
4040    void
4041    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
4042    {
4043            seamless_window *sw;
4044    
4045            if (!g_seamless_active)
4046                    return;
4047    
4048            sw = sw_get_window_by_id(id);
4049            if (!sw)
4050            {
4051                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
4052                    return;
4053            }
4054    
4055            switch (state)
4056            {
4057                    case SEAMLESSRDP_NORMAL:
4058                    case SEAMLESSRDP_MAXIMIZED:
4059                            ewmh_change_state(sw->wnd, state);
4060                            XMapWindow(g_display, sw->wnd);
4061                            break;
4062                    case SEAMLESSRDP_MINIMIZED:
4063                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
4064                               the Window Manager should probably just ignore the request, since
4065                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
4066                               such as minimization, rather than an independent state." Besides,
4067                               XIconifyWindow is easier. */
4068                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
4069                            {
4070                                    XWMHints *hints;
4071                                    hints = XGetWMHints(g_display, sw->wnd);
4072                                    if (hints)
4073                                    {
4074                                            hints->flags |= StateHint;
4075                                            hints->initial_state = IconicState;
4076                                            XSetWMHints(g_display, sw->wnd, hints);
4077                                            XFree(hints);
4078                                    }
4079                                    XMapWindow(g_display, sw->wnd);
4080                            }
4081                            else
4082                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
4083                            break;
4084                    default:
4085                            warning("SeamlessRDP: Invalid state %d\n", state);
4086                            break;
4087            }
4088    
4089            sw->state = state;
4090    }
4091    
4092    
4093    void
4094    ui_seamless_syncbegin(unsigned long flags)
4095    {
4096            if (!g_seamless_active)
4097                    return;
4098    
4099            /* Destroy all seamless windows */
4100            while (g_seamless_windows)
4101            {
4102                    XDestroyWindow(g_display, g_seamless_windows->wnd);
4103                    sw_remove_window(g_seamless_windows);
4104            }
4105    }
4106    
4107    
4108    void
4109    ui_seamless_ack(unsigned int serial)
4110    {
4111            seamless_window *sw;
4112            for (sw = g_seamless_windows; sw; sw = sw->next)
4113            {
4114                    if (sw->outstanding_position && (sw->outpos_serial == serial))
4115                    {
4116                            sw->xoffset = sw->outpos_xoffset;
4117                            sw->yoffset = sw->outpos_yoffset;
4118                            sw->width = sw->outpos_width;
4119                            sw->height = sw->outpos_height;
4120                            sw->outstanding_position = False;
4121    
4122                            /* Do a complete redraw of the window as part of the
4123                               completion of the move. This is to remove any
4124                               artifacts caused by our lack of synchronization. */
4125                            XCopyArea(g_display, g_backstore,
4126                                      sw->wnd, g_gc,
4127                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
4128    
4129                            break;
4130                    }
4131            }
4132    }

Legend:
Removed from v.66  
changed lines
  Added in v.1461

  ViewVC Help
Powered by ViewVC 1.1.26