/[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 53 by matthewc, Tue May 28 11:48:55 2002 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1154 by ossman_, Fri Mar 17 09:56:20 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            int xoffset, yoffset;
59            int width, height;
60            int state;              /* normal/minimized/maximized. */
61            unsigned int desktop;
62            struct _seamless_window *next;
63    } seamless_window;
64    static seamless_window *g_seamless_windows = NULL;
65    static BOOL g_seamless_started = False; /* Server end is up and running */
66    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
67    extern BOOL g_seamless_rdp;
68    
69    extern uint32 g_embed_wnd;
70    BOOL g_enable_compose = False;
71    BOOL g_Unobscured;              /* used for screenblt */
72    static GC g_gc = NULL;
73    static GC g_create_bitmap_gc = NULL;
74    static GC g_create_glyph_gc = NULL;
75    static XRectangle g_clip_rectangle;
76    static Visual *g_visual;
77    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
78       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
79       as far as we're concerned. */
80    static int g_depth;
81    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
82       This may be larger than g_depth, in which case some of the bits would
83       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
84    static int g_bpp;
85    static XIM g_IM;
86    static XIC g_IC;
87    static XModifierKeymap *g_mod_map;
88    static Cursor g_current_cursor;
89    static HCURSOR g_null_cursor = NULL;
90    static Atom g_protocol_atom, g_kill_atom;
91    extern Atom g_net_wm_state_atom;
92    extern Atom g_net_wm_desktop_atom;
93    static BOOL g_focused;
94    static BOOL g_mouse_in_wnd;
95    /* Indicates that:
96       1) visual has 15, 16 or 24 depth and the same color channel masks
97          as its RDP equivalent (implies X server is LE),
98       2) host is LE
99       This will trigger an optimization whose real value is questionable.
100    */
101    static BOOL g_compatible_arch;
102    /* Indicates whether RDP's bitmaps and our XImages have the same
103       binary format. If so, we can avoid an expensive translation.
104       Note that this can be true when g_compatible_arch is false,
105       e.g.:
106      
107         RDP(LE) <-> host(BE) <-> X-Server(LE)
108        
109       ('host' is the machine running rdesktop; the host simply memcpy's
110        so its endianess doesn't matter)
111     */
112    static BOOL g_no_translate_image = False;
113    
114  /* endianness */  /* endianness */
115  static BOOL host_be;  static BOOL g_host_be;
116  static BOOL xserver_be;  static BOOL g_xserver_be;
117    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
118    static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
119    
120  /* software backing store */  /* software backing store */
121  static BOOL ownbackstore;  extern BOOL g_ownbackstore;
122  static Pixmap backstore;  static Pixmap g_backstore = 0;
123    
124    /* Moving in single app mode */
125    static BOOL g_moving_wnd;
126    static int g_move_x_offset = 0;
127    static int g_move_y_offset = 0;
128    static BOOL g_using_full_workarea = False;
129    
130    #ifdef WITH_RDPSND
131    extern int g_dsp_fd;
132    extern BOOL g_dsp_busy;
133    extern BOOL g_rdpsnd;
134    #endif
135    
136    /* MWM decorations */
137    #define MWM_HINTS_DECORATIONS   (1L << 1)
138    #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
139    typedef struct
140    {
141            unsigned long flags;
142            unsigned long functions;
143            unsigned long decorations;
144            long inputMode;
145            unsigned long status;
146    }
147    PropMotifWmHints;
148    
149    typedef struct
150    {
151            uint32 red;
152            uint32 green;
153            uint32 blue;
154    }
155    PixelColour;
156    
157    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
158            do { \
159                    seamless_window *sw; \
160                    XRectangle rect; \
161                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
162                        rect.x = g_clip_rectangle.x - sw->xoffset; \
163                        rect.y = g_clip_rectangle.y - sw->yoffset; \
164                        rect.width = g_clip_rectangle.width; \
165                        rect.height = g_clip_rectangle.height; \
166                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
167                        func args; \
168                    } \
169                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
170            } while (0)
171    
172  /* needed to keep track of the modifiers */  static void
173  static unsigned int key_modifier_state = 0;  seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
174  static unsigned int key_down_state = 0;  {
175            points[0].x -= xoffset;
176  #define DShift1Mask   (1<<0)          points[0].y -= yoffset;
177  #define DShift2Mask   (1<<1)          XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
178  #define DControl1Mask (1<<2)          points[0].x += xoffset;
179  #define DControl2Mask (1<<3)          points[0].y += yoffset;
180  #define DMod1Mask     (1<<4)  }
181  #define DMod2Mask     (1<<5)  
182    static void
183    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
184    {
185            points[0].x -= xoffset;
186            points[0].y -= yoffset;
187            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
188            points[0].x += xoffset;
189            points[0].y += yoffset;
190    }
191    
192  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
193  { \  { \
194          XFillRectangle(display, wnd, gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
195          if (ownbackstore) \          ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
196                  XFillRectangle(display, backstore, gc, x, y, cx, cy); \          if (g_ownbackstore) \
197                    XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
198    }
199    
200    #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
201    { \
202            XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
203    }
204    
205    #define FILL_POLYGON(p,np)\
206    { \
207            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
208            if (g_ownbackstore) \
209                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
210            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
211    }
212    
213    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
214    { \
215            switch (m) \
216            { \
217                    case 0: /* Outline */ \
218                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
219                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
220                            if (g_ownbackstore) \
221                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
222                            break; \
223                    case 1: /* Filled */ \
224                            XFillArc(g_display, g_wnd, g_gc, x, y, \
225                                     cx, cy, 0, 360*64); \
226                            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)); \
227                            if (g_ownbackstore) \
228                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
229                            break; \
230            } \
231  }  }
232    
233  /* colour maps */  /* colour maps */
234  static BOOL owncolmap;  extern BOOL g_owncolmap;
235  static Colormap xcolmap;  static Colormap g_xcolmap;
236  static uint32 white;  static uint32 *g_colmap = NULL;
237  static uint32 *colmap;  
238    #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
239  #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
240  #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));  
241    
242  static int rop2_map[] = {  static int rop2_map[] = {
243          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 96  static int rop2_map[] = { Line 258  static int rop2_map[] = {
258          GXset                   /* 1 */          GXset                   /* 1 */
259  };  };
260    
261  #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]); }
262  #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); }
   
 void xwin_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode);  
 void xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode);  
263    
264  static void  static seamless_window *
265  translate8(uint8 *data, uint8 *out, uint8 *end)  seamless_get_window_by_id(unsigned long id)
266  {  {
267          while (out < end)          seamless_window *sw;
268                  *(out++) = (uint8)colmap[*(data++)];          for (sw = g_seamless_windows; sw; sw = sw->next)
269            {
270                    if (sw->id == id)
271                            return sw;
272            }
273            return NULL;
274  }  }
275    
276  static void  
277  translate16(uint8 *data, uint16 *out, uint16 *end)  static seamless_window *
278    seamless_get_window_by_wnd(Window wnd)
279  {  {
280          while (out < end)          seamless_window *sw;
281                  *(out++) = (uint16)colmap[*(data++)];          for (sw = g_seamless_windows; sw; sw = sw->next)
282            {
283                    if (sw->wnd == wnd)
284                            return sw;
285            }
286            return NULL;
287  }  }
288    
289  /* little endian - conversion happens when colourmap is built */  
290  static void  static void
291  translate24(uint8 *data, uint8 *out, uint8 *end)  seamless_remove_window(seamless_window * win)
292  {  {
293          uint32 value;          seamless_window *sw, **prevnext = &g_seamless_windows;
294            for (sw = g_seamless_windows; sw; sw = sw->next)
         while (out < end)  
295          {          {
296                  value = colmap[*(data++)];                  if (sw == win)
297                  *(out++) = value;                  {
298                  *(out++) = value >> 8;                          *prevnext = sw->next;
299                  *(out++) = value >> 16;                          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;
331          uint8 *end = out + size;  
332            /* setup the property */
333            motif_hints.flags = MWM_HINTS_DECORATIONS;
334            motif_hints.decorations = 0;
335    
336          switch (bpp)          /* 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          return colour;  /* indent is confused by UNROLL8 */
416    /* *INDENT-OFF* */
417    
418    /* 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;  }
456          unsigned long input_mask;  
457          XPixmapFormatValues *pfm;  static void
458          Screen *screen;  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
459          uint16 test;  {
460          int i;          uint16 value;
461            
462          int xkb_minor, xkb_major;          if (g_compatible_arch)
         int xkb_event, xkb_error, xkb_reason;  
   
         /* compare compiletime libs with runtime libs. */  
         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          /* XKB is the 'new' keyboard handler in x.. ( the xkb code in Xfree86 originates from SGI, years 1993 and 1995 from what I could tell. )          if (g_compatible_arch)
          * it makes it possible for people with disabilities to use rdesktop, stickykeys, bouncekeys etc. VERY MUCH useful.  
          * XFree86 has had support for it since it's earliest incarnation. I believe it is a reasonable dependency.  
          */  
         display = 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    static void
515    translate8to32(const uint8 * data, uint8 * out, uint8 * end)
516    {
517            uint32 value;
518    
519          if (display == NULL)          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          pfm = XListPixmapFormats(display, &i);          PixelColour pc;
553          if (pfm != NULL)  
554            if (g_xserver_be)
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
569            {
570                    while (out < end)
571                    {
572                            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          if (bpp < 8)  static void
585    translate15to24(const uint16 * data, uint8 * out, uint8 * end)
586    {
587            uint32 value;
588            uint16 pixel;
589            PixelColour pc;
590    
591            if (g_compatible_arch)
592          {          {
593                  error("Less than 8 bpp not currently supported.\n");                  /* *INDENT-OFF* */
594                  XCloseDisplay(display);                  REPEAT3
595                  return False;                  (
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
619            {
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    static void
635    translate15to32(const uint16 * data, uint8 * out, uint8 * end)
636    {
637            uint16 pixel;
638            uint32 value;
639            PixelColour pc;
640    
641          if (depth <= 8)          if (g_compatible_arch)
642                  owncolmap = True;          {
643                    /* *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          else
670                  xcolmap = DefaultColormapOfScreen(screen);          {
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          test = 1;  static void
686          host_be = !(BOOL)(*(uint8 *)(&test));  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
687          xserver_be = (ImageByteOrder(display) == MSBFirst);  {
688            uint16 pixel;
689            uint16 value;
690            PixelColour pc;
691    
692          white = WhitePixelOfScreen(screen);          if (g_xserver_be)
693          attribs.background_pixel = BlackPixelOfScreen(screen);          {
694          attribs.backing_store = DoesBackingStore(screen);                  if (g_host_be)
695                    {
696                            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
717            {
718                    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          if (attribs.backing_store == NotUseful)  static void
743                  ownbackstore = True;  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
744    {
745            uint32 value;
746            uint16 pixel;
747            PixelColour pc;
748    
749          if (fullscreen)          if (g_compatible_arch)
750          {          {
751                  attribs.override_redirect = True;                  /* *INDENT-OFF* */
752                  width = WidthOfScreen(screen);                  REPEAT3
753                  height = HeightOfScreen(screen);                  (
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          else
787          {          {
788                  attribs.override_redirect = False;                  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          width = (width + 3) & ~3; /* make width a multiple of 32 bits */  static void
813    translate16to32(const uint16 * data, uint8 * out, uint8 * end)
814    {
815            uint16 pixel;
816            uint32 value;
817            PixelColour pc;
818    
819          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          if (g_compatible_arch)
820                              0, 0, width, height, 0, CopyFromParent,          {
821                              InputOutput, CopyFromParent,                  /* *INDENT-OFF* */
822                              CWBackingStore | CWBackPixel | CWOverrideRedirect,                  REPEAT4
823                              &attribs);                  (
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)
834            {
835                    if (g_host_be)
836                    {
837                            while (out < end)
838                            {
839                                    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          XStoreName(display, wnd, title);  static void
884    translate24to16(const uint8 * data, uint8 * out, uint8 * end)
885    {
886            uint32 pixel = 0;
887            uint16 value;
888            PixelColour pc;
889    
890          classhints = XAllocClassHint();          while (out < end)
         if (classhints != NULL)  
891          {          {
892                  classhints->res_name = classhints->res_class = "rdesktop";                  pixel = *(data++) << 16;
893                  XSetClassHint(display, wnd, classhints);                  pixel |= *(data++) << 8;
894                  XFree(classhints);                  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          sizehints = XAllocSizeHints();  static void
909          if (sizehints)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
910    {
911            uint32 pixel;
912            uint32 value;
913            PixelColour pc;
914    
915            if (g_xserver_be)
916          {          {
917                  sizehints->flags = PMinSize | PMaxSize;                  while (out < end)
918                  sizehints->min_width = sizehints->max_width = width;                  {
919                  sizehints->min_height = sizehints->max_height = height;                          pixel = *(data++) << 16;
920                  XSetWMNormalHints(display, wnd, sizehints);                          pixel |= *(data++) << 8;
921                  XFree(sizehints);                          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          xkeymap_init();  static void
942    translate24to32(const uint8 * data, uint8 * out, uint8 * end)
943    {
944            uint32 pixel;
945            uint32 value;
946            PixelColour pc;
947    
948          input_mask = KeyPressMask | KeyReleaseMask |          if (g_compatible_arch)
949                           ButtonPressMask | ButtonReleaseMask |          {
950                           EnterWindowMask | LeaveWindowMask | KeymapStateMask;                  /* *INDENT-OFF* */
951          if (sendmotion)  #ifdef NEED_ALIGN
952                  input_mask |= PointerMotionMask;                  REPEAT4
953                    (
954          if (ownbackstore)                          *(out++) = *(data++);
955                  input_mask |= ExposureMask;                          *(out++) = *(data++);
956                            *(out++) = *(data++);
957          XSelectInput(display, wnd, input_mask);                          *(out++) = 0;
958          gc = XCreateGC(display, wnd, 0, NULL);                  )
959    #else
960          if (ownbackstore)                  REPEAT4
961                  backstore = XCreatePixmap(display, wnd, width, height, depth);                  (
962                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
963          XMapWindow(display, wnd);                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
964                     out += 4;
965          /* TODO: error texts... make them friendly. */                   data += 3;
966          xkb = XkbGetKeyboard(display, XkbAllComponentsMask, XkbUseCoreKbd);                  )
967          if ((int)xkb == BadAlloc || xkb == NULL)  #endif
968          {                  /* *INDENT-ON* */
969                          error( "XkbGetKeyboard failed.\n");          }
970                          exit(0);          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          if( XkbSelectEvents(display, xkb->device_spec, XkbAllEventsMask, XkbAllEventsMask) == False )  translate_image(int width, int height, uint8 * data)
998    {
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                          error( "XkbSelectEvents failed.\n");                  if ((g_depth == 15 && g_server_depth == 15) ||
1014                          exit(0);                      (g_depth == 16 && g_server_depth == 16) ||
1015                        (g_depth == 24 && g_server_depth == 24))
1016                            return data;
1017          }          }
1018    
1019          return True;          size = width * height * (g_bpp / 8);
1020            out = (uint8 *) xmalloc(size);
1021            end = out + size;
1022    
1023            switch (g_server_depth)
1024            {
1025                    case 24:
1026                            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  void  BOOL
1089  ui_destroy_window()  get_key_state(unsigned int state, uint32 keysym)
1090  {  {
1091          if( xkb != NULL )          int modifierpos, key, keysymMask = 0;
1092                  XkbFreeKeyboard(xkb, XkbAllControlsMask, True);          int offset;
1093    
1094            KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1095    
1096          if (ownbackstore)          if (keycode == NoSymbol)
1097                  XFreePixmap(display, backstore);                  return False;
1098    
1099            for (modifierpos = 0; modifierpos < 8; modifierpos++)
1100            {
1101                    offset = g_mod_map->max_keypermod * modifierpos;
1102    
1103          XFreeGC(display, gc);                  for (key = 0; key < g_mod_map->max_keypermod; key++)
1104          XDestroyWindow(display, wnd);                  {
1105          XCloseDisplay(display);                          if (g_mod_map->modifiermap[offset + key] == keycode)
1106          display = NULL;                                  keysymMask |= 1 << modifierpos;
1107                    }
1108            }
1109    
1110            return (state & keysymMask) ? True : False;
1111  }  }
1112    
1113  static void  static void
1114  xwin_process_events()  calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1115  {  {
1116          XkbEvent xkbevent;          *shift_l = ffs(mask) - 1;
1117                    mask >>= *shift_l;
1118          KeySym keysym;          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1119          uint8 scancode;  }
         uint16 button, flags;  
         uint32 ev_time;  
         uint32 tmpmods;  
1120    
1121          while (XCheckMaskEvent(display, ~0, &xkbevent.core))  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1122       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            unsigned weight = 0;
1128            do
1129          {          {
1130                  ev_time = time(NULL);                  weight += (mask & 1);
1131                  flags = 0;          }
1132            while (mask >>= 1);
1133            return weight;
1134    }
1135    
1136                  switch (xkbevent.type)  static BOOL
1137                  {  select_visual()
1138                          case KeymapNotify:  {
1139                                  /* TODO:          XPixmapFormatValues *pfm;
1140                                   * read modifier status at focus in, and update the local masks, and the other end as well..          int pixmap_formats_count, visuals_count;
1141                                   * if not, we may get out of sync.          XVisualInfo *vmatches = NULL;
1142                                   * xkbevent.core.xkeymap.key_vector          XVisualInfo template;
1143                                   * char key_vector[32];          int i;
1144                                   */          unsigned red_weight, blue_weight, green_weight;
                                 break;  
1145    
1146                          case KeyRelease:          red_weight = blue_weight = green_weight = 0;
                                 flags = KBD_FLAG_DOWN | KBD_FLAG_UP;  
                                 /* fall through */  
1147    
1148                          case KeyPress:          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1149                                  if( XkbTranslateKeyCode(xkb, xkbevent.core.xkey.keycode, xkbevent.core.xkey.state, &tmpmods, &keysym) == False )          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            /* Search for best TrueColor visual */
1157            template.class = TrueColor;
1158            vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1159            g_visual = NULL;
1160            g_no_translate_image = False;
1161            g_compatible_arch = False;
1162            if (vmatches != NULL)
1163            {
1164                    for (i = 0; i < visuals_count; ++i)
1165                    {
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;                                          break;
1193                                  scancode = xkeymap_translate_key(keysym, xkbevent.core.xkey.keycode, &flags);                          }
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                                  if (scancode == 0 )                          /* 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 ((pfm[j].bits_per_pixel == 16) ||
1217                                                (pfm[j].bits_per_pixel == 24) ||
1218                                                (pfm[j].bits_per_pixel == 32))
1219                                            {
1220                                                    can_translate_to_bpp = True;
1221                                            }
1222                                          break;                                          break;
1223                                    }
1224                            }
1225    
1226                                  /* keep track of the modifiers -- needed for stickykeys... */                          /* Prefer formats which have the most colour depth.
1227                                  if( xkbevent.type == KeyPress )                             We're being truly aristocratic here, minding each
1228                                          xwin_press_modifiers( &xkbevent.core.xkey, ev_time, scancode );                             weight on its own. */
1229                            if (can_translate_to_bpp)
1230                            {
1231                                    unsigned vis_red_weight =
1232                                            calculate_mask_weight(visual_info->red_mask);
1233                                    unsigned vis_green_weight =
1234                                            calculate_mask_weight(visual_info->green_mask);
1235                                    unsigned vis_blue_weight =
1236                                            calculate_mask_weight(visual_info->blue_mask);
1237                                    if ((vis_red_weight >= red_weight)
1238                                        && (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                            }
1248                    }
1249                    XFree(vmatches);
1250            }
1251    
1252                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, flags, scancode, 0);          if (g_visual != NULL)
1253            {
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                                  if( xkbevent.type == KeyRelease )                  /* we use a colourmap, so the default visual should do */
1277                                          xwin_release_modifiers( &xkbevent.core.xkey, ev_time, scancode );                  g_owncolmap = True;
1278                    g_visual = vmatches[0].visual;
1279                    g_depth = vmatches[0].depth;
1280            }
1281    
1282                                  break;          g_bpp = 0;
1283            for (i = 0; i < pixmap_formats_count; ++i)
1284            {
1285                    XPixmapFormatValues *pf = &pfm[i];
1286                    if (pf->depth == g_depth)
1287                    {
1288                            g_bpp = pf->bits_per_pixel;
1289    
1290                          case ButtonPress:                          if (g_no_translate_image)
1291                                  flags = MOUSE_FLAG_DOWN;                          {
1292                                  /* fall through */                                  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                          case ButtonRelease:                          /* Pixmap formats list is a depth-to-bpp mapping --
1313                                  button = xkeymap_translate_button(xkbevent.core.xbutton.button);                             there's just a single entry for every depth,
1314                                  if (button == 0)                             so we can safely break here */
1315                                          break;                          break;
1316                    }
1317            }
1318            XFree(pfm);
1319            pfm = NULL;
1320            return True;
1321    }
1322    
1323                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,  BOOL
1324                                                 flags | button,  ui_init(void)
1325                                                 xkbevent.core.xbutton.x,  {
1326                                                 xkbevent.core.xbutton.y);          int screen_num;
                                 break;  
1327    
1328                          case MotionNotify:          g_display = XOpenDisplay(NULL);
1329                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,          if (g_display == NULL)
1330                                                 MOUSE_FLAG_MOVE,          {
1331                                                 xkbevent.core.xmotion.x,                  error("Failed to open display: %s\n", XDisplayName(NULL));
1332                                                 xkbevent.core.xmotion.y);                  return False;
1333                                  break;          }
1334    
1335                          case EnterNotify:          {
1336                                  XGrabKeyboard(display, wnd, True, GrabModeAsync,                  uint16 endianess_test = 1;
1337                                                GrabModeAsync, CurrentTime);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1338                                  break;          }
1339    
1340                          case LeaveNotify:          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1341                                  XUngrabKeyboard(display, CurrentTime);          screen_num = DefaultScreen(g_display);
1342                                  break;          g_x_socket = ConnectionNumber(g_display);
1343            g_screen = ScreenOfDisplay(g_display, screen_num);
1344            g_depth = DefaultDepthOfScreen(g_screen);
1345    
1346                          case Expose:          if (!select_visual())
1347                                  XCopyArea(display, backstore, wnd, gc,                  return False;
1348                                            xkbevent.core.xexpose.x, xkbevent.core.xexpose.y,  
1349                                            xkbevent.core.xexpose.width, xkbevent.core.xexpose.height,          if (g_no_translate_image)
1350                                            xkbevent.core.xexpose.x, xkbevent.core.xexpose.y);          {
1351                                  break;                  DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1352            }
1353    
1354            if (g_server_depth > g_bpp)
1355            {
1356                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1357                            g_server_depth, g_bpp);
1358            }
1359    
1360            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1361                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1362    
1363            if (!g_owncolmap)
1364            {
1365                    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            if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1373            {
1374                    warning("External BackingStore not available. Using internal.\n");
1375                    g_ownbackstore = True;
1376            }
1377    
1378            /*
1379             * Determine desktop size
1380             */
1381            if (g_fullscreen)
1382            {
1383                    g_width = WidthOfScreen(g_screen);
1384                    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_release_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)  ui_deinit(void)
1435  {  {
1436          switch (scancode) {          if (g_IM != NULL)
1437          case 0x2a:                  XCloseIM(g_IM);
1438                  key_down_state &= ~DShift1Mask;  
1439                  break;          if (g_null_cursor != NULL)
1440          case 0x36:                  ui_destroy_cursor(g_null_cursor);
1441                  key_down_state &= ~DShift2Mask;  
1442                  break;          XFreeModifiermap(g_mod_map);
1443          case 0x1d:  
1444                  key_down_state &= ~DControl1Mask;          if (g_ownbackstore)
1445                  break;                  XFreePixmap(g_display, g_backstore);
1446          case 0x9d:  
1447                  key_down_state &= ~DControl2Mask;          XFreeGC(g_display, g_gc);
1448                  break;          XCloseDisplay(g_display);
1449          case 0x38:          g_display = NULL;
1450                  key_down_state &= ~DMod1Mask;  }
1451                  break;  
1452          case 0xb8:  
1453                  key_down_state &= ~DMod2Mask;  static void
1454                  break;  get_window_attribs(XSetWindowAttributes * attribs)
1455    {
1456            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1457            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1458            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1459            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1460            attribs->override_redirect = g_fullscreen;
1461            attribs->colormap = g_xcolmap;
1462    }
1463    
1464    static void
1465    get_input_mask(long *input_mask)
1466    {
1467            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1468                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1469    
1470            if (g_sendmotion)
1471                    *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                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1512                    ui_reset_clip();
1513          }          }
1514    
1515          if( !(ShiftMask & ev->state) && (key_down_state & DShift1Mask))          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, KBD_FLAG_UP, 0x2a, 0);                  g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
                 key_down_state &= ~DShift1Mask;  
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          if( !(ControlMask & ev->state) && (key_down_state & DControl1Mask))          XStoreName(g_display, g_wnd, g_title);
1528    
1529            if (g_hide_decorations)
1530                    mwm_hide_decorations(g_wnd);
1531    
1532            classhints = XAllocClassHint();
1533            if (classhints != NULL)
1534          {          {
1535                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x1d, 0);                  classhints->res_name = classhints->res_class = "rdesktop";
1536                  key_down_state &= ~DControl1Mask;                  XSetClassHint(g_display, g_wnd, classhints);
1537                    XFree(classhints);
1538            }
1539    
1540            sizehints = XAllocSizeHints();
1541            if (sizehints)
1542            {
1543                    sizehints->flags = PMinSize | PMaxSize;
1544                    if (g_pos)
1545                            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 & ev->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, 0);                  g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1562                  key_down_state &= ~DMod1Mask;                                   XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
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 & ev->state) && (key_down_state & DMod2Mask))          XSelectInput(g_display, g_wnd, input_mask);
1570    
1571            XMapWindow(g_display, g_wnd);
1572            /* wait for VisibilityNotify */
1573            do
1574          {          {
1575                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0xb8, 0);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
                 key_down_state &= ~DMod2Mask;  
1576          }          }
1577  }          while (xevent.type != VisibilityNotify);
1578            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1579    
1580            g_focused = False;
1581            g_mouse_in_wnd = False;
1582    
1583            /* handle the WM_DELETE_WINDOW protocol */
1584            g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1585            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1586            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1587    
1588            /* create invisible 1x1 cursor to be used as null cursor */
1589            if (g_null_cursor == NULL)
1590                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1591    
1592            return True;
1593    }
1594    
1595  void  void
1596  xwin_press_modifiers(XKeyEvent* ev, uint32 ev_time, uint32 scancode)  ui_resize_window()
1597  {  {
1598          key_modifier_state = ev->state;          XSizeHints *sizehints;
1599            Pixmap bs;
1600    
1601            sizehints = XAllocSizeHints();
1602            if (sizehints)
1603            {
1604                    sizehints->flags = PMinSize | PMaxSize;
1605                    sizehints->min_width = sizehints->max_width = g_width;
1606                    sizehints->min_height = sizehints->max_height = g_height;
1607                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1608                    XFree(sizehints);
1609            }
1610    
1611            if (!(g_fullscreen || g_embed_wnd))
1612            {
1613                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1614            }
1615    
1616          switch (scancode) {          /* create new backstore pixmap */
1617          case 0x2a:          if (g_backstore != 0)
1618                  key_down_state |= DShift1Mask;          {
1619                  break;                  bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1620          case 0x36:                  XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1621                  key_down_state |= DShift2Mask;                  XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1622                  break;                  XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1623          case 0x1d:                  XFreePixmap(g_display, g_backstore);
1624                  key_down_state |= DControl1Mask;                  g_backstore = bs;
                 break;  
         case 0x9d:  
                 key_down_state |= DControl2Mask;  
                 break;  
         case 0x38:  
                 key_down_state |= DMod1Mask;  
                 break;  
         case 0xb8:  
                 key_down_state |= DMod2Mask;  
                 break;  
1625          }          }
1626    }
1627    
1628    void
1629    ui_destroy_window(void)
1630    {
1631            if (g_IC != NULL)
1632                    XDestroyIC(g_IC);
1633    
1634          if( (ShiftMask & ev->state) && !((key_down_state & DShift1Mask) || (key_down_state & DShift2Mask)))          XDestroyWindow(g_display, g_wnd);
1635    }
1636    
1637    void
1638    xwin_toggle_fullscreen(void)
1639    {
1640            Pixmap contents = 0;
1641    
1642            if (g_seamless_active)
1643                    /* Turn off SeamlessRDP mode */
1644                    ui_seamless_toggle();
1645    
1646            if (!g_ownbackstore)
1647          {          {
1648                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x2a, 0);                  /* need to save contents of window */
1649                  key_down_state |= DShift1Mask;                  contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1650                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1651            }
1652    
1653            ui_destroy_window();
1654            g_fullscreen = !g_fullscreen;
1655            ui_create_window();
1656    
1657            XDefineCursor(g_display, g_wnd, g_current_cursor);
1658    
1659            if (!g_ownbackstore)
1660            {
1661                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1662                    XFreePixmap(g_display, contents);
1663          }          }
1664    }
1665    
1666          if( (ControlMask & ev->state) && !((key_down_state & DControl1Mask) || (key_down_state & DControl2Mask)))  static void
1667    handle_button_event(XEvent xevent, BOOL down)
1668    {
1669            uint16 button, flags = 0;
1670            g_last_gesturetime = xevent.xbutton.time;
1671            button = xkeymap_translate_button(xevent.xbutton.button);
1672            if (button == 0)
1673                    return;
1674    
1675            if (down)
1676                    flags = MOUSE_FLAG_DOWN;
1677    
1678            /* Stop moving window when button is released, regardless of cursor position */
1679            if (g_moving_wnd && (xevent.type == ButtonRelease))
1680                    g_moving_wnd = False;
1681    
1682            /* If win_button_size is nonzero, enable single app mode */
1683            if (xevent.xbutton.y < g_win_button_size)
1684          {          {
1685                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x1d, 0);                  /*  Check from right to left: */
1686                  key_down_state |= DControl1Mask;                  if (xevent.xbutton.x >= g_width - g_win_button_size)
1687                    {
1688                            /* The close button, continue */
1689                            ;
1690                    }
1691                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1692                    {
1693                            /* The maximize/restore button. Do not send to
1694                               server.  It might be a good idea to change the
1695                               cursor or give some other visible indication
1696                               that rdesktop inhibited this click */
1697                            if (xevent.type == ButtonPress)
1698                                    return;
1699                    }
1700                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1701                    {
1702                            /* The minimize button. Iconify window. */
1703                            if (xevent.type == ButtonRelease)
1704                            {
1705                                    /* Release the mouse button outside the minimize button, to prevent the
1706                                       actual minimazation to happen */
1707                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1708                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1709                                    return;
1710                            }
1711                    }
1712                    else if (xevent.xbutton.x <= g_win_button_size)
1713                    {
1714                            /* The system menu. Ignore. */
1715                            if (xevent.type == ButtonPress)
1716                                    return;
1717                    }
1718                    else
1719                    {
1720                            /* The title bar. */
1721                            if (xevent.type == ButtonPress)
1722                            {
1723                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1724                                    {
1725                                            g_moving_wnd = True;
1726                                            g_move_x_offset = xevent.xbutton.x;
1727                                            g_move_y_offset = xevent.xbutton.y;
1728                                    }
1729                                    return;
1730                            }
1731                    }
1732            }
1733    
1734            if (xevent.xmotion.window == g_wnd)
1735            {
1736                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1737                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1738          }          }
1739            else
1740            {
1741                    /* SeamlessRDP */
1742                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1743                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1744            }
1745    }
1746    
1747    static void
1748    ui_seamless_handle_restack(seamless_window * sw)
1749    {
1750            Status status;
1751            Window root, parent, *children;
1752            unsigned int nchildren, i;
1753            seamless_window *sw_below;
1754    
1755            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1756                                &root, &parent, &children, &nchildren);
1757            if (!status || !nchildren)
1758                    return;
1759    
1760          if( (Mod1Mask & ev->state) && !(key_down_state & DMod1Mask))          sw_below = NULL;
1761    
1762            i = 0;
1763            while (children[i] != sw->wnd)
1764          {          {
1765                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x38, 0);                  i++;
1766                  key_down_state |= DMod1Mask;                  if (i >= nchildren)
1767                            return;
1768            }
1769    
1770            for (i++; i < nchildren; i++)
1771            {
1772                    sw_below = seamless_get_window_by_wnd(children[i]);
1773                    if (sw_below)
1774                            break;
1775          }          }
1776    
1777          if( (Mod2Mask & ev->state) && !(key_down_state & DMod2Mask))          if (sw_below)
1778                    seamless_send_zchange(sw->id, sw_below->id, 0);
1779            else
1780                    seamless_send_zchange(sw->id, 0, 0);
1781    }
1782    
1783    /* Process events in Xlib queue
1784       Returns 0 after user quit, 1 otherwise */
1785    static int
1786    xwin_process_events(void)
1787    {
1788            XEvent xevent;
1789            KeySym keysym;
1790            uint32 ev_time;
1791            char str[256];
1792            Status status;
1793            int events = 0;
1794            seamless_window *sw;
1795    
1796            while ((XPending(g_display) > 0) && events++ < 20)
1797          {          {
1798                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0xb8, 0);                  XNextEvent(g_display, &xevent);
1799                  key_down_state |= DMod2Mask;  
1800                    if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1801                    {
1802                            DEBUG_KBD(("Filtering event\n"));
1803                            continue;
1804                    }
1805    
1806                    switch (xevent.type)
1807                    {
1808                            case VisibilityNotify:
1809                                    if (xevent.xvisibility.window == g_wnd)
1810                                            g_Unobscured =
1811                                                    xevent.xvisibility.state == VisibilityUnobscured;
1812    
1813                                    break;
1814                            case ClientMessage:
1815                                    /* the window manager told us to quit */
1816                                    if ((xevent.xclient.message_type == g_protocol_atom)
1817                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1818                                            /* Quit */
1819                                            return 0;
1820                                    break;
1821    
1822                            case KeyPress:
1823                                    g_last_gesturetime = xevent.xkey.time;
1824                                    if (g_IC != NULL)
1825                                            /* Multi_key compatible version */
1826                                    {
1827                                            XmbLookupString(g_IC,
1828                                                            &xevent.xkey, str, sizeof(str), &keysym,
1829                                                            &status);
1830                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1831                                            {
1832                                                    error("XmbLookupString failed with status 0x%x\n",
1833                                                          status);
1834                                                    break;
1835                                            }
1836                                    }
1837                                    else
1838                                    {
1839                                            /* Plain old XLookupString */
1840                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1841                                            XLookupString((XKeyEvent *) & xevent,
1842                                                          str, sizeof(str), &keysym, NULL);
1843                                    }
1844    
1845                                    DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1846                                               get_ksname(keysym)));
1847    
1848                                    ev_time = time(NULL);
1849                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1850                                            break;
1851    
1852                                    xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1853                                                      ev_time, True, 0);
1854                                    break;
1855    
1856                            case KeyRelease:
1857                                    g_last_gesturetime = xevent.xkey.time;
1858                                    XLookupString((XKeyEvent *) & xevent, str,
1859                                                  sizeof(str), &keysym, NULL);
1860    
1861                                    DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1862                                               get_ksname(keysym)));
1863    
1864                                    ev_time = time(NULL);
1865                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1866                                            break;
1867    
1868                                    xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1869                                                      ev_time, False, 0);
1870                                    break;
1871    
1872                            case ButtonPress:
1873                                    handle_button_event(xevent, True);
1874                                    break;
1875    
1876                            case ButtonRelease:
1877                                    handle_button_event(xevent, False);
1878                                    break;
1879    
1880                            case MotionNotify:
1881                                    if (g_moving_wnd)
1882                                    {
1883                                            XMoveWindow(g_display, g_wnd,
1884                                                        xevent.xmotion.x_root - g_move_x_offset,
1885                                                        xevent.xmotion.y_root - g_move_y_offset);
1886                                            break;
1887                                    }
1888    
1889                                    if (g_fullscreen && !g_focused)
1890                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1891                                                           CurrentTime);
1892    
1893                                    if (xevent.xmotion.window == g_wnd)
1894                                    {
1895                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1896                                                           xevent.xmotion.x, xevent.xmotion.y);
1897                                    }
1898                                    else
1899                                    {
1900                                            /* SeamlessRDP */
1901                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1902                                                           xevent.xmotion.x_root,
1903                                                           xevent.xmotion.y_root);
1904                                    }
1905                                    break;
1906    
1907                            case FocusIn:
1908                                    if (xevent.xfocus.mode == NotifyGrab)
1909                                            break;
1910                                    g_focused = True;
1911                                    reset_modifier_keys();
1912                                    if (g_grab_keyboard && g_mouse_in_wnd)
1913                                            XGrabKeyboard(g_display, g_wnd, True,
1914                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1915    
1916                                    sw = seamless_get_window_by_wnd(xevent.xfocus.window);
1917                                    if (!sw)
1918                                            break;
1919    
1920                                    seamless_send_focus(sw->id, 0);
1921                                    break;
1922    
1923                            case FocusOut:
1924                                    if (xevent.xfocus.mode == NotifyUngrab)
1925                                            break;
1926                                    g_focused = False;
1927                                    if (xevent.xfocus.mode == NotifyWhileGrabbed)
1928                                            XUngrabKeyboard(g_display, CurrentTime);
1929                                    break;
1930    
1931                            case EnterNotify:
1932                                    /* we only register for this event when in fullscreen mode */
1933                                    /* or grab_keyboard */
1934                                    g_mouse_in_wnd = True;
1935                                    if (g_fullscreen)
1936                                    {
1937                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1938                                                           CurrentTime);
1939                                            break;
1940                                    }
1941                                    if (g_focused)
1942                                            XGrabKeyboard(g_display, g_wnd, True,
1943                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1944                                    break;
1945    
1946                            case LeaveNotify:
1947                                    /* we only register for this event when grab_keyboard */
1948                                    g_mouse_in_wnd = False;
1949                                    XUngrabKeyboard(g_display, CurrentTime);
1950                                    break;
1951    
1952                            case Expose:
1953                                    if (xevent.xexpose.window == g_wnd)
1954                                    {
1955                                            XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1956                                                      g_gc,
1957                                                      xevent.xexpose.x, xevent.xexpose.y,
1958                                                      xevent.xexpose.width, xevent.xexpose.height,
1959                                                      xevent.xexpose.x, xevent.xexpose.y);
1960                                    }
1961                                    else
1962                                    {
1963                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1964                                            if (sw)
1965                                                    XCopyArea(g_display, g_backstore,
1966                                                              xevent.xexpose.window, g_gc,
1967                                                              xevent.xexpose.x + sw->xoffset,
1968                                                              xevent.xexpose.y + sw->yoffset,
1969                                                              xevent.xexpose.width,
1970                                                              xevent.xexpose.height, xevent.xexpose.x,
1971                                                              xevent.xexpose.y);
1972                                            else
1973                                            {
1974                                                    error("Expose for unknown window 0x%lx\n",
1975                                                          xevent.xexpose.window);
1976                                            }
1977                                    }
1978    
1979                                    break;
1980    
1981                            case MappingNotify:
1982                                    /* Refresh keyboard mapping if it has changed. This is important for
1983                                       Xvnc, since it allocates keycodes dynamically */
1984                                    if (xevent.xmapping.request == MappingKeyboard
1985                                        || xevent.xmapping.request == MappingModifier)
1986                                            XRefreshKeyboardMapping(&xevent.xmapping);
1987    
1988                                    if (xevent.xmapping.request == MappingModifier)
1989                                    {
1990                                            XFreeModifiermap(g_mod_map);
1991                                            g_mod_map = XGetModifierMapping(g_display);
1992                                    }
1993                                    break;
1994    
1995                                    /* clipboard stuff */
1996                            case SelectionNotify:
1997                                    xclip_handle_SelectionNotify(&xevent.xselection);
1998                                    break;
1999                            case SelectionRequest:
2000                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2001                                    break;
2002                            case SelectionClear:
2003                                    xclip_handle_SelectionClear();
2004                                    break;
2005                            case PropertyNotify:
2006                                    xclip_handle_PropertyNotify(&xevent.xproperty);
2007                                    if (xevent.xproperty.window == g_wnd)
2008                                            break;
2009                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2010                                            break;
2011    
2012                                    /* seamless */
2013                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2014                                    if (!sw)
2015                                            break;
2016    
2017                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2018                                        && (xevent.xproperty.state == PropertyNewValue))
2019                                    {
2020                                            sw->state = ewmh_get_window_state(sw->wnd);
2021                                            seamless_send_state(sw->id, sw->state, 0);
2022                                    }
2023    
2024                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2025                                        && (xevent.xproperty.state == PropertyNewValue))
2026                                    {
2027                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2028                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
2029                                    }
2030    
2031                                    break;
2032                            case MapNotify:
2033                                    if (!g_seamless_active)
2034                                            rdp_send_client_window_status(1);
2035                                    break;
2036                            case UnmapNotify:
2037                                    if (!g_seamless_active)
2038                                            rdp_send_client_window_status(0);
2039                                    break;
2040                            case ConfigureNotify:
2041                                    /* seamless */
2042                                    sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2043                                    if (!sw)
2044                                            break;
2045    
2046                                    ui_seamless_handle_restack(sw);
2047                    }
2048          }          }
2049            /* Keep going */
2050            return 1;
2051  }  }
2052    
2053  void  /* Returns 0 after user quit, 1 otherwise */
2054    int
2055  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2056  {  {
2057          int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1;          int n;
2058          fd_set rfds;          fd_set rfds, wfds;
2059            struct timeval tv;
2060          FD_ZERO(&rfds);          BOOL s_timeout = False;
2061    
2062          while (True)          while (True)
2063          {          {
2064                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2065                    /* Process any events already waiting */
2066                    if (!xwin_process_events())
2067                            /* User quit */
2068                            return 0;
2069    
2070                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2071                    FD_ZERO(&wfds);
2072                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2073                  if (display != NULL)                  FD_SET(g_x_socket, &rfds);
2074    
2075    #ifdef WITH_RDPSND
2076                    /* FIXME: there should be an API for registering fds */
2077                    if (g_dsp_busy)
2078                  {                  {
2079                          FD_SET(x_socket, &rfds);                          FD_SET(g_dsp_fd, &wfds);
2080                          XFlush(display);                          n = (g_dsp_fd > n) ? g_dsp_fd : n;
2081                  }                  }
2082    #endif
2083                    /* default timeout */
2084                    tv.tv_sec = 60;
2085                    tv.tv_usec = 0;
2086    
2087                    /* add redirection handles */
2088                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2089    
2090                  switch (select(n, &rfds, NULL, NULL, NULL))                  n++;
2091    
2092                    switch (select(n, &rfds, &wfds, NULL, &tv))
2093                  {                  {
2094                          case -1:                          case -1:
2095                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2096    
2097                          case 0:                          case 0:
2098                                    /* Abort serial read calls */
2099                                    if (s_timeout)
2100                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2101                                  continue;                                  continue;
2102                  }                  }
2103    
2104                  if (FD_ISSET(x_socket, &rfds))                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
                         xwin_process_events();  
2105    
2106                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2107                          return;                          return 1;
2108    
2109    #ifdef WITH_RDPSND
2110                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2111                            wave_out_play();
2112    #endif
2113          }          }
2114  }  }
2115    
2116  void  void
2117  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
2118  {  {
2119          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2120  }  }
2121    
2122  HBITMAP  HBITMAP
2123  ui_create_bitmap(int width, int height, uint8 *data)  ui_create_bitmap(int width, int height, uint8 * data)
2124  {  {
2125          XImage *image;          XImage *image;
2126          Pixmap bitmap;          Pixmap bitmap;
2127          uint8 *tdata;          uint8 *tdata;
2128            int bitmap_pad;
2129    
2130            if (g_server_depth == 8)
2131            {
2132                    bitmap_pad = 8;
2133            }
2134            else
2135            {
2136                    bitmap_pad = g_bpp;
2137    
2138          tdata = (owncolmap ? data : translate_image(width, height, data));                  if (g_bpp == 24)
2139          bitmap = XCreatePixmap(display, wnd, width, height, depth);                          bitmap_pad = 32;
2140          image = XCreateImage(display, visual, depth, ZPixmap,          }
2141                               0, tdata, width, height, 8, 0);  
2142            tdata = (g_owncolmap ? data : translate_image(width, height, data));
2143            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2144            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2145                                 (char *) tdata, width, height, bitmap_pad, 0);
2146    
2147          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2148    
2149          XFree(image);          XFree(image);
2150          if (!owncolmap)          if (tdata != data)
2151                  xfree(tdata);                  xfree(tdata);
2152          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2153  }  }
2154    
2155  void  void
2156  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)  
2157  {  {
2158          XImage *image;          XImage *image;
2159          uint8 *tdata;          uint8 *tdata;
2160            int bitmap_pad;
2161    
2162            if (g_server_depth == 8)
2163            {
2164                    bitmap_pad = 8;
2165            }
2166            else
2167            {
2168                    bitmap_pad = g_bpp;
2169    
2170                    if (g_bpp == 24)
2171                            bitmap_pad = 32;
2172            }
2173    
2174          tdata = (owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2175          image = XCreateImage(display, visual, depth, ZPixmap,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2176                               0, tdata, width, height, 8, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2177    
2178          if (ownbackstore)          if (g_ownbackstore)
2179          {          {
2180                  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);
2181                  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);
2182                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2183                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2184                                             x - sw->xoffset, y - sw->yoffset));
2185          }          }
2186          else          else
2187          {          {
2188                  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);
2189                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2190                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2191                                             x - sw->xoffset, y - sw->yoffset));
2192          }          }
2193    
2194          XFree(image);          XFree(image);
2195          if (!owncolmap)          if (tdata != data)
2196                  xfree(tdata);                  xfree(tdata);
2197  }  }
2198    
2199  void  void
2200  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(HBITMAP bmp)
2201  {  {
2202          XFreePixmap(display, (Pixmap)bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2203  }  }
2204    
2205  HGLYPH  HGLYPH
2206  ui_create_glyph(int width, int height, uint8 *data)  ui_create_glyph(int width, int height, uint8 * data)
2207  {  {
2208          XImage *image;          XImage *image;
2209          Pixmap bitmap;          Pixmap bitmap;
2210          int scanline;          int scanline;
         GC gc;  
2211    
2212          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2213    
2214          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2215          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2216                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2217    
2218          image = XCreateImage(display, visual, 1, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2219                               data, width, height, 8, scanline);                               width, height, 8, scanline);
2220          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2221          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2222          XInitImage(image);          XInitImage(image);
2223    
2224          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);
2225    
2226          XFree(image);          XFree(image);
2227          XFreeGC(display, gc);          return (HGLYPH) bitmap;
         return (HGLYPH)bitmap;  
2228  }  }
2229    
2230  void  void
2231  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
2232  {  {
2233          XFreePixmap(display, (Pixmap)glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2234  }  }
2235    
2236  HCURSOR  HCURSOR
2237  ui_create_cursor(unsigned int x, unsigned int y, int width,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2238                   int height, uint8 *andmask, uint8 *xormask)                   uint8 * andmask, uint8 * xormask)
2239  {  {
2240          HGLYPH maskglyph, cursorglyph;          HGLYPH maskglyph, cursorglyph;
2241          XColor bg, fg;          XColor bg, fg;
# Line 726  ui_create_cursor(unsigned int x, unsigne Line 2249  ui_create_cursor(unsigned int x, unsigne
2249          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2250          offset = scanline * height;          offset = scanline * height;
2251    
2252          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
2253          memset(cursor, 0, offset);          memset(cursor, 0, offset);
2254    
2255          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
2256          memset(mask, 0, offset);          memset(mask, 0, offset);
2257    
2258          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 769  ui_create_cursor(unsigned int x, unsigne Line 2292  ui_create_cursor(unsigned int x, unsigne
2292    
2293          cursorglyph = ui_create_glyph(width, height, cursor);          cursorglyph = ui_create_glyph(width, height, cursor);
2294          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2295            
2296          xcursor = XCreatePixmapCursor(display, (Pixmap)cursorglyph,          xcursor =
2297                                  (Pixmap)maskglyph, &fg, &bg, x, y);                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2298                                        (Pixmap) maskglyph, &fg, &bg, x, y);
2299    
2300          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
2301          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2302          xfree(mask);          xfree(mask);
2303          xfree(cursor);          xfree(cursor);
2304          return (HCURSOR)xcursor;          return (HCURSOR) xcursor;
2305  }  }
2306    
2307  void  void
2308  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2309  {  {
2310          XDefineCursor(display, wnd, (Cursor)cursor);          g_current_cursor = (Cursor) cursor;
2311            XDefineCursor(g_display, g_wnd, g_current_cursor);
2312            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2313  }  }
2314    
2315  void  void
2316  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(HCURSOR cursor)
2317  {  {
2318          XFreeCursor(display, (Cursor)cursor);          XFreeCursor(g_display, (Cursor) cursor);
2319    }
2320    
2321    void
2322    ui_set_null_cursor(void)
2323    {
2324            ui_set_cursor(g_null_cursor);
2325  }  }
2326    
2327  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 798  ui_destroy_cursor(HCURSOR cursor) Line 2330  ui_destroy_cursor(HCURSOR cursor)
2330                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2331                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2332    
2333    
2334  HCOLOURMAP  HCOLOURMAP
2335  ui_create_colourmap(COLOURMAP *colours)  ui_create_colourmap(COLOURMAP * colours)
2336  {  {
2337          COLOURENTRY *entry;          COLOURENTRY *entry;
2338          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2339            if (!g_owncolmap)
         if (owncolmap)  
2340          {          {
2341                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2342                  Colormap map;                  XColor xentry;
2343                    XColor xc_cache[256];
2344                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
2345                    int colLookup = 256;
2346                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2347                  {                  {
2348                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2349                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
                         xentry->pixel = i;  
                         MAKE_XCOLOR(xentry, entry);  
                 }  
2350    
2351                  map = XCreateColormap(display, wnd, visual, AllocAll);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2352                  XStoreColors(display, map, xcolours, ncolours);                          {
2353                                    /* Allocation failed, find closest match. */
2354                                    int j = 256;
2355                                    int nMinDist = 3 * 256 * 256;
2356                                    long nDist = nMinDist;
2357    
2358                  xfree(xcolours);                                  /* only get the colors once */
2359                  return (HCOLOURMAP)map;                                  while (colLookup--)
2360                                    {
2361                                            xc_cache[colLookup].pixel = colLookup;
2362                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2363                                                    xc_cache[colLookup].blue = 0;
2364                                            xc_cache[colLookup].flags = 0;
2365                                            XQueryColor(g_display,
2366                                                        DefaultColormap(g_display,
2367                                                                        DefaultScreen(g_display)),
2368                                                        &xc_cache[colLookup]);
2369                                    }
2370                                    colLookup = 0;
2371    
2372                                    /* approximate the pixel */
2373                                    while (j--)
2374                                    {
2375                                            if (xc_cache[j].flags)
2376                                            {
2377                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2378                                                             (long) (xentry.red >> 8)) *
2379                                                            ((long) (xc_cache[j].red >> 8) -
2380                                                             (long) (xentry.red >> 8)) +
2381                                                            ((long) (xc_cache[j].green >> 8) -
2382                                                             (long) (xentry.green >> 8)) *
2383                                                            ((long) (xc_cache[j].green >> 8) -
2384                                                             (long) (xentry.green >> 8)) +
2385                                                            ((long) (xc_cache[j].blue >> 8) -
2386                                                             (long) (xentry.blue >> 8)) *
2387                                                            ((long) (xc_cache[j].blue >> 8) -
2388                                                             (long) (xentry.blue >> 8));
2389                                            }
2390                                            if (nDist < nMinDist)
2391                                            {
2392                                                    nMinDist = nDist;
2393                                                    xentry.pixel = j;
2394                                            }
2395                                    }
2396                            }
2397                            colour = xentry.pixel;
2398    
2399                            /* update our cache */
2400                            if (xentry.pixel < 256)
2401                            {
2402                                    xc_cache[xentry.pixel].red = xentry.red;
2403                                    xc_cache[xentry.pixel].green = xentry.green;
2404                                    xc_cache[xentry.pixel].blue = xentry.blue;
2405    
2406                            }
2407    
2408                            map[i] = colour;
2409                    }
2410                    return map;
2411          }          }
2412          else          else
2413          {          {
2414                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
2415                  XColor xentry;                  Colormap map;
                 uint32 colour;  
2416    
2417                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2418                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2419                  {                  {
2420                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2421                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
2422                            xentry->pixel = i;
2423                          if (XAllocColor(display, xcolmap, &xentry) != 0)                          MAKE_XCOLOR(xentry, entry);
                                 colour = xentry.pixel;  
                         else  
                                 colour = white;  
   
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
2424                  }                  }
2425    
2426                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2427                    XStoreColors(g_display, map, xcolours, ncolours);
2428    
2429                    xfree(xcolours);
2430                    return (HCOLOURMAP) map;
2431          }          }
2432  }  }
2433    
2434  void  void
2435  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(HCOLOURMAP map)
2436  {  {
2437          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap)map);  
         else  
2438                  xfree(map);                  xfree(map);
2439            else
2440                    XFreeColormap(g_display, (Colormap) map);
2441  }  }
2442    
2443  void  void
2444  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(HCOLOURMAP map)
2445  {  {
2446          if (owncolmap)          if (!g_owncolmap)
2447                  XSetWindowColormap(display, wnd, (Colormap)map);          {
2448                    if (g_colmap)
2449                            xfree(g_colmap);
2450    
2451                    g_colmap = (uint32 *) map;
2452            }
2453          else          else
2454                  colmap = map;          {
2455                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2456                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2457            }
2458  }  }
2459    
2460  void  void
2461  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2462  {  {
2463          XRectangle rect;          g_clip_rectangle.x = x;
2464            g_clip_rectangle.y = y;
2465          rect.x = x;          g_clip_rectangle.width = cx;
2466          rect.y = y;          g_clip_rectangle.height = cy;
2467          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);  
2468  }  }
2469    
2470  void  void
2471  ui_reset_clip()  ui_reset_clip(void)
2472  {  {
2473          XRectangle rect;          g_clip_rectangle.x = 0;
2474            g_clip_rectangle.y = 0;
2475          rect.x = 0;          g_clip_rectangle.width = g_width;
2476          rect.y = 0;          g_clip_rectangle.height = g_height;
2477          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);  
2478  }  }
2479    
2480  void  void
2481  ui_bell()  ui_bell(void)
2482  {  {
2483          XBell(display, 0);          XBell(g_display, 0);
2484  }  }
2485    
2486  void  void
# Line 905  ui_destblt(uint8 opcode, Line 2492  ui_destblt(uint8 opcode,
2492          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2493  }  }
2494    
2495    static uint8 hatch_patterns[] = {
2496            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2497            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2498            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2499            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2500            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2501            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2502    };
2503    
2504  void  void
2505  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2506            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2507            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2508  {  {
2509          Pixmap fill;          Pixmap fill;
2510            uint8 i, ipattern[8];
2511    
2512          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2513    
# Line 918  ui_patblt(uint8 opcode, Line 2515  ui_patblt(uint8 opcode,
2515          {          {
2516                  case 0: /* Solid */                  case 0: /* Solid */
2517                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2518                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2519                          break;                          break;
2520    
2521                  case 3: /* Pattern */                  case 2: /* Hatch */
2522                          fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);                          fill = (Pixmap) ui_create_glyph(8, 8,
2523                                                            hatch_patterns + brush->pattern[0] * 8);
2524                            SET_FOREGROUND(fgcolour);
2525                            SET_BACKGROUND(bgcolour);
2526                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2527                            XSetStipple(g_display, g_gc, fill);
2528                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2529                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2530                            XSetFillStyle(g_display, g_gc, FillSolid);
2531                            XSetTSOrigin(g_display, g_gc, 0, 0);
2532                            ui_destroy_glyph((HGLYPH) fill);
2533                            break;
2534    
2535                    case 3: /* Pattern */
2536                            for (i = 0; i != 8; i++)
2537                                    ipattern[7 - i] = brush->pattern[i];
2538                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2539                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2540                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2541                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2542                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2543                          XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2544                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2545                          FILL_RECTANGLE(x, y, cx, cy);                          XSetFillStyle(g_display, g_gc, FillSolid);
2546                            XSetTSOrigin(g_display, g_gc, 0, 0);
2547                          XSetFillStyle(display, gc, FillSolid);                          ui_destroy_glyph((HGLYPH) fill);
                         ui_destroy_glyph((HGLYPH)fill);  
2548                          break;                          break;
2549    
2550                  default:                  default:
# Line 941  ui_patblt(uint8 opcode, Line 2552  ui_patblt(uint8 opcode,
2552          }          }
2553    
2554          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2555    
2556            if (g_ownbackstore)
2557                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2558            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2559                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2560                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2561  }  }
2562    
2563  void  void
# Line 949  ui_screenblt(uint8 opcode, Line 2566  ui_screenblt(uint8 opcode,
2566               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2567  {  {
2568          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2569          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2570          if (ownbackstore)          {
2571                  XCopyArea(display, backstore, backstore, gc, srcx, srcy,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2572                            cx, cy, x, y);                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2573                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2574            }
2575            else
2576            {
2577                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2578            }
2579    
2580            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2581                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2582                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2583    
2584          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2585  }  }
2586    
# Line 962  ui_memblt(uint8 opcode, Line 2590  ui_memblt(uint8 opcode,
2590            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ HBITMAP src, int srcx, int srcy)
2591  {  {
2592          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2593          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);
2594          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2595                  XCopyArea(display, (Pixmap)src, backstore, gc, srcx, srcy,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
2596                            cx, cy, x, y);                                   srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2597            if (g_ownbackstore)
2598                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2599          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2600  }  }
2601    
# Line 973  void Line 2603  void
2603  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2604            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2605            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ HBITMAP src, int srcx, int srcy,
2606            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2607  {  {
2608          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
2609             comes up with a more efficient way of doing it I am using cases. */             comes up with a more efficient way of doing it I am using cases. */
# Line 982  ui_triblt(uint8 opcode, Line 2612  ui_triblt(uint8 opcode,
2612          {          {
2613                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
2614                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2615                          ui_patblt(ROP2_NXOR, x, y, cx, cy,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2616                          break;                          break;
2617    
2618                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2619                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2620                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2621                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2622                          break;                          break;
2623    
2624                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
2625                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2626                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2627                          break;                          break;
2628    
2629                  default:                  default:
# Line 1009  ui_triblt(uint8 opcode, Line 2635  ui_triblt(uint8 opcode,
2635  void  void
2636  ui_line(uint8 opcode,  ui_line(uint8 opcode,
2637          /* dest */ int startx, int starty, int endx, int endy,          /* dest */ int startx, int starty, int endx, int endy,
2638          /* pen */ PEN *pen)          /* pen */ PEN * pen)
2639  {  {
2640          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2641          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2642          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2643          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2644                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
2645                                                endx - sw->xoffset, endy - sw->yoffset));
2646            if (g_ownbackstore)
2647                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2648          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2649  }  }
2650    
# Line 1029  ui_rect( Line 2658  ui_rect(
2658  }  }
2659    
2660  void  void
2661    ui_polygon(uint8 opcode,
2662               /* mode */ uint8 fillmode,
2663               /* dest */ POINT * point, int npoints,
2664               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2665    {
2666            uint8 style, i, ipattern[8];
2667            Pixmap fill;
2668    
2669            SET_FUNCTION(opcode);
2670    
2671            switch (fillmode)
2672            {
2673                    case ALTERNATE:
2674                            XSetFillRule(g_display, g_gc, EvenOddRule);
2675                            break;
2676                    case WINDING:
2677                            XSetFillRule(g_display, g_gc, WindingRule);
2678                            break;
2679                    default:
2680                            unimpl("fill mode %d\n", fillmode);
2681            }
2682    
2683            if (brush)
2684                    style = brush->style;
2685            else
2686                    style = 0;
2687    
2688            switch (style)
2689            {
2690                    case 0: /* Solid */
2691                            SET_FOREGROUND(fgcolour);
2692                            FILL_POLYGON((XPoint *) point, npoints);
2693                            break;
2694    
2695                    case 2: /* Hatch */
2696                            fill = (Pixmap) ui_create_glyph(8, 8,
2697                                                            hatch_patterns + brush->pattern[0] * 8);
2698                            SET_FOREGROUND(fgcolour);
2699                            SET_BACKGROUND(bgcolour);
2700                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2701                            XSetStipple(g_display, g_gc, fill);
2702                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2703                            FILL_POLYGON((XPoint *) point, npoints);
2704                            XSetFillStyle(g_display, g_gc, FillSolid);
2705                            XSetTSOrigin(g_display, g_gc, 0, 0);
2706                            ui_destroy_glyph((HGLYPH) fill);
2707                            break;
2708    
2709                    case 3: /* Pattern */
2710                            for (i = 0; i != 8; i++)
2711                                    ipattern[7 - i] = brush->pattern[i];
2712                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2713                            SET_FOREGROUND(bgcolour);
2714                            SET_BACKGROUND(fgcolour);
2715                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2716                            XSetStipple(g_display, g_gc, fill);
2717                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2718                            FILL_POLYGON((XPoint *) point, npoints);
2719                            XSetFillStyle(g_display, g_gc, FillSolid);
2720                            XSetTSOrigin(g_display, g_gc, 0, 0);
2721                            ui_destroy_glyph((HGLYPH) fill);
2722                            break;
2723    
2724                    default:
2725                            unimpl("brush %d\n", brush->style);
2726            }
2727    
2728            RESET_FUNCTION(opcode);
2729    }
2730    
2731    void
2732    ui_polyline(uint8 opcode,
2733                /* dest */ POINT * points, int npoints,
2734                /* pen */ PEN * pen)
2735    {
2736            /* TODO: set join style */
2737            SET_FUNCTION(opcode);
2738            SET_FOREGROUND(pen->colour);
2739            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2740            if (g_ownbackstore)
2741                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2742                               CoordModePrevious);
2743    
2744            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2745                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2746    
2747            RESET_FUNCTION(opcode);
2748    }
2749    
2750    void
2751    ui_ellipse(uint8 opcode,
2752               /* mode */ uint8 fillmode,
2753               /* dest */ int x, int y, int cx, int cy,
2754               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2755    {
2756            uint8 style, i, ipattern[8];
2757            Pixmap fill;
2758    
2759            SET_FUNCTION(opcode);
2760    
2761            if (brush)
2762                    style = brush->style;
2763            else
2764                    style = 0;
2765    
2766            switch (style)
2767            {
2768                    case 0: /* Solid */
2769                            SET_FOREGROUND(fgcolour);
2770                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2771                            break;
2772    
2773                    case 2: /* Hatch */
2774                            fill = (Pixmap) ui_create_glyph(8, 8,
2775                                                            hatch_patterns + brush->pattern[0] * 8);
2776                            SET_FOREGROUND(fgcolour);
2777                            SET_BACKGROUND(bgcolour);
2778                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2779                            XSetStipple(g_display, g_gc, fill);
2780                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2781                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2782                            XSetFillStyle(g_display, g_gc, FillSolid);
2783                            XSetTSOrigin(g_display, g_gc, 0, 0);
2784                            ui_destroy_glyph((HGLYPH) fill);
2785                            break;
2786    
2787                    case 3: /* Pattern */
2788                            for (i = 0; i != 8; i++)
2789                                    ipattern[7 - i] = brush->pattern[i];
2790                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2791                            SET_FOREGROUND(bgcolour);
2792                            SET_BACKGROUND(fgcolour);
2793                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2794                            XSetStipple(g_display, g_gc, fill);
2795                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2796                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2797                            XSetFillStyle(g_display, g_gc, FillSolid);
2798                            XSetTSOrigin(g_display, g_gc, 0, 0);
2799                            ui_destroy_glyph((HGLYPH) fill);
2800                            break;
2801    
2802                    default:
2803                            unimpl("brush %d\n", brush->style);
2804            }
2805    
2806            RESET_FUNCTION(opcode);
2807    }
2808    
2809    /* warning, this function only draws on wnd or backstore, not both */
2810    void
2811  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
2812                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
2813                /* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour,                /* src */ HGLYPH glyph, int srcx, int srcy,
2814                int fgcolour)                int bgcolour, int fgcolour)
2815  {  {
2816          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
2817          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
2818    
2819          XSetFillStyle(display, gc, (mixmode == MIX_TRANSPARENT)          XSetFillStyle(g_display, g_gc,
2820                        ? FillStippled : FillOpaqueStippled);                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2821          XSetStipple(display, gc, (Pixmap)glyph);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
2822          XSetTSOrigin(display, gc, x, y);          XSetTSOrigin(g_display, g_gc, x, y);
2823    
2824          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2825    
2826          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
2827  }  }
2828    
2829  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
2830  {\  {\
2831    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
2832    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
2833      {\
2834        xyoffset = ttext[++idx];\
2835        if ((xyoffset & 0x80))\
2836      {\      {\
2837        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
2838        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);\  
         }\  
2839        else\        else\
2840          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
2841            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
2842      }\      }\
2843    if (glyph != NULL)\      else\
2844      {\      {\
2845        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
2846                       y + (short) glyph->baseline,\          y += xyoffset;\
2847                       glyph->width, glyph->height,\        else\
2848                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
2849      }\      }\
2850      }\
2851      if (glyph != NULL)\
2852      {\
2853        x1 = x + glyph->offset;\
2854        y1 = y + glyph->baseline;\
2855        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2856        XSetTSOrigin(g_display, g_gc, x1, y1);\
2857        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2858        if (flags & TEXT2_IMPLICIT_X)\
2859          x += glyph->width;\
2860      }\
2861  }  }
2862    
2863  void  void
2864  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,
2865               int clipx, int clipy, int clipcx, int clipcy, int boxx,               int clipx, int clipy, int clipcx, int clipcy,
2866               int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2867               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2868  {  {
2869            /* TODO: use brush appropriately */
2870    
2871          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2872          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
2873          DATABLOB *entry;          DATABLOB *entry;
2874    
2875          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2876    
2877            /* Sometimes, the boxcx value is something really large, like
2878               32691. This makes XCopyArea fail with Xvnc. The code below
2879               is a quick fix. */
2880            if (boxx + boxcx > g_width)
2881                    boxcx = g_width - boxx;
2882    
2883          if (boxcx > 1)          if (boxcx > 1)
2884          {          {
2885                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2886          }          }
2887          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
2888          {          {
2889                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2890          }          }
2891    
2892            SET_FOREGROUND(fgcolour);
2893            SET_BACKGROUND(bgcolour);
2894            XSetFillStyle(g_display, g_gc, FillStippled);
2895    
2896          /* Paint text, character by character */          /* Paint text, character by character */
2897          for (i = 0; i < length;) {          for (i = 0; i < length;)
2898                  switch (text[i]) {          {
2899                  case 0xff:                  switch (text[i])
2900                          if (i + 2 < length)                  {
2901                            case 0xff:
2902                                    /* At least two bytes needs to follow */
2903                                    if (i + 3 > length)
2904                                    {
2905                                            warning("Skipping short 0xff command:");
2906                                            for (j = 0; j < length; j++)
2907                                                    fprintf(stderr, "%02x ", text[j]);
2908                                            fprintf(stderr, "\n");
2909                                            i = length = 0;
2910                                            break;
2911                                    }
2912                                  cache_put_text(text[i + 1], text, text[i + 2]);                                  cache_put_text(text[i + 1], text, text[i + 2]);
2913                          else {                                  i += 3;
2914                                  error("this shouldn't be happening\n");                                  length -= i;
2915                                    /* this will move pointer from start to first character after FF command */
2916                                    text = &(text[i]);
2917                                    i = 0;
2918                                  break;                                  break;
2919                          }  
2920                          /* this will move pointer from start to first character after FF command */                          case 0xfe:
2921                          length -= i + 3;                                  /* At least one byte needs to follow */
2922                          text = &(text[i + 3]);                                  if (i + 2 > length)
2923                          i = 0;                                  {
2924                          break;                                          warning("Skipping short 0xfe command:");
2925                                            for (j = 0; j < length; j++)
2926                  case 0xfe:                                                  fprintf(stderr, "%02x ", text[j]);
2927                          entry = cache_get_text(text[i + 1]);                                          fprintf(stderr, "\n");
2928                          if (entry != NULL) {                                          i = length = 0;
2929                                  if ((((uint8 *) (entry->data))[1] == 0)                                          break;
2930                                      && (!(flags & TEXT2_IMPLICIT_X))) {                                  }
2931                                          if (flags & TEXT2_VERTICAL)                                  entry = cache_get_text(text[i + 1]);
2932                                                  y += text[i + 2];                                  if (entry->data != NULL)
2933                                          else                                  {
2934                                                  x += text[i + 2];                                          if ((((uint8 *) (entry->data))[1] == 0)
2935                                                && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2936                                            {
2937                                                    if (flags & TEXT2_VERTICAL)
2938                                                            y += text[i + 2];
2939                                                    else
2940                                                            x += text[i + 2];
2941                                            }
2942                                            for (j = 0; j < entry->size; j++)
2943                                                    DO_GLYPH(((uint8 *) (entry->data)), j);
2944                                  }                                  }
2945                                  if (i + 2 < length)                                  if (i + 2 < length)
2946                                          i += 3;                                          i += 3;
2947                                  else                                  else
2948                                          i += 2;                                          i += 2;
2949                                  length -= i;                                  length -= i;
2950                                  /* this will move pointer from start to first character after FE command */                                  /* this will move pointer from start to first character after FE command */
2951                                  text = &(text[i]);                                  text = &(text[i]);
2952                                  i = 0;                                  i = 0;
2953                                  for (j = 0; j < entry->size; j++)                                  break;
                                         DO_GLYPH(((uint8 *) (entry->data)), j);  
                         }  
                         break;  
2954    
2955                  default:                          default:
2956                          DO_GLYPH(text, i);                                  DO_GLYPH(text, i);
2957                          i++;                                  i++;
2958                          break;                                  break;
2959                  }                  }
2960          }          }
2961    
2962            XSetFillStyle(g_display, g_gc, FillSolid);
2963    
2964            if (g_ownbackstore)
2965            {
2966                    if (boxcx > 1)
2967                    {
2968                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2969                                      boxy, boxcx, boxcy, boxx, boxy);
2970                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2971                                                    (g_display, g_backstore, sw->wnd, g_gc,
2972                                                     boxx, boxy,
2973                                                     boxcx, boxcy,
2974                                                     boxx - sw->xoffset, boxy - sw->yoffset));
2975                    }
2976                    else
2977                    {
2978                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2979                                      clipy, clipcx, clipcy, clipx, clipy);
2980                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2981                                                    (g_display, g_backstore, sw->wnd, g_gc,
2982                                                     clipx, clipy,
2983                                                     clipcx, clipcy, clipx - sw->xoffset,
2984                                                     clipy - sw->yoffset));
2985                    }
2986            }
2987  }  }
2988    
2989  void  void
# Line 1155  ui_desktop_save(uint32 offset, int x, in Line 2992  ui_desktop_save(uint32 offset, int x, in
2992          Pixmap pix;          Pixmap pix;
2993          XImage *image;          XImage *image;
2994    
2995          if (ownbackstore)          if (g_ownbackstore)
2996          {          {
2997                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
                                   ZPixmap);  
2998          }          }
2999          else          else
3000          {          {
3001                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3002                  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);
3003                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3004                                    ZPixmap);                  XFreePixmap(g_display, pix);
                 XFreePixmap(display, pix);  
3005          }          }
3006    
3007          offset *= bpp/8;          offset *= g_bpp / 8;
3008          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);  
3009    
3010          XDestroyImage(image);          XDestroyImage(image);
3011  }  }
# Line 1182  ui_desktop_restore(uint32 offset, int x, Line 3016  ui_desktop_restore(uint32 offset, int x,
3016          XImage *image;          XImage *image;
3017          uint8 *data;          uint8 *data;
3018    
3019          offset *= bpp/8;          offset *= g_bpp / 8;
3020          data = cache_get_desktop(offset, cx, cy, bpp/8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3021          if (data == NULL)          if (data == NULL)
3022                  return;                  return;
3023    
3024          image = XCreateImage(display, visual, depth, ZPixmap,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3025                               0, data, cx, cy, BitmapPad(display),                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
                              cx * bpp/8);  
3026    
3027          if (ownbackstore)          if (g_ownbackstore)
3028          {          {
3029                  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);
3030                  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);
3031                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3032                                            (g_display, g_backstore, sw->wnd, g_gc,
3033                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3034          }          }
3035          else          else
3036          {          {
3037                  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);
3038                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3039                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3040                                             x - sw->xoffset, y - sw->yoffset));
3041          }          }
3042    
3043          XFree(image);          XFree(image);
3044  }  }
3045    
3046    /* these do nothing here but are used in uiports */
3047    void
3048    ui_begin_update(void)
3049    {
3050    }
3051    
3052    void
3053    ui_end_update(void)
3054    {
3055    }
3056    
3057    void
3058    ui_seamless_begin()
3059    {
3060            if (!g_seamless_rdp)
3061                    return;
3062    
3063            if (g_seamless_started)
3064                    return;
3065    
3066            g_seamless_started = True;
3067    
3068            ui_seamless_toggle();
3069    }
3070    
3071    void
3072    ui_seamless_toggle()
3073    {
3074            if (!g_seamless_rdp)
3075                    return;
3076    
3077            if (!g_seamless_started)
3078                    return;
3079    
3080            if (g_seamless_active)
3081            {
3082                    /* Deactivate */
3083                    while (g_seamless_windows)
3084                    {
3085                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3086                            seamless_remove_window(g_seamless_windows);
3087                    }
3088                    XMapWindow(g_display, g_wnd);
3089            }
3090            else
3091            {
3092                    /* Activate */
3093                    XUnmapWindow(g_display, g_wnd);
3094                    seamless_send_sync();
3095            }
3096    
3097            g_seamless_active = !g_seamless_active;
3098    }
3099    
3100    void
3101    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3102    {
3103            Window wnd;
3104            XSetWindowAttributes attribs;
3105            XClassHint *classhints;
3106            XSizeHints *sizehints;
3107            long input_mask;
3108            seamless_window *sw, *sw_parent;
3109    
3110            if (!g_seamless_active)
3111                    return;
3112    
3113            /* Ignore CREATEs for existing windows */
3114            sw = seamless_get_window_by_id(id);
3115            if (sw)
3116                    return;
3117    
3118            get_window_attribs(&attribs);
3119            attribs.override_redirect = False;
3120    
3121            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3122                                InputOutput, g_visual,
3123                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3124                                CWBorderPixel, &attribs);
3125    
3126            XStoreName(g_display, wnd, "SeamlessRDP");
3127            ewmh_set_wm_name(wnd, "SeamlessRDP");
3128    
3129            mwm_hide_decorations(wnd);
3130    
3131            classhints = XAllocClassHint();
3132            if (classhints != NULL)
3133            {
3134                    classhints->res_name = "rdesktop";
3135                    classhints->res_class = "SeamlessRDP";
3136                    XSetClassHint(g_display, wnd, classhints);
3137                    XFree(classhints);
3138            }
3139    
3140            /* WM_NORMAL_HINTS */
3141            sizehints = XAllocSizeHints();
3142            if (sizehints != NULL)
3143            {
3144                    sizehints->flags = USPosition;
3145                    XSetWMNormalHints(g_display, wnd, sizehints);
3146                    XFree(sizehints);
3147            }
3148    
3149            /* Set WM_TRANSIENT_FOR, if necessary */
3150            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3151            {
3152                    sw_parent = seamless_get_window_by_id(parent);
3153                    if (sw_parent)
3154                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3155                    else
3156                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3157            }
3158    
3159    
3160            /* FIXME: Support for Input Context:s */
3161    
3162            get_input_mask(&input_mask);
3163            input_mask |= PropertyChangeMask;
3164    
3165            XSelectInput(g_display, wnd, input_mask);
3166    
3167            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3168               seamless window, we could try to close the window on the
3169               serverside, instead of terminating rdesktop */
3170            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3171    
3172            sw = malloc(sizeof(seamless_window));
3173            sw->wnd = wnd;
3174            sw->id = id;
3175            sw->parent = parent;
3176            sw->xoffset = 0;
3177            sw->yoffset = 0;
3178            sw->width = 0;
3179            sw->height = 0;
3180            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3181            sw->desktop = 0;
3182            sw->next = g_seamless_windows;
3183            g_seamless_windows = sw;
3184    }
3185    
3186    
3187    void
3188    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3189    {
3190            seamless_window *sw;
3191    
3192            if (!g_seamless_active)
3193                    return;
3194    
3195            sw = seamless_get_window_by_id(id);
3196            if (!sw)
3197            {
3198                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3199                    return;
3200            }
3201    
3202            XDestroyWindow(g_display, sw->wnd);
3203            seamless_remove_window(sw);
3204    }
3205    
3206    
3207    void
3208    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3209    {
3210            seamless_window *sw;
3211    
3212            if (!g_seamless_active)
3213                    return;
3214    
3215            sw = seamless_get_window_by_id(id);
3216            if (!sw)
3217            {
3218                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3219                    return;
3220            }
3221    
3222            if (!width || !height)
3223                    /* X11 windows must be at least 1x1 */
3224                    return;
3225    
3226            /* About MAX and MIN: Windows allows moving a window outside
3227               the desktop. This happens, for example, when maximizing an
3228               application. In this case, the position is set to something
3229               like -4,-4,1288,1032. Many WMs does not allow windows
3230               outside the desktop, however. Therefore, clip the window
3231               ourselves. */
3232            sw->xoffset = MAX(0, x);
3233            sw->yoffset = MAX(0, y);
3234            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3235            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3236    
3237            /* If we move the window in a maximized state, then KDE won't
3238               accept restoration */
3239            switch (sw->state)
3240            {
3241                    case SEAMLESSRDP_MINIMIZED:
3242                    case SEAMLESSRDP_MAXIMIZED:
3243                            return;
3244            }
3245    
3246            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3247            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3248    }
3249    
3250    void
3251    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3252    {
3253            seamless_window *sw;
3254    
3255            if (!g_seamless_active)
3256                    return;
3257    
3258            sw = seamless_get_window_by_id(id);
3259            if (!sw)
3260            {
3261                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3262                    return;
3263            }
3264    
3265            if (behind)
3266            {
3267                    seamless_window *sw_behind;
3268                    Window wnds[2];
3269    
3270                    sw_behind = seamless_get_window_by_id(behind);
3271                    if (!sw_behind)
3272                    {
3273                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3274                                    behind);
3275                            return;
3276                    }
3277    
3278                    wnds[1] = sw_behind->wnd;
3279                    wnds[0] = sw->wnd;
3280    
3281                    XRestackWindows(g_display, wnds, 2);
3282            }
3283            else
3284            {
3285                    XRaiseWindow(g_display, sw->wnd);
3286            }
3287    }
3288    
3289    void
3290    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3291    {
3292            seamless_window *sw;
3293    
3294            if (!g_seamless_active)
3295                    return;
3296    
3297            sw = seamless_get_window_by_id(id);
3298            if (!sw)
3299            {
3300                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3301                    return;
3302            }
3303    
3304            /* FIXME: Might want to convert the name for non-EWMH WMs */
3305            XStoreName(g_display, sw->wnd, title);
3306            ewmh_set_wm_name(sw->wnd, title);
3307    }
3308    
3309    
3310    void
3311    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3312    {
3313            seamless_window *sw;
3314    
3315            if (!g_seamless_active)
3316                    return;
3317    
3318            sw = seamless_get_window_by_id(id);
3319            if (!sw)
3320            {
3321                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3322                    return;
3323            }
3324    
3325            switch (state)
3326            {
3327                    case SEAMLESSRDP_NORMAL:
3328                    case SEAMLESSRDP_MAXIMIZED:
3329                            ewmh_change_state(sw->wnd, state);
3330                            XMapWindow(g_display, sw->wnd);
3331                            break;
3332                    case SEAMLESSRDP_MINIMIZED:
3333                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3334                               the Window Manager should probably just ignore the request, since
3335                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3336                               such as minimization, rather than an independent state." Besides,
3337                               XIconifyWindow is easier. */
3338                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3339                            {
3340                                    XWMHints *hints;
3341                                    hints = XAllocWMHints();
3342                                    hints->flags = StateHint;
3343                                    hints->initial_state = IconicState;
3344                                    XSetWMHints(g_display, sw->wnd, hints);
3345                                    XFree(hints);
3346                                    XMapWindow(g_display, sw->wnd);
3347                            }
3348                            else
3349                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3350                            break;
3351                    default:
3352                            warning("SeamlessRDP: Invalid state %d\n", state);
3353                            break;
3354            }
3355    
3356            /* Handle popups without parents through some ewm hints */
3357            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3358                    ewmh_set_window_popup(sw->wnd);
3359    
3360            sw->state = state;
3361    }
3362    
3363    
3364    void
3365    ui_seamless_syncbegin(unsigned long flags)
3366    {
3367            if (!g_seamless_active)
3368                    return;
3369    
3370            /* Destroy all seamless windows */
3371            while (g_seamless_windows)
3372            {
3373                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3374                    seamless_remove_window(g_seamless_windows);
3375            }
3376    }

Legend:
Removed from v.53  
changed lines
  Added in v.1154

  ViewVC Help
Powered by ViewVC 1.1.26