/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

Legend:
Removed from v.84  
changed lines
  Added in v.1181

  ViewVC Help
Powered by ViewVC 1.1.26