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

Legend:
Removed from v.64  
changed lines
  Added in v.1143

  ViewVC Help
Powered by ViewVC 1.1.26