/[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 54 by n-ki, Fri Jun 7 07:49:59 2002 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1149 by ossman_, Thu Mar 16 15:27:59 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    static void
173    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
174    {
175            points[0].x -= xoffset;
176            points[0].y -= yoffset;
177            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
178            points[0].x += xoffset;
179            points[0].y += yoffset;
180    }
181    
182  /* needed to keep track of the modifiers */  static void
183  static unsigned int numlock_modifier_mask = 0;  seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
184  static unsigned int key_down_state = 0;  {
185            points[0].x -= xoffset;
186            points[0].y -= yoffset;
187  #define DShift1Mask   (1<<0)          XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
188  #define DLockMask     (1<<1)          points[0].x += xoffset;
189  #define DControl1Mask (1<<2)          points[0].y += yoffset;
190  #define DMod1Mask     (1<<3)  }
 #define DMod2Mask     (1<<4)  
 #define DMod3Mask     (1<<5)  
 #define DMod4Mask     (1<<6)  
 #define DMod5Mask     (1<<7)  
 #define DShift2Mask   (1<<8)  
 #define DControl2Mask (1<<9)  
 #define DNumLockMask  (1<<10)  
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 102  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); }
263    
264  void xwin_get_numlock_mask();  static seamless_window *
265  void xwin_mod_update(uint32 state, uint32 ev_time );  seamless_get_window_by_id(unsigned long id)
 void xwin_mod_release(uint32 state, uint32 ev_time, uint32 scancode);  
 void xwin_mod_press(uint32 state, uint32 ev_time, uint32 scancode);  
   
 static void  
 translate8(uint8 *data, uint8 *out, uint8 *end)  
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          display = XkbOpenDisplay( NULL, &xkb_event, &xkb_error, &xkb_major, &xkb_minor, &xkb_reason );          if (g_compatible_arch)
         switch(xkb_reason)  
497          {          {
498                  case XkbOD_BadLibraryVersion:                  while (out < end)
499                          error("XkbOD_BadLibraryVersion: XKB extensions in server and the library rdesktop is linked against aren't compatible with each other.\n");                  {
500                          break;                          value = g_colmap[*(data++)];
501                  case XkbOD_ConnectionRefused:                          BOUT24(out, value);
502                          error("XkbOD_ConnectionRefused\n");                  }
503                          break;          }
504                  case XkbOD_BadServerVersion:          else
505                          error("XkbOD_BadServerVersion\n");          {
506                          break;                  while (out < end)
507                  case XkbOD_NonXkbServer:                  {
508                          error("XkbOD_NonXkbServer: XKB extension not present in server\nupdate your X server.\n");                          value = g_colmap[*(data++)];
509                          break;                          LOUT24(out, value);
510                  case XkbOD_Success:                  }
                         DEBUG("XkbOD_Success: Connection established with display\n");  
                         break;  
511          }          }
512    }
513    
514          if (display == NULL)  static void
515    translate8to32(const uint8 * data, uint8 * out, uint8 * end)
516    {
517            uint32 value;
518    
519            if (g_compatible_arch)
520          {          {
521                  error("Failed to open display\n");                  /* *INDENT-OFF* */
522                  return False;                  REPEAT4
523                    (
524                            *((uint32 *) out) = g_colmap[*(data++)];
525                            out += 4;
526                    )
527                    /* *INDENT-ON* */
528          }          }
529            else if (g_xserver_be)
530            {
531                    while (out < end)
532                    {
533                            value = g_colmap[*(data++)];
534                            BOUT32(out, value);
535                    }
536            }
537            else
538            {
539                    while (out < end)
540                    {
541                            value = g_colmap[*(data++)];
542                            LOUT32(out, value);
543                    }
544            }
545    }
546    
547          x_socket = ConnectionNumber(display);  static void
548          screen = DefaultScreenOfDisplay(display);  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
549          visual = DefaultVisualOfScreen(screen);  {
550          depth = DefaultDepthOfScreen(screen);          uint16 pixel;
551                    uint16 value;
552          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
         if (bpp < 8)  
569          {          {
570                  error("Less than 8 bpp not currently supported.\n");                  while (out < end)
571                  XCloseDisplay(display);                  {
572                  return False;                          pixel = *(data++);
573                            if (g_host_be)
574                            {
575                                    BSWAP16(pixel);
576                            }
577                            SPLITCOLOUR15(pixel, pc);
578                            value = MAKECOLOUR(pc);
579                            LOUT16(out, value);
580                    }
581          }          }
582    }
583    
584    static void
585    translate15to24(const uint16 * data, uint8 * out, uint8 * end)
586    {
587            uint32 value;
588            uint16 pixel;
589            PixelColour pc;
590    
591          if (depth <= 8)          if (g_compatible_arch)
592                  owncolmap = True;          {
593                    /* *INDENT-OFF* */
594                    REPEAT3
595                    (
596                            pixel = *(data++);
597                            SPLITCOLOUR15(pixel, pc);
598                            *(out++) = pc.blue;
599                            *(out++) = pc.green;
600                            *(out++) = pc.red;
601                    )
602                    /* *INDENT-ON* */
603            }
604            else if (g_xserver_be)
605            {
606                    while (out < end)
607                    {
608                            pixel = *(data++);
609                            if (g_host_be)
610                            {
611                                    BSWAP16(pixel);
612                            }
613                            SPLITCOLOUR15(pixel, pc);
614                            value = MAKECOLOUR(pc);
615                            BOUT24(out, value);
616                    }
617            }
618          else          else
619                  xcolmap = DefaultColormapOfScreen(screen);          {
620                    while (out < end)
621                    {
622                            pixel = *(data++);
623                            if (g_host_be)
624                            {
625                                    BSWAP16(pixel);
626                            }
627                            SPLITCOLOUR15(pixel, pc);
628                            value = MAKECOLOUR(pc);
629                            LOUT24(out, value);
630                    }
631            }
632    }
633    
634          test = 1;  static void
635          host_be = !(BOOL)(*(uint8 *)(&test));  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
636          xserver_be = (ImageByteOrder(display) == MSBFirst);  {
637            uint16 pixel;
638            uint32 value;
639            PixelColour pc;
640    
641          white = WhitePixelOfScreen(screen);          if (g_compatible_arch)
642          attribs.background_pixel = BlackPixelOfScreen(screen);          {
643          attribs.backing_store = DoesBackingStore(screen);                  /* *INDENT-OFF* */
644                    REPEAT4
645                    (
646                            pixel = *(data++);
647                            SPLITCOLOUR15(pixel, pc);
648                            *(out++) = pc.blue;
649                            *(out++) = pc.green;
650                            *(out++) = pc.red;
651                            *(out++) = 0;
652                    )
653                    /* *INDENT-ON* */
654            }
655            else if (g_xserver_be)
656            {
657                    while (out < end)
658                    {
659                            pixel = *(data++);
660                            if (g_host_be)
661                            {
662                                    BSWAP16(pixel);
663                            }
664                            SPLITCOLOUR15(pixel, pc);
665                            value = MAKECOLOUR(pc);
666                            BOUT32(out, value);
667                    }
668            }
669            else
670            {
671                    while (out < end)
672                    {
673                            pixel = *(data++);
674                            if (g_host_be)
675                            {
676                                    BSWAP16(pixel);
677                            }
678                            SPLITCOLOUR15(pixel, pc);
679                            value = MAKECOLOUR(pc);
680                            LOUT32(out, value);
681                    }
682            }
683    }
684    
685          if (attribs.backing_store == NotUseful)  static void
686                  ownbackstore = True;  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
687    {
688            uint16 pixel;
689            uint16 value;
690            PixelColour pc;
691    
692          if (fullscreen)          if (g_xserver_be)
693          {          {
694                  attribs.override_redirect = True;                  if (g_host_be)
695                  width = WidthOfScreen(screen);                  {
696                  height = HeightOfScreen(screen);                          while (out < end)
697                            {
698                                    pixel = *(data++);
699                                    BSWAP16(pixel);
700                                    SPLITCOLOUR16(pixel, pc);
701                                    value = MAKECOLOUR(pc);
702                                    BOUT16(out, value);
703                            }
704                    }
705                    else
706                    {
707                            while (out < end)
708                            {
709                                    pixel = *(data++);
710                                    SPLITCOLOUR16(pixel, pc);
711                                    value = MAKECOLOUR(pc);
712                                    BOUT16(out, value);
713                            }
714                    }
715          }          }
716          else          else
717          {          {
718                  attribs.override_redirect = False;                  if (g_host_be)
719                    {
720                            while (out < end)
721                            {
722                                    pixel = *(data++);
723                                    BSWAP16(pixel);
724                                    SPLITCOLOUR16(pixel, pc);
725                                    value = MAKECOLOUR(pc);
726                                    LOUT16(out, value);
727                            }
728                    }
729                    else
730                    {
731                            while (out < end)
732                            {
733                                    pixel = *(data++);
734                                    SPLITCOLOUR16(pixel, pc);
735                                    value = MAKECOLOUR(pc);
736                                    LOUT16(out, value);
737                            }
738                    }
739          }          }
740    }
741    
742          width = (width + 3) & ~3; /* make width a multiple of 32 bits */  static void
743    translate16to24(const uint16 * data, uint8 * out, uint8 * end)
744    {
745            uint32 value;
746            uint16 pixel;
747            PixelColour pc;
748    
749          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          if (g_compatible_arch)
750                              0, 0, width, height, 0, CopyFromParent,          {
751                              InputOutput, CopyFromParent,                  /* *INDENT-OFF* */
752                              CWBackingStore | CWBackPixel | CWOverrideRedirect,                  REPEAT3
753                              &attribs);                  (
754                            pixel = *(data++);
755                            SPLITCOLOUR16(pixel, pc);
756                            *(out++) = pc.blue;
757                            *(out++) = pc.green;
758                            *(out++) = pc.red;
759                    )
760                    /* *INDENT-ON* */
761            }
762            else if (g_xserver_be)
763            {
764                    if (g_host_be)
765                    {
766                            while (out < end)
767                            {
768                                    pixel = *(data++);
769                                    BSWAP16(pixel);
770                                    SPLITCOLOUR16(pixel, pc);
771                                    value = MAKECOLOUR(pc);
772                                    BOUT24(out, value);
773                            }
774                    }
775                    else
776                    {
777                            while (out < end)
778                            {
779                                    pixel = *(data++);
780                                    SPLITCOLOUR16(pixel, pc);
781                                    value = MAKECOLOUR(pc);
782                                    BOUT24(out, value);
783                            }
784                    }
785            }
786            else
787            {
788                    if (g_host_be)
789                    {
790                            while (out < end)
791                            {
792                                    pixel = *(data++);
793                                    BSWAP16(pixel);
794                                    SPLITCOLOUR16(pixel, pc);
795                                    value = MAKECOLOUR(pc);
796                                    LOUT24(out, value);
797                            }
798                    }
799                    else
800                    {
801                            while (out < end)
802                            {
803                                    pixel = *(data++);
804                                    SPLITCOLOUR16(pixel, pc);
805                                    value = MAKECOLOUR(pc);
806                                    LOUT24(out, value);
807                            }
808                    }
809            }
810    }
811    
812          XStoreName(display, wnd, title);  static void
813    translate16to32(const uint16 * data, uint8 * out, uint8 * end)
814    {
815            uint16 pixel;
816            uint32 value;
817            PixelColour pc;
818    
819          classhints = XAllocClassHint();          if (g_compatible_arch)
         if (classhints != NULL)  
820          {          {
821                  classhints->res_name = classhints->res_class = "rdesktop";                  /* *INDENT-OFF* */
822                  XSetClassHint(display, wnd, classhints);                  REPEAT4
823                  XFree(classhints);                  (
824                            pixel = *(data++);
825                            SPLITCOLOUR16(pixel, pc);
826                            *(out++) = pc.blue;
827                            *(out++) = pc.green;
828                            *(out++) = pc.red;
829                            *(out++) = 0;
830                    )
831                    /* *INDENT-ON* */
832          }          }
833            else if (g_xserver_be)
         sizehints = XAllocSizeHints();  
         if (sizehints)  
834          {          {
835                  sizehints->flags = PMinSize | PMaxSize;                  if (g_host_be)
836                  sizehints->min_width = sizehints->max_width = width;                  {
837                  sizehints->min_height = sizehints->max_height = height;                          while (out < end)
838                  XSetWMNormalHints(display, wnd, sizehints);                          {
839                  XFree(sizehints);                                  pixel = *(data++);
840                                    BSWAP16(pixel);
841                                    SPLITCOLOUR16(pixel, pc);
842                                    value = MAKECOLOUR(pc);
843                                    BOUT32(out, value);
844                            }
845                    }
846                    else
847                    {
848                            while (out < end)
849                            {
850                                    pixel = *(data++);
851                                    SPLITCOLOUR16(pixel, pc);
852                                    value = MAKECOLOUR(pc);
853                                    BOUT32(out, value);
854                            }
855                    }
856          }          }
857            else
858            {
859                    if (g_host_be)
860                    {
861                            while (out < end)
862                            {
863                                    pixel = *(data++);
864                                    BSWAP16(pixel);
865                                    SPLITCOLOUR16(pixel, pc);
866                                    value = MAKECOLOUR(pc);
867                                    LOUT32(out, value);
868                            }
869                    }
870                    else
871                    {
872                            while (out < end)
873                            {
874                                    pixel = *(data++);
875                                    SPLITCOLOUR16(pixel, pc);
876                                    value = MAKECOLOUR(pc);
877                                    LOUT32(out, value);
878                            }
879                    }
880            }
881    }
882    
883          xkeymap_init();  static void
884    translate24to16(const uint8 * data, uint8 * out, uint8 * end)
885          input_mask = KeyPressMask | KeyReleaseMask |  {
886                           ButtonPressMask | ButtonReleaseMask |          uint32 pixel = 0;
887                           EnterWindowMask | LeaveWindowMask;          uint16 value;
888          if (sendmotion)          PixelColour pc;
                 input_mask |= PointerMotionMask;  
   
         if (ownbackstore)  
                 input_mask |= ExposureMask;  
   
         XSelectInput(display, wnd, input_mask);  
         gc = XCreateGC(display, wnd, 0, NULL);  
   
         if (ownbackstore)  
                 backstore = XCreatePixmap(display, wnd, width, height, depth);  
   
         XMapWindow(display, wnd);  
   
         /* TODO: error texts... make them friendly. */  
         xkb = XkbGetKeyboard(display, XkbAllComponentsMask, XkbUseCoreKbd);  
         if ((int)xkb == BadAlloc || xkb == NULL)  
         {  
                         error( "XkbGetKeyboard failed.\n");  
                         exit(0);  
         }  
889    
890          /* TODO: error texts... make them friendly. */          while (out < end)
         if( XkbSelectEvents(display, xkb->device_spec, XkbAllEventsMask, XkbAllEventsMask) == False )  
891          {          {
892                          error( "XkbSelectEvents failed.\n");                  pixel = *(data++) << 16;
893                          exit(0);                  pixel |= *(data++) << 8;
894                    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            }
         xwin_get_numlock_mask();  
907    
908          return True;  static void
909    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                    while (out < end)
918                    {
919                            pixel = *(data++) << 16;
920                            pixel |= *(data++) << 8;
921                            pixel |= *(data++);
922                            SPLITCOLOUR24(pixel, pc);
923                            value = MAKECOLOUR(pc);
924                            BOUT24(out, value);
925                    }
926            }
927            else
928            {
929                    while (out < end)
930                    {
931                            pixel = *(data++) << 16;
932                            pixel |= *(data++) << 8;
933                            pixel |= *(data++);
934                            SPLITCOLOUR24(pixel, pc);
935                            value = MAKECOLOUR(pc);
936                            LOUT24(out, value);
937                    }
938            }
939  }  }
940    
941  void  static void
942  xwin_get_numlock_mask()  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
943  {  {
944          KeyCode numlockcode;          uint32 pixel;
945          KeyCode* keycode;          uint32 value;
946          XModifierKeymap *modmap;          PixelColour pc;
947          int i,j;  
948            if (g_compatible_arch)
949          /* Find out if numlock is already defined as a modifier key, and if so where */          {
950          numlockcode = XKeysymToKeycode(display, 0xFF7F);        /* XF_Num_Lock = 0xFF7F */                  /* *INDENT-OFF* */
951          if (numlockcode) {  #ifdef NEED_ALIGN
952                  modmap = XGetModifierMapping(display);                  REPEAT4
953                  if (modmap) {                  (
954                          keycode = modmap->modifiermap;                          *(out++) = *(data++);
955                          for (i = 0; i < 8; i++)                          *(out++) = *(data++);
956                                  for (j = modmap->max_keypermod; j--;) {                          *(out++) = *(data++);
957                                          if (*keycode == numlockcode) {                          *(out++) = 0;
958                                                  numlock_modifier_mask = (1 << i);                  )
959                                                  i = 8;  #else
960                                                  break;                  REPEAT4
961                                          }                  (
962                                          keycode++;                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
963                                  }                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
964                  if (!numlock_modifier_mask) {                   out += 4;
965                                  modmap->modifiermap[7 * modmap->max_keypermod] = numlockcode;                   data += 3;
966                                  if (XSetModifierMapping(display, modmap) == MappingSuccess)                  )
967                                          numlock_modifier_mask = (1 << 7);  #endif
968                                  else                  /* *INDENT-ON* */
969                                          printf("XSetModifierMapping failed!\n");          }
970                          }          else if (g_xserver_be)
971                          XFreeModifiermap(modmap);          {
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    static uint8 *
997    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                    if ((g_depth == 15 && g_server_depth == 15) ||
1014                        (g_depth == 16 && g_server_depth == 16) ||
1015                        (g_depth == 24 && g_server_depth == 24))
1016                            return data;
1017            }
1018    
1019            size = width * height * (g_bpp / 8);
1020            out = (uint8 *) xmalloc(size);
1021            end = out + size;
1022    
1023          if (!numlock_modifier_mask)          switch (g_server_depth)
1024                  printf("WARNING: Failed to get a numlock modifier mapping.\n");          {
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 (keycode == NoSymbol)
1097                    return False;
1098    
1099          if (ownbackstore)          for (modifierpos = 0; modifierpos < 8; modifierpos++)
1100                  XFreePixmap(display, backstore);          {
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          XEvent xevent;          *shift_l = ffs(mask) - 1;
1117            mask >>= *shift_l;
1118            *shift_r = 8 - ffs(mask & ~(mask >> 1));
1119    }
1120    
1121          KeySym keysym;  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1122          uint8 scancode;     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1123          uint16 button, flags;   */
1124          uint32 ev_time;  static unsigned
1125          uint32 tmpmods;  calculate_mask_weight(uint32 mask)
1126    {
1127            unsigned weight = 0;
1128            do
1129            {
1130                    weight += (mask & 1);
1131            }
1132            while (mask >>= 1);
1133            return weight;
1134    }
1135    
1136    static BOOL
1137    select_visual()
1138    {
1139            XPixmapFormatValues *pfm;
1140            int pixmap_formats_count, visuals_count;
1141            XVisualInfo *vmatches = NULL;
1142            XVisualInfo template;
1143            int i;
1144            unsigned red_weight, blue_weight, green_weight;
1145    
1146          while (XCheckMaskEvent(display, ~0, &xevent))          red_weight = blue_weight = green_weight = 0;
1147    
1148            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1149            if (pfm == NULL)
1150          {          {
1151                  ev_time = time(NULL);                  error("Unable to get list of pixmap formats from display.\n");
1152                  flags = 0;                  XCloseDisplay(g_display);
1153                    return False;
1154            }
1155    
1156                  switch (xevent.type)          /* 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                          case KeyRelease:                          XVisualInfo *visual_info = &vmatches[i];
1167                                  flags = KBD_FLAG_DOWN | KBD_FLAG_UP;  
1168                                  /* fall through */                          /* Try to find a no-translation visual that'll
1169                          case KeyPress:                             allow us to use RDP bitmaps directly as ZPixmaps. */
1170                                  if( XkbTranslateKeyCode(xkb, xevent.xkey.keycode, xevent.xkey.state, &tmpmods, &keysym) == False )                          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, xevent.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( xevent.type == KeyPress )                             We're being truly aristocratic here, minding each
1228                                          xwin_mod_press( xevent.xkey.state, 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( xevent.type == KeyRelease )                  /* we use a colourmap, so the default visual should do */
1277                                          xwin_mod_release( xevent.xkey.state, 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(xevent.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                                                 xevent.xbutton.x,  {
1326                                                 xevent.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                                                 xevent.xmotion.x,                  error("Failed to open display: %s\n", XDisplayName(NULL));
1332                                                 xevent.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            }
1339    
1340                                   xwin_mod_update( xevent.xcrossing.state, ev_time );          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1341                                  break;          screen_num = DefaultScreen(g_display);
1342            g_x_socket = ConnectionNumber(g_display);
1343            g_screen = ScreenOfDisplay(g_display, screen_num);
1344            g_depth = DefaultDepthOfScreen(g_screen);
1345    
1346                          case LeaveNotify:          if (!select_visual())
1347                                  XUngrabKeyboard(display, CurrentTime);                  return False;
                                 break;  
1348    
1349                          case Expose:          if (g_no_translate_image)
1350                                  XCopyArea(display, backstore, wnd, gc,          {
1351                                            xevent.xexpose.x, xevent.xexpose.y,                  DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1352                                            xevent.xexpose.width, xevent.xexpose.height,          }
1353                                            xevent.xexpose.x, xevent.xexpose.y);  
1354                                  break;          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_mod_update(uint32 state, uint32 ev_time )  ui_deinit(void)
1435  {  {
1436          xwin_mod_press(state, ev_time, 0);          if (g_IM != NULL)
1437          xwin_mod_release(state, ev_time, 0);                  XCloseIM(g_IM);
1438    
1439            if (g_null_cursor != NULL)
1440                    ui_destroy_cursor(g_null_cursor);
1441    
1442            XFreeModifiermap(g_mod_map);
1443    
1444            if (g_ownbackstore)
1445                    XFreePixmap(g_display, g_backstore);
1446    
1447            XFreeGC(g_display, g_gc);
1448            XCloseDisplay(g_display);
1449            g_display = NULL;
1450  }  }
1451    
1452  void  
1453  xwin_mod_release(uint32 state, uint32 ev_time, uint32 scancode)  static void
1454    get_window_attribs(XSetWindowAttributes * attribs)
1455  {  {
1456          switch (scancode) {          attribs->background_pixel = BlackPixelOfScreen(g_screen);
1457          case 0x2a:          attribs->background_pixel = WhitePixelOfScreen(g_screen);
1458                  key_down_state &= ~DShift1Mask;          attribs->border_pixel = WhitePixelOfScreen(g_screen);
1459                  break;          attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1460          case 0x36:          attribs->override_redirect = g_fullscreen;
1461                  key_down_state &= ~DShift2Mask;          attribs->colormap = g_xcolmap;
1462                  break;  }
1463          case 0x1d:  
1464                  key_down_state &= ~DControl1Mask;  static void
1465                  break;  get_input_mask(long *input_mask)
1466          case 0x9d:  {
1467                  key_down_state &= ~DControl2Mask;          *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1468                  break;                  VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1469          case 0x38:  
1470                  key_down_state &= ~DMod1Mask;          if (g_sendmotion)
1471                  break;                  *input_mask |= PointerMotionMask;
1472          case 0xb8:          if (g_ownbackstore)
1473                  key_down_state &= ~DMod2Mask;                  *input_mask |= ExposureMask;
1474                  break;          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          if( !(numlock_modifier_mask & state) && (key_down_state & DNumLockMask) )          /* Handle -x-y portion of geometry string */
1497            if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1498                    g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1499            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1500                    g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1501    
1502            get_window_attribs(&attribs);
1503    
1504            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1505                                  wndheight, 0, g_depth, InputOutput, g_visual,
1506                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1507                                  CWBorderPixel, &attribs);
1508    
1509            if (g_gc == NULL)
1510          {          {
1511                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x45, 0);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1512                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x45, 0);                  ui_reset_clip();
                 key_down_state &= ~DNumLockMask;  
1513          }          }
1514    
1515          if( !(LockMask & state) && (key_down_state & DLockMask))          if (g_create_bitmap_gc == NULL)
1516                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1517    
1518            if ((g_ownbackstore) && (g_backstore == 0))
1519          {          {
1520                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x3a, 0);                  g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
                 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x3a, 0);  
                 key_down_state &= ~DLockMask;  
1521    
1522                    /* clear to prevent rubbish being exposed at startup */
1523                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1524                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1525          }          }
1526    
1527            XStoreName(g_display, g_wnd, g_title);
1528    
1529          if( !(ShiftMask & state) && (key_down_state & DShift1Mask))          if (g_hide_decorations)
1530          {                  mwm_hide_decorations(g_wnd);
                 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x2a, 0);  
                 key_down_state &= ~DShift1Mask;  
1531    
1532            classhints = XAllocClassHint();
1533            if (classhints != NULL)
1534            {
1535                    classhints->res_name = classhints->res_class = "rdesktop";
1536                    XSetClassHint(g_display, g_wnd, classhints);
1537                    XFree(classhints);
1538          }          }
1539    
1540          if( !(ControlMask & state) && (key_down_state & DControl1Mask))          sizehints = XAllocSizeHints();
1541            if (sizehints)
1542          {          {
1543                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_UP, 0x1d, 0);                  sizehints->flags = PMinSize | PMaxSize;
1544                  key_down_state &= ~DControl1Mask;                  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 & 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 & 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_mod_press(uint32 state, uint32 ev_time, uint32 scancode)  ui_resize_window()
1597  {  {
1598            XSizeHints *sizehints;
1599            Pixmap bs;
1600    
1601          switch (scancode) {          sizehints = XAllocSizeHints();
1602          case 0x2a:          if (sizehints)
1603                  key_down_state |= DShift1Mask;          {
1604                  break;                  sizehints->flags = PMinSize | PMaxSize;
1605          case 0x36:                  sizehints->min_width = sizehints->max_width = g_width;
1606                  key_down_state |= DShift2Mask;                  sizehints->min_height = sizehints->max_height = g_height;
1607                  break;                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1608          case 0x1d:                  XFree(sizehints);
                 key_down_state |= DControl1Mask;  
                 break;  
         case 0x9d:  
                 key_down_state |= DControl2Mask;  
                 break;  
         case 0x3a:  
                 key_down_state ^= DLockMask;  
                 break;  
         case 0x45:  
                 key_down_state ^= DNumLockMask;  
                 break;  
         case 0x38:  
                 key_down_state |= DMod1Mask;  
                 break;  
         case 0xb8:  
                 key_down_state |= DMod2Mask;  
                 break;  
1609          }          }
1610    
1611          if( (numlock_modifier_mask && state) && !(key_down_state & DNumLockMask) )          if (!(g_fullscreen || g_embed_wnd))
1612          {          {
1613                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x45, 0);                  XResizeWindow(g_display, g_wnd, g_width, g_height);
                 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x45, 0);  
                 key_down_state |= DNumLockMask;  
1614          }          }
1615    
1616          if( (LockMask & state) && !(key_down_state & DLockMask))          /* create new backstore pixmap */
1617            if (g_backstore != 0)
1618          {          {
1619                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0, 0x3a, 0);                  bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1620                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN | KBD_FLAG_UP, 0x3a, 0);                  XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1621                  key_down_state |= DLockMask;                  XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1622                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1623                    XFreePixmap(g_display, g_backstore);
1624                    g_backstore = bs;
1625          }          }
1626    }
1627    
1628    void
1629    ui_destroy_window(void)
1630    {
1631            if (g_IC != NULL)
1632                    XDestroyIC(g_IC);
1633    
1634          if( (ShiftMask & state) && !((key_down_state & DShift1Mask) || (key_down_state & DShift2Mask)))          XDestroyWindow(g_display, g_wnd);
1635          {  }
                 rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0x2a, 0);  
                 key_down_state |= DShift1Mask;  
1636    
1637          }  void
1638    xwin_toggle_fullscreen(void)
1639    {
1640            Pixmap contents = 0;
1641    
1642          if( (ControlMask & state) && !((key_down_state & DControl1Mask) || (key_down_state & DControl2Mask)))          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, 0x1d, 0);                  /* need to save contents of window */
1649                  key_down_state |= DControl1Mask;                  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    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( (Mod1Mask & state) && !(key_down_state & DMod1Mask))          /* 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, 0x38, 0);                  /*  Check from right to left: */
1686                  key_down_state |= DMod1Mask;                  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          if( (Mod2Mask & state) && !(key_down_state & DMod2Mask))  /* Process events in Xlib queue
1748       Returns 0 after user quit, 1 otherwise */
1749    static int
1750    xwin_process_events(void)
1751    {
1752            XEvent xevent;
1753            KeySym keysym;
1754            uint32 ev_time;
1755            char str[256];
1756            Status status;
1757            int events = 0;
1758            seamless_window *sw;
1759    
1760            while ((XPending(g_display) > 0) && events++ < 20)
1761          {          {
1762                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, KBD_FLAG_DOWN, 0xb8, 0);                  XNextEvent(g_display, &xevent);
1763                  key_down_state |= DMod2Mask;  
1764                    if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1765                    {
1766                            DEBUG_KBD(("Filtering event\n"));
1767                            continue;
1768                    }
1769    
1770                    switch (xevent.type)
1771                    {
1772                            case VisibilityNotify:
1773                                    if (xevent.xvisibility.window == g_wnd)
1774                                            g_Unobscured =
1775                                                    xevent.xvisibility.state == VisibilityUnobscured;
1776    
1777                                    break;
1778                            case ClientMessage:
1779                                    /* the window manager told us to quit */
1780                                    if ((xevent.xclient.message_type == g_protocol_atom)
1781                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1782                                            /* Quit */
1783                                            return 0;
1784                                    break;
1785    
1786                            case KeyPress:
1787                                    g_last_gesturetime = xevent.xkey.time;
1788                                    if (g_IC != NULL)
1789                                            /* Multi_key compatible version */
1790                                    {
1791                                            XmbLookupString(g_IC,
1792                                                            &xevent.xkey, str, sizeof(str), &keysym,
1793                                                            &status);
1794                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1795                                            {
1796                                                    error("XmbLookupString failed with status 0x%x\n",
1797                                                          status);
1798                                                    break;
1799                                            }
1800                                    }
1801                                    else
1802                                    {
1803                                            /* Plain old XLookupString */
1804                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1805                                            XLookupString((XKeyEvent *) & xevent,
1806                                                          str, sizeof(str), &keysym, NULL);
1807                                    }
1808    
1809                                    DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1810                                               get_ksname(keysym)));
1811    
1812                                    ev_time = time(NULL);
1813                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1814                                            break;
1815    
1816                                    xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1817                                                      ev_time, True, 0);
1818                                    break;
1819    
1820                            case KeyRelease:
1821                                    g_last_gesturetime = xevent.xkey.time;
1822                                    XLookupString((XKeyEvent *) & xevent, str,
1823                                                  sizeof(str), &keysym, NULL);
1824    
1825                                    DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1826                                               get_ksname(keysym)));
1827    
1828                                    ev_time = time(NULL);
1829                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1830                                            break;
1831    
1832                                    xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1833                                                      ev_time, False, 0);
1834                                    break;
1835    
1836                            case ButtonPress:
1837                                    handle_button_event(xevent, True);
1838                                    break;
1839    
1840                            case ButtonRelease:
1841                                    handle_button_event(xevent, False);
1842                                    break;
1843    
1844                            case MotionNotify:
1845                                    if (g_moving_wnd)
1846                                    {
1847                                            XMoveWindow(g_display, g_wnd,
1848                                                        xevent.xmotion.x_root - g_move_x_offset,
1849                                                        xevent.xmotion.y_root - g_move_y_offset);
1850                                            break;
1851                                    }
1852    
1853                                    if (g_fullscreen && !g_focused)
1854                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1855                                                           CurrentTime);
1856    
1857                                    if (xevent.xmotion.window == g_wnd)
1858                                    {
1859                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1860                                                           xevent.xmotion.x, xevent.xmotion.y);
1861                                    }
1862                                    else
1863                                    {
1864                                            /* SeamlessRDP */
1865                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1866                                                           xevent.xmotion.x_root,
1867                                                           xevent.xmotion.y_root);
1868                                    }
1869                                    break;
1870    
1871                            case FocusIn:
1872                                    if (xevent.xfocus.mode == NotifyGrab)
1873                                            break;
1874                                    g_focused = True;
1875                                    reset_modifier_keys();
1876                                    if (g_grab_keyboard && g_mouse_in_wnd)
1877                                            XGrabKeyboard(g_display, g_wnd, True,
1878                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1879                                    break;
1880    
1881                            case FocusOut:
1882                                    if (xevent.xfocus.mode == NotifyUngrab)
1883                                            break;
1884                                    g_focused = False;
1885                                    if (xevent.xfocus.mode == NotifyWhileGrabbed)
1886                                            XUngrabKeyboard(g_display, CurrentTime);
1887                                    break;
1888    
1889                            case EnterNotify:
1890                                    /* we only register for this event when in fullscreen mode */
1891                                    /* or grab_keyboard */
1892                                    g_mouse_in_wnd = True;
1893                                    if (g_fullscreen)
1894                                    {
1895                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1896                                                           CurrentTime);
1897                                            break;
1898                                    }
1899                                    if (g_focused)
1900                                            XGrabKeyboard(g_display, g_wnd, True,
1901                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
1902                                    break;
1903    
1904                            case LeaveNotify:
1905                                    /* we only register for this event when grab_keyboard */
1906                                    g_mouse_in_wnd = False;
1907                                    XUngrabKeyboard(g_display, CurrentTime);
1908                                    break;
1909    
1910                            case Expose:
1911                                    if (xevent.xexpose.window == g_wnd)
1912                                    {
1913                                            XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1914                                                      g_gc,
1915                                                      xevent.xexpose.x, xevent.xexpose.y,
1916                                                      xevent.xexpose.width, xevent.xexpose.height,
1917                                                      xevent.xexpose.x, xevent.xexpose.y);
1918                                    }
1919                                    else
1920                                    {
1921                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1922                                            if (sw)
1923                                                    XCopyArea(g_display, g_backstore,
1924                                                              xevent.xexpose.window, g_gc,
1925                                                              xevent.xexpose.x + sw->xoffset,
1926                                                              xevent.xexpose.y + sw->yoffset,
1927                                                              xevent.xexpose.width,
1928                                                              xevent.xexpose.height, xevent.xexpose.x,
1929                                                              xevent.xexpose.y);
1930                                            else
1931                                            {
1932                                                    error("Expose for unknown window 0x%lx\n",
1933                                                          xevent.xexpose.window);
1934                                            }
1935                                    }
1936    
1937                                    break;
1938    
1939                            case MappingNotify:
1940                                    /* Refresh keyboard mapping if it has changed. This is important for
1941                                       Xvnc, since it allocates keycodes dynamically */
1942                                    if (xevent.xmapping.request == MappingKeyboard
1943                                        || xevent.xmapping.request == MappingModifier)
1944                                            XRefreshKeyboardMapping(&xevent.xmapping);
1945    
1946                                    if (xevent.xmapping.request == MappingModifier)
1947                                    {
1948                                            XFreeModifiermap(g_mod_map);
1949                                            g_mod_map = XGetModifierMapping(g_display);
1950                                    }
1951                                    break;
1952    
1953                                    /* clipboard stuff */
1954                            case SelectionNotify:
1955                                    xclip_handle_SelectionNotify(&xevent.xselection);
1956                                    break;
1957                            case SelectionRequest:
1958                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1959                                    break;
1960                            case SelectionClear:
1961                                    xclip_handle_SelectionClear();
1962                                    break;
1963                            case PropertyNotify:
1964                                    xclip_handle_PropertyNotify(&xevent.xproperty);
1965                                    if (xevent.xproperty.window == g_wnd)
1966                                            break;
1967                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
1968                                            break;
1969    
1970                                    /* seamless */
1971                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
1972                                    if (!sw)
1973                                            break;
1974    
1975                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
1976                                        && (xevent.xproperty.state == PropertyNewValue))
1977                                    {
1978                                            sw->state = ewmh_get_window_state(sw->wnd);
1979                                            seamless_send_state(sw->id, sw->state, 0);
1980                                    }
1981    
1982                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
1983                                        && (xevent.xproperty.state == PropertyNewValue))
1984                                    {
1985                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
1986                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
1987                                    }
1988    
1989                                    break;
1990                            case MapNotify:
1991                                    if (!g_seamless_active)
1992                                            rdp_send_client_window_status(1);
1993                                    break;
1994                            case UnmapNotify:
1995                                    if (!g_seamless_active)
1996                                            rdp_send_client_window_status(0);
1997                                    break;
1998                    }
1999          }          }
2000            /* Keep going */
2001            return 1;
2002  }  }
2003    
2004  void  /* Returns 0 after user quit, 1 otherwise */
2005    int
2006  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2007  {  {
2008          int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1;          int n;
2009          fd_set rfds;          fd_set rfds, wfds;
2010            struct timeval tv;
2011          FD_ZERO(&rfds);          BOOL s_timeout = False;
2012    
2013          while (True)          while (True)
2014          {          {
2015                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2016                    /* Process any events already waiting */
2017                    if (!xwin_process_events())
2018                            /* User quit */
2019                            return 0;
2020    
2021                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2022                    FD_ZERO(&wfds);
2023                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2024                  if (display != NULL)                  FD_SET(g_x_socket, &rfds);
2025    
2026    #ifdef WITH_RDPSND
2027                    /* FIXME: there should be an API for registering fds */
2028                    if (g_dsp_busy)
2029                  {                  {
2030                          FD_SET(x_socket, &rfds);                          FD_SET(g_dsp_fd, &wfds);
2031                          XFlush(display);                          n = (g_dsp_fd > n) ? g_dsp_fd : n;
2032                  }                  }
2033    #endif
2034                    /* default timeout */
2035                    tv.tv_sec = 60;
2036                    tv.tv_usec = 0;
2037    
2038                    /* add redirection handles */
2039                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2040    
2041                  switch (select(n, &rfds, NULL, NULL, NULL))                  n++;
2042    
2043                    switch (select(n, &rfds, &wfds, NULL, &tv))
2044                  {                  {
2045                          case -1:                          case -1:
2046                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2047    
2048                          case 0:                          case 0:
2049                                    /* Abort serial read calls */
2050                                    if (s_timeout)
2051                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2052                                  continue;                                  continue;
2053                  }                  }
2054    
2055                  if (FD_ISSET(x_socket, &rfds))                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
                         xwin_process_events();  
2056    
2057                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2058                          return;                          return 1;
2059    
2060    #ifdef WITH_RDPSND
2061                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2062                            wave_out_play();
2063    #endif
2064          }          }
2065  }  }
2066    
2067  void  void
2068  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
2069  {  {
2070          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2071  }  }
2072    
2073  HBITMAP  HBITMAP
2074  ui_create_bitmap(int width, int height, uint8 *data)  ui_create_bitmap(int width, int height, uint8 * data)
2075  {  {
2076          XImage *image;          XImage *image;
2077          Pixmap bitmap;          Pixmap bitmap;
2078          uint8 *tdata;          uint8 *tdata;
2079            int bitmap_pad;
2080    
2081            if (g_server_depth == 8)
2082            {
2083                    bitmap_pad = 8;
2084            }
2085            else
2086            {
2087                    bitmap_pad = g_bpp;
2088    
2089          tdata = (owncolmap ? data : translate_image(width, height, data));                  if (g_bpp == 24)
2090          bitmap = XCreatePixmap(display, wnd, width, height, depth);                          bitmap_pad = 32;
2091          image = XCreateImage(display, visual, depth, ZPixmap,          }
2092                               0, tdata, width, height, 8, 0);  
2093            tdata = (g_owncolmap ? data : translate_image(width, height, data));
2094            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2095            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2096                                 (char *) tdata, width, height, bitmap_pad, 0);
2097    
2098          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);
2099    
2100          XFree(image);          XFree(image);
2101          if (!owncolmap)          if (tdata != data)
2102                  xfree(tdata);                  xfree(tdata);
2103          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2104  }  }
2105    
2106  void  void
2107  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)  
2108  {  {
2109          XImage *image;          XImage *image;
2110          uint8 *tdata;          uint8 *tdata;
2111            int bitmap_pad;
2112    
2113          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2114          image = XCreateImage(display, visual, depth, ZPixmap,          {
2115                               0, tdata, width, height, 8, 0);                  bitmap_pad = 8;
2116            }
2117            else
2118            {
2119                    bitmap_pad = g_bpp;
2120    
2121                    if (g_bpp == 24)
2122                            bitmap_pad = 32;
2123            }
2124    
2125          if (ownbackstore)          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2126            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2127                                 (char *) tdata, width, height, bitmap_pad, 0);
2128    
2129            if (g_ownbackstore)
2130          {          {
2131                  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);
2132                  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);
2133                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2134                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2135                                             x - sw->xoffset, y - sw->yoffset));
2136          }          }
2137          else          else
2138          {          {
2139                  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);
2140                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2141                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2142                                             x - sw->xoffset, y - sw->yoffset));
2143          }          }
2144    
2145          XFree(image);          XFree(image);
2146          if (!owncolmap)          if (tdata != data)
2147                  xfree(tdata);                  xfree(tdata);
2148  }  }
2149    
2150  void  void
2151  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(HBITMAP bmp)
2152  {  {
2153          XFreePixmap(display, (Pixmap)bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2154  }  }
2155    
2156  HGLYPH  HGLYPH
2157  ui_create_glyph(int width, int height, uint8 *data)  ui_create_glyph(int width, int height, uint8 * data)
2158  {  {
2159          XImage *image;          XImage *image;
2160          Pixmap bitmap;          Pixmap bitmap;
2161          int scanline;          int scanline;
         GC gc;  
2162    
2163          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2164    
2165          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2166          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2167                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2168    
2169          image = XCreateImage(display, visual, 1, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2170                               data, width, height, 8, scanline);                               width, height, 8, scanline);
2171          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2172          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2173          XInitImage(image);          XInitImage(image);
2174    
2175          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);
2176    
2177          XFree(image);          XFree(image);
2178          XFreeGC(display, gc);          return (HGLYPH) bitmap;
         return (HGLYPH)bitmap;  
2179  }  }
2180    
2181  void  void
2182  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
2183  {  {
2184          XFreePixmap(display, (Pixmap)glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2185  }  }
2186    
2187  HCURSOR  HCURSOR
2188  ui_create_cursor(unsigned int x, unsigned int y, int width,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2189                   int height, uint8 *andmask, uint8 *xormask)                   uint8 * andmask, uint8 * xormask)
2190  {  {
2191          HGLYPH maskglyph, cursorglyph;          HGLYPH maskglyph, cursorglyph;
2192          XColor bg, fg;          XColor bg, fg;
# Line 807  ui_create_cursor(unsigned int x, unsigne Line 2200  ui_create_cursor(unsigned int x, unsigne
2200          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2201          offset = scanline * height;          offset = scanline * height;
2202    
2203          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
2204          memset(cursor, 0, offset);          memset(cursor, 0, offset);
2205    
2206          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
2207          memset(mask, 0, offset);          memset(mask, 0, offset);
2208    
2209          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 850  ui_create_cursor(unsigned int x, unsigne Line 2243  ui_create_cursor(unsigned int x, unsigne
2243    
2244          cursorglyph = ui_create_glyph(width, height, cursor);          cursorglyph = ui_create_glyph(width, height, cursor);
2245          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2246            
2247          xcursor = XCreatePixmapCursor(display, (Pixmap)cursorglyph,          xcursor =
2248                                  (Pixmap)maskglyph, &fg, &bg, x, y);                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2249                                        (Pixmap) maskglyph, &fg, &bg, x, y);
2250    
2251          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
2252          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2253          xfree(mask);          xfree(mask);
2254          xfree(cursor);          xfree(cursor);
2255          return (HCURSOR)xcursor;          return (HCURSOR) xcursor;
2256  }  }
2257    
2258  void  void
2259  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2260  {  {
2261          XDefineCursor(display, wnd, (Cursor)cursor);          g_current_cursor = (Cursor) cursor;
2262            XDefineCursor(g_display, g_wnd, g_current_cursor);
2263            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2264  }  }
2265    
2266  void  void
2267  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(HCURSOR cursor)
2268  {  {
2269          XFreeCursor(display, (Cursor)cursor);          XFreeCursor(g_display, (Cursor) cursor);
2270    }
2271    
2272    void
2273    ui_set_null_cursor(void)
2274    {
2275            ui_set_cursor(g_null_cursor);
2276  }  }
2277    
2278  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 879  ui_destroy_cursor(HCURSOR cursor) Line 2281  ui_destroy_cursor(HCURSOR cursor)
2281                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2282                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2283    
2284    
2285  HCOLOURMAP  HCOLOURMAP
2286  ui_create_colourmap(COLOURMAP *colours)  ui_create_colourmap(COLOURMAP * colours)
2287  {  {
2288          COLOURENTRY *entry;          COLOURENTRY *entry;
2289          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2290            if (!g_owncolmap)
         if (owncolmap)  
2291          {          {
2292                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2293                  Colormap map;                  XColor xentry;
2294                    XColor xc_cache[256];
2295                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
2296                    int colLookup = 256;
2297                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2298                  {                  {
2299                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2300                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
2301                          xentry->pixel = i;  
2302                          MAKE_XCOLOR(xentry, entry);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2303                  }                          {
2304                                    /* Allocation failed, find closest match. */
2305                                    int j = 256;
2306                                    int nMinDist = 3 * 256 * 256;
2307                                    long nDist = nMinDist;
2308    
2309                  map = XCreateColormap(display, wnd, visual, AllocAll);                                  /* only get the colors once */
2310                  XStoreColors(display, map, xcolours, ncolours);                                  while (colLookup--)
2311                                    {
2312                                            xc_cache[colLookup].pixel = colLookup;
2313                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2314                                                    xc_cache[colLookup].blue = 0;
2315                                            xc_cache[colLookup].flags = 0;
2316                                            XQueryColor(g_display,
2317                                                        DefaultColormap(g_display,
2318                                                                        DefaultScreen(g_display)),
2319                                                        &xc_cache[colLookup]);
2320                                    }
2321                                    colLookup = 0;
2322    
2323                  xfree(xcolours);                                  /* approximate the pixel */
2324                  return (HCOLOURMAP)map;                                  while (j--)
2325                                    {
2326                                            if (xc_cache[j].flags)
2327                                            {
2328                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2329                                                             (long) (xentry.red >> 8)) *
2330                                                            ((long) (xc_cache[j].red >> 8) -
2331                                                             (long) (xentry.red >> 8)) +
2332                                                            ((long) (xc_cache[j].green >> 8) -
2333                                                             (long) (xentry.green >> 8)) *
2334                                                            ((long) (xc_cache[j].green >> 8) -
2335                                                             (long) (xentry.green >> 8)) +
2336                                                            ((long) (xc_cache[j].blue >> 8) -
2337                                                             (long) (xentry.blue >> 8)) *
2338                                                            ((long) (xc_cache[j].blue >> 8) -
2339                                                             (long) (xentry.blue >> 8));
2340                                            }
2341                                            if (nDist < nMinDist)
2342                                            {
2343                                                    nMinDist = nDist;
2344                                                    xentry.pixel = j;
2345                                            }
2346                                    }
2347                            }
2348                            colour = xentry.pixel;
2349    
2350                            /* update our cache */
2351                            if (xentry.pixel < 256)
2352                            {
2353                                    xc_cache[xentry.pixel].red = xentry.red;
2354                                    xc_cache[xentry.pixel].green = xentry.green;
2355                                    xc_cache[xentry.pixel].blue = xentry.blue;
2356    
2357                            }
2358    
2359                            map[i] = colour;
2360                    }
2361                    return map;
2362          }          }
2363          else          else
2364          {          {
2365                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
2366                  XColor xentry;                  Colormap map;
                 uint32 colour;  
2367    
2368                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2369                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2370                  {                  {
2371                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2372                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
2373                            xentry->pixel = i;
2374                          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);  
2375                  }                  }
2376    
2377                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2378                    XStoreColors(g_display, map, xcolours, ncolours);
2379    
2380                    xfree(xcolours);
2381                    return (HCOLOURMAP) map;
2382          }          }
2383  }  }
2384    
2385  void  void
2386  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(HCOLOURMAP map)
2387  {  {
2388          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap)map);  
         else  
2389                  xfree(map);                  xfree(map);
2390            else
2391                    XFreeColormap(g_display, (Colormap) map);
2392  }  }
2393    
2394  void  void
2395  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(HCOLOURMAP map)
2396  {  {
2397          if (owncolmap)          if (!g_owncolmap)
2398                  XSetWindowColormap(display, wnd, (Colormap)map);          {
2399                    if (g_colmap)
2400                            xfree(g_colmap);
2401    
2402                    g_colmap = (uint32 *) map;
2403            }
2404          else          else
2405                  colmap = map;          {
2406                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2407                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2408            }
2409  }  }
2410    
2411  void  void
2412  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2413  {  {
2414          XRectangle rect;          g_clip_rectangle.x = x;
2415            g_clip_rectangle.y = y;
2416          rect.x = x;          g_clip_rectangle.width = cx;
2417          rect.y = y;          g_clip_rectangle.height = cy;
2418          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);  
2419  }  }
2420    
2421  void  void
2422  ui_reset_clip()  ui_reset_clip(void)
2423  {  {
2424          XRectangle rect;          g_clip_rectangle.x = 0;
2425            g_clip_rectangle.y = 0;
2426          rect.x = 0;          g_clip_rectangle.width = g_width;
2427          rect.y = 0;          g_clip_rectangle.height = g_height;
2428          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);  
2429  }  }
2430    
2431  void  void
2432  ui_bell()  ui_bell(void)
2433  {  {
2434          XBell(display, 0);          XBell(g_display, 0);
2435  }  }
2436    
2437  void  void
# Line 986  ui_destblt(uint8 opcode, Line 2443  ui_destblt(uint8 opcode,
2443          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2444  }  }
2445    
2446    static uint8 hatch_patterns[] = {
2447            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2448            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2449            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2450            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2451            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2452            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2453    };
2454    
2455  void  void
2456  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2457            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2458            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2459  {  {
2460          Pixmap fill;          Pixmap fill;
2461            uint8 i, ipattern[8];
2462    
2463          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2464    
# Line 999  ui_patblt(uint8 opcode, Line 2466  ui_patblt(uint8 opcode,
2466          {          {
2467                  case 0: /* Solid */                  case 0: /* Solid */
2468                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2469                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2470                          break;                          break;
2471    
2472                  case 3: /* Pattern */                  case 2: /* Hatch */
2473                          fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);                          fill = (Pixmap) ui_create_glyph(8, 8,
2474                                                            hatch_patterns + brush->pattern[0] * 8);
2475                            SET_FOREGROUND(fgcolour);
2476                            SET_BACKGROUND(bgcolour);
2477                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2478                            XSetStipple(g_display, g_gc, fill);
2479                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2480                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2481                            XSetFillStyle(g_display, g_gc, FillSolid);
2482                            XSetTSOrigin(g_display, g_gc, 0, 0);
2483                            ui_destroy_glyph((HGLYPH) fill);
2484                            break;
2485    
2486                    case 3: /* Pattern */
2487                            for (i = 0; i != 8; i++)
2488                                    ipattern[7 - i] = brush->pattern[i];
2489                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2490                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2491                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2492                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2493                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2494                          XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2495                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2496                          FILL_RECTANGLE(x, y, cx, cy);                          XSetFillStyle(g_display, g_gc, FillSolid);
2497                            XSetTSOrigin(g_display, g_gc, 0, 0);
2498                          XSetFillStyle(display, gc, FillSolid);                          ui_destroy_glyph((HGLYPH) fill);
                         ui_destroy_glyph((HGLYPH)fill);  
2499                          break;                          break;
2500    
2501                  default:                  default:
# Line 1022  ui_patblt(uint8 opcode, Line 2503  ui_patblt(uint8 opcode,
2503          }          }
2504    
2505          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2506    
2507            if (g_ownbackstore)
2508                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2509            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2510                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2511                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2512  }  }
2513    
2514  void  void
# Line 1030  ui_screenblt(uint8 opcode, Line 2517  ui_screenblt(uint8 opcode,
2517               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2518  {  {
2519          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2520          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2521          if (ownbackstore)          {
2522                  XCopyArea(display, backstore, backstore, gc, srcx, srcy,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2523                            cx, cy, x, y);                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2524                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2525            }
2526            else
2527            {
2528                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2529            }
2530    
2531            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2532                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2533                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2534    
2535          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2536  }  }
2537    
# Line 1043  ui_memblt(uint8 opcode, Line 2541  ui_memblt(uint8 opcode,
2541            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ HBITMAP src, int srcx, int srcy)
2542  {  {
2543          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2544          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);
2545          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2546                  XCopyArea(display, (Pixmap)src, backstore, gc, srcx, srcy,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
2547                            cx, cy, x, y);                                   srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2548            if (g_ownbackstore)
2549                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2550          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2551  }  }
2552    
# Line 1054  void Line 2554  void
2554  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2555            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2556            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ HBITMAP src, int srcx, int srcy,
2557            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2558  {  {
2559          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
2560             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 1063  ui_triblt(uint8 opcode, Line 2563  ui_triblt(uint8 opcode,
2563          {          {
2564                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
2565                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2566                          ui_patblt(ROP2_NXOR, x, y, cx, cy,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2567                          break;                          break;
2568    
2569                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2570                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2571                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2572                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2573                          break;                          break;
2574    
2575                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
2576                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2577                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2578                          break;                          break;
2579    
2580                  default:                  default:
# Line 1090  ui_triblt(uint8 opcode, Line 2586  ui_triblt(uint8 opcode,
2586  void  void
2587  ui_line(uint8 opcode,  ui_line(uint8 opcode,
2588          /* dest */ int startx, int starty, int endx, int endy,          /* dest */ int startx, int starty, int endx, int endy,
2589          /* pen */ PEN *pen)          /* pen */ PEN * pen)
2590  {  {
2591          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2592          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2593          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2594          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2595                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
2596                                                endx - sw->xoffset, endy - sw->yoffset));
2597            if (g_ownbackstore)
2598                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2599          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2600  }  }
2601    
# Line 1110  ui_rect( Line 2609  ui_rect(
2609  }  }
2610    
2611  void  void
2612    ui_polygon(uint8 opcode,
2613               /* mode */ uint8 fillmode,
2614               /* dest */ POINT * point, int npoints,
2615               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2616    {
2617            uint8 style, i, ipattern[8];
2618            Pixmap fill;
2619    
2620            SET_FUNCTION(opcode);
2621    
2622            switch (fillmode)
2623            {
2624                    case ALTERNATE:
2625                            XSetFillRule(g_display, g_gc, EvenOddRule);
2626                            break;
2627                    case WINDING:
2628                            XSetFillRule(g_display, g_gc, WindingRule);
2629                            break;
2630                    default:
2631                            unimpl("fill mode %d\n", fillmode);
2632            }
2633    
2634            if (brush)
2635                    style = brush->style;
2636            else
2637                    style = 0;
2638    
2639            switch (style)
2640            {
2641                    case 0: /* Solid */
2642                            SET_FOREGROUND(fgcolour);
2643                            FILL_POLYGON((XPoint *) point, npoints);
2644                            break;
2645    
2646                    case 2: /* Hatch */
2647                            fill = (Pixmap) ui_create_glyph(8, 8,
2648                                                            hatch_patterns + brush->pattern[0] * 8);
2649                            SET_FOREGROUND(fgcolour);
2650                            SET_BACKGROUND(bgcolour);
2651                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2652                            XSetStipple(g_display, g_gc, fill);
2653                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2654                            FILL_POLYGON((XPoint *) point, npoints);
2655                            XSetFillStyle(g_display, g_gc, FillSolid);
2656                            XSetTSOrigin(g_display, g_gc, 0, 0);
2657                            ui_destroy_glyph((HGLYPH) fill);
2658                            break;
2659    
2660                    case 3: /* Pattern */
2661                            for (i = 0; i != 8; i++)
2662                                    ipattern[7 - i] = brush->pattern[i];
2663                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2664                            SET_FOREGROUND(bgcolour);
2665                            SET_BACKGROUND(fgcolour);
2666                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2667                            XSetStipple(g_display, g_gc, fill);
2668                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2669                            FILL_POLYGON((XPoint *) point, npoints);
2670                            XSetFillStyle(g_display, g_gc, FillSolid);
2671                            XSetTSOrigin(g_display, g_gc, 0, 0);
2672                            ui_destroy_glyph((HGLYPH) fill);
2673                            break;
2674    
2675                    default:
2676                            unimpl("brush %d\n", brush->style);
2677            }
2678    
2679            RESET_FUNCTION(opcode);
2680    }
2681    
2682    void
2683    ui_polyline(uint8 opcode,
2684                /* dest */ POINT * points, int npoints,
2685                /* pen */ PEN * pen)
2686    {
2687            /* TODO: set join style */
2688            SET_FUNCTION(opcode);
2689            SET_FOREGROUND(pen->colour);
2690            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2691            if (g_ownbackstore)
2692                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2693                               CoordModePrevious);
2694    
2695            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2696                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2697    
2698            RESET_FUNCTION(opcode);
2699    }
2700    
2701    void
2702    ui_ellipse(uint8 opcode,
2703               /* mode */ uint8 fillmode,
2704               /* dest */ int x, int y, int cx, int cy,
2705               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2706    {
2707            uint8 style, i, ipattern[8];
2708            Pixmap fill;
2709    
2710            SET_FUNCTION(opcode);
2711    
2712            if (brush)
2713                    style = brush->style;
2714            else
2715                    style = 0;
2716    
2717            switch (style)
2718            {
2719                    case 0: /* Solid */
2720                            SET_FOREGROUND(fgcolour);
2721                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2722                            break;
2723    
2724                    case 2: /* Hatch */
2725                            fill = (Pixmap) ui_create_glyph(8, 8,
2726                                                            hatch_patterns + brush->pattern[0] * 8);
2727                            SET_FOREGROUND(fgcolour);
2728                            SET_BACKGROUND(bgcolour);
2729                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2730                            XSetStipple(g_display, g_gc, fill);
2731                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2732                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2733                            XSetFillStyle(g_display, g_gc, FillSolid);
2734                            XSetTSOrigin(g_display, g_gc, 0, 0);
2735                            ui_destroy_glyph((HGLYPH) fill);
2736                            break;
2737    
2738                    case 3: /* Pattern */
2739                            for (i = 0; i != 8; i++)
2740                                    ipattern[7 - i] = brush->pattern[i];
2741                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2742                            SET_FOREGROUND(bgcolour);
2743                            SET_BACKGROUND(fgcolour);
2744                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2745                            XSetStipple(g_display, g_gc, fill);
2746                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2747                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2748                            XSetFillStyle(g_display, g_gc, FillSolid);
2749                            XSetTSOrigin(g_display, g_gc, 0, 0);
2750                            ui_destroy_glyph((HGLYPH) fill);
2751                            break;
2752    
2753                    default:
2754                            unimpl("brush %d\n", brush->style);
2755            }
2756    
2757            RESET_FUNCTION(opcode);
2758    }
2759    
2760    /* warning, this function only draws on wnd or backstore, not both */
2761    void
2762  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
2763                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
2764                /* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour,                /* src */ HGLYPH glyph, int srcx, int srcy,
2765                int fgcolour)                int bgcolour, int fgcolour)
2766  {  {
2767          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
2768          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
2769    
2770          XSetFillStyle(display, gc, (mixmode == MIX_TRANSPARENT)          XSetFillStyle(g_display, g_gc,
2771                        ? FillStippled : FillOpaqueStippled);                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2772          XSetStipple(display, gc, (Pixmap)glyph);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
2773          XSetTSOrigin(display, gc, x, y);          XSetTSOrigin(g_display, g_gc, x, y);
2774    
2775          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2776    
2777          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
2778  }  }
2779    
2780  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
2781  {\  {\
2782    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
2783    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
2784      {\
2785        xyoffset = ttext[++idx];\
2786        if ((xyoffset & 0x80))\
2787      {\      {\
2788        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
2789        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);\  
         }\  
2790        else\        else\
2791          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
2792            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
2793      }\      }\
2794    if (glyph != NULL)\      else\
2795      {\      {\
2796        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
2797                       y + (short) glyph->baseline,\          y += xyoffset;\
2798                       glyph->width, glyph->height,\        else\
2799                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
2800      }\      }\
2801      }\
2802      if (glyph != NULL)\
2803      {\
2804        x1 = x + glyph->offset;\
2805        y1 = y + glyph->baseline;\
2806        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2807        XSetTSOrigin(g_display, g_gc, x1, y1);\
2808        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2809        if (flags & TEXT2_IMPLICIT_X)\
2810          x += glyph->width;\
2811      }\
2812  }  }
2813    
2814  void  void
2815  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,
2816               int clipx, int clipy, int clipcx, int clipcy, int boxx,               int clipx, int clipy, int clipcx, int clipcy,
2817               int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2818               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2819  {  {
2820            /* TODO: use brush appropriately */
2821    
2822          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2823          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
2824          DATABLOB *entry;          DATABLOB *entry;
2825    
2826          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2827    
2828            /* Sometimes, the boxcx value is something really large, like
2829               32691. This makes XCopyArea fail with Xvnc. The code below
2830               is a quick fix. */
2831            if (boxx + boxcx > g_width)
2832                    boxcx = g_width - boxx;
2833    
2834          if (boxcx > 1)          if (boxcx > 1)
2835          {          {
2836                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2837          }          }
2838          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
2839          {          {
2840                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2841          }          }
2842    
2843            SET_FOREGROUND(fgcolour);
2844            SET_BACKGROUND(bgcolour);
2845            XSetFillStyle(g_display, g_gc, FillStippled);
2846    
2847          /* Paint text, character by character */          /* Paint text, character by character */
2848          for (i = 0; i < length;) {          for (i = 0; i < length;)
2849                  switch (text[i]) {          {
2850                  case 0xff:                  switch (text[i])
2851                          if (i + 2 < length)                  {
2852                            case 0xff:
2853                                    /* At least two bytes needs to follow */
2854                                    if (i + 3 > length)
2855                                    {
2856                                            warning("Skipping short 0xff command:");
2857                                            for (j = 0; j < length; j++)
2858                                                    fprintf(stderr, "%02x ", text[j]);
2859                                            fprintf(stderr, "\n");
2860                                            i = length = 0;
2861                                            break;
2862                                    }
2863                                  cache_put_text(text[i + 1], text, text[i + 2]);                                  cache_put_text(text[i + 1], text, text[i + 2]);
2864                          else {                                  i += 3;
2865                                  error("this shouldn't be happening\n");                                  length -= i;
2866                                    /* this will move pointer from start to first character after FF command */
2867                                    text = &(text[i]);
2868                                    i = 0;
2869                                  break;                                  break;
2870                          }  
2871                          /* this will move pointer from start to first character after FF command */                          case 0xfe:
2872                          length -= i + 3;                                  /* At least one byte needs to follow */
2873                          text = &(text[i + 3]);                                  if (i + 2 > length)
2874                          i = 0;                                  {
2875                          break;                                          warning("Skipping short 0xfe command:");
2876                                            for (j = 0; j < length; j++)
2877                  case 0xfe:                                                  fprintf(stderr, "%02x ", text[j]);
2878                          entry = cache_get_text(text[i + 1]);                                          fprintf(stderr, "\n");
2879                          if (entry != NULL) {                                          i = length = 0;
2880                                  if ((((uint8 *) (entry->data))[1] == 0)                                          break;
2881                                      && (!(flags & TEXT2_IMPLICIT_X))) {                                  }
2882                                          if (flags & TEXT2_VERTICAL)                                  entry = cache_get_text(text[i + 1]);
2883                                                  y += text[i + 2];                                  if (entry->data != NULL)
2884                                          else                                  {
2885                                                  x += text[i + 2];                                          if ((((uint8 *) (entry->data))[1] == 0)
2886                                                && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2887                                            {
2888                                                    if (flags & TEXT2_VERTICAL)
2889                                                            y += text[i + 2];
2890                                                    else
2891                                                            x += text[i + 2];
2892                                            }
2893                                            for (j = 0; j < entry->size; j++)
2894                                                    DO_GLYPH(((uint8 *) (entry->data)), j);
2895                                  }                                  }
2896                                  if (i + 2 < length)                                  if (i + 2 < length)
2897                                          i += 3;                                          i += 3;
2898                                  else                                  else
2899                                          i += 2;                                          i += 2;
2900                                  length -= i;                                  length -= i;
2901                                  /* this will move pointer from start to first character after FE command */                                  /* this will move pointer from start to first character after FE command */
2902                                  text = &(text[i]);                                  text = &(text[i]);
2903                                  i = 0;                                  i = 0;
2904                                  for (j = 0; j < entry->size; j++)                                  break;
                                         DO_GLYPH(((uint8 *) (entry->data)), j);  
                         }  
                         break;  
2905    
2906                  default:                          default:
2907                          DO_GLYPH(text, i);                                  DO_GLYPH(text, i);
2908                          i++;                                  i++;
2909                          break;                                  break;
2910                  }                  }
2911          }          }
2912    
2913            XSetFillStyle(g_display, g_gc, FillSolid);
2914    
2915            if (g_ownbackstore)
2916            {
2917                    if (boxcx > 1)
2918                    {
2919                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2920                                      boxy, boxcx, boxcy, boxx, boxy);
2921                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2922                                                    (g_display, g_backstore, sw->wnd, g_gc,
2923                                                     boxx, boxy,
2924                                                     boxcx, boxcy,
2925                                                     boxx - sw->xoffset, boxy - sw->yoffset));
2926                    }
2927                    else
2928                    {
2929                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2930                                      clipy, clipcx, clipcy, clipx, clipy);
2931                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2932                                                    (g_display, g_backstore, sw->wnd, g_gc,
2933                                                     clipx, clipy,
2934                                                     clipcx, clipcy, clipx - sw->xoffset,
2935                                                     clipy - sw->yoffset));
2936                    }
2937            }
2938  }  }
2939    
2940  void  void
# Line 1236  ui_desktop_save(uint32 offset, int x, in Line 2943  ui_desktop_save(uint32 offset, int x, in
2943          Pixmap pix;          Pixmap pix;
2944          XImage *image;          XImage *image;
2945    
2946          if (ownbackstore)          if (g_ownbackstore)
2947          {          {
2948                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
                                   ZPixmap);  
2949          }          }
2950          else          else
2951          {          {
2952                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2953                  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);
2954                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2955                                    ZPixmap);                  XFreePixmap(g_display, pix);
                 XFreePixmap(display, pix);  
2956          }          }
2957    
2958          offset *= bpp/8;          offset *= g_bpp / 8;
2959          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);  
2960    
2961          XDestroyImage(image);          XDestroyImage(image);
2962  }  }
# Line 1263  ui_desktop_restore(uint32 offset, int x, Line 2967  ui_desktop_restore(uint32 offset, int x,
2967          XImage *image;          XImage *image;
2968          uint8 *data;          uint8 *data;
2969    
2970          offset *= bpp/8;          offset *= g_bpp / 8;
2971          data = cache_get_desktop(offset, cx, cy, bpp/8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2972          if (data == NULL)          if (data == NULL)
2973                  return;                  return;
2974    
2975          image = XCreateImage(display, visual, depth, ZPixmap,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2976                               0, data, cx, cy, BitmapPad(display),                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
                              cx * bpp/8);  
2977    
2978          if (ownbackstore)          if (g_ownbackstore)
2979          {          {
2980                  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);
2981                  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);
2982                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2983                                            (g_display, g_backstore, sw->wnd, g_gc,
2984                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2985          }          }
2986          else          else
2987          {          {
2988                  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);
2989                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2990                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2991                                             x - sw->xoffset, y - sw->yoffset));
2992          }          }
2993    
2994          XFree(image);          XFree(image);
2995  }  }
2996    
2997    /* these do nothing here but are used in uiports */
2998    void
2999    ui_begin_update(void)
3000    {
3001    }
3002    
3003    void
3004    ui_end_update(void)
3005    {
3006    }
3007    
3008    void
3009    ui_seamless_begin()
3010    {
3011            if (!g_seamless_rdp)
3012                    return;
3013    
3014            if (g_seamless_started)
3015                    return;
3016    
3017            g_seamless_started = True;
3018    
3019            ui_seamless_toggle();
3020    }
3021    
3022    void
3023    ui_seamless_toggle()
3024    {
3025            if (!g_seamless_rdp)
3026                    return;
3027    
3028            if (!g_seamless_started)
3029                    return;
3030    
3031            if (g_seamless_active)
3032            {
3033                    /* Deactivate */
3034                    while (g_seamless_windows)
3035                    {
3036                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3037                            seamless_remove_window(g_seamless_windows);
3038                    }
3039                    XMapWindow(g_display, g_wnd);
3040            }
3041            else
3042            {
3043                    /* Activate */
3044                    XUnmapWindow(g_display, g_wnd);
3045                    seamless_send_sync();
3046            }
3047    
3048            g_seamless_active = !g_seamless_active;
3049    }
3050    
3051    void
3052    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3053    {
3054            Window wnd;
3055            XSetWindowAttributes attribs;
3056            XClassHint *classhints;
3057            XSizeHints *sizehints;
3058            long input_mask;
3059            seamless_window *sw, *sw_parent;
3060    
3061            if (!g_seamless_active)
3062                    return;
3063    
3064            /* Ignore CREATEs for existing windows */
3065            sw = seamless_get_window_by_id(id);
3066            if (sw)
3067                    return;
3068    
3069            get_window_attribs(&attribs);
3070            attribs.override_redirect = False;
3071    
3072            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3073                                InputOutput, g_visual,
3074                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3075                                CWBorderPixel, &attribs);
3076    
3077            XStoreName(g_display, wnd, "SeamlessRDP");
3078            ewmh_set_wm_name(wnd, "SeamlessRDP");
3079    
3080            mwm_hide_decorations(wnd);
3081    
3082            classhints = XAllocClassHint();
3083            if (classhints != NULL)
3084            {
3085                    classhints->res_name = "rdesktop";
3086                    classhints->res_class = "SeamlessRDP";
3087                    XSetClassHint(g_display, wnd, classhints);
3088                    XFree(classhints);
3089            }
3090    
3091            /* WM_NORMAL_HINTS */
3092            sizehints = XAllocSizeHints();
3093            if (sizehints != NULL)
3094            {
3095                    sizehints->flags = USPosition;
3096                    XSetWMNormalHints(g_display, wnd, sizehints);
3097                    XFree(sizehints);
3098            }
3099    
3100            /* Set WM_TRANSIENT_FOR, if necessary */
3101            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3102            {
3103                    sw_parent = seamless_get_window_by_id(parent);
3104                    if (sw_parent)
3105                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3106                    else
3107                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3108            }
3109    
3110    
3111            /* FIXME: Support for Input Context:s */
3112    
3113            get_input_mask(&input_mask);
3114            input_mask |= PropertyChangeMask;
3115    
3116            XSelectInput(g_display, wnd, input_mask);
3117    
3118            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3119               seamless window, we could try to close the window on the
3120               serverside, instead of terminating rdesktop */
3121            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3122    
3123            sw = malloc(sizeof(seamless_window));
3124            sw->wnd = wnd;
3125            sw->id = id;
3126            sw->parent = parent;
3127            sw->xoffset = 0;
3128            sw->yoffset = 0;
3129            sw->width = 0;
3130            sw->height = 0;
3131            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3132            sw->desktop = 0;
3133            sw->next = g_seamless_windows;
3134            g_seamless_windows = sw;
3135    }
3136    
3137    
3138    void
3139    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3140    {
3141            seamless_window *sw;
3142    
3143            if (!g_seamless_active)
3144                    return;
3145    
3146            sw = seamless_get_window_by_id(id);
3147            if (!sw)
3148            {
3149                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3150                    return;
3151            }
3152    
3153            XDestroyWindow(g_display, sw->wnd);
3154            seamless_remove_window(sw);
3155    }
3156    
3157    
3158    void
3159    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3160    {
3161            seamless_window *sw;
3162    
3163            if (!g_seamless_active)
3164                    return;
3165    
3166            sw = seamless_get_window_by_id(id);
3167            if (!sw)
3168            {
3169                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3170                    return;
3171            }
3172    
3173            if (!width || !height)
3174                    /* X11 windows must be at least 1x1 */
3175                    return;
3176    
3177            /* About MAX and MIN: Windows allows moving a window outside
3178               the desktop. This happens, for example, when maximizing an
3179               application. In this case, the position is set to something
3180               like -4,-4,1288,1032. Many WMs does not allow windows
3181               outside the desktop, however. Therefore, clip the window
3182               ourselves. */
3183            sw->xoffset = MAX(0, x);
3184            sw->yoffset = MAX(0, y);
3185            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3186            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3187    
3188            /* If we move the window in a maximized state, then KDE won't
3189               accept restoration */
3190            switch (sw->state)
3191            {
3192                    case SEAMLESSRDP_MINIMIZED:
3193                    case SEAMLESSRDP_MAXIMIZED:
3194                            return;
3195            }
3196    
3197            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3198            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3199    }
3200    
3201    
3202    void
3203    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3204    {
3205            seamless_window *sw;
3206    
3207            if (!g_seamless_active)
3208                    return;
3209    
3210            sw = seamless_get_window_by_id(id);
3211            if (!sw)
3212            {
3213                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3214                    return;
3215            }
3216    
3217            /* FIXME: Might want to convert the name for non-EWMH WMs */
3218            XStoreName(g_display, sw->wnd, title);
3219            ewmh_set_wm_name(sw->wnd, title);
3220    }
3221    
3222    
3223    void
3224    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3225    {
3226            seamless_window *sw;
3227    
3228            if (!g_seamless_active)
3229                    return;
3230    
3231            sw = seamless_get_window_by_id(id);
3232            if (!sw)
3233            {
3234                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3235                    return;
3236            }
3237    
3238            switch (state)
3239            {
3240                    case SEAMLESSRDP_NORMAL:
3241                    case SEAMLESSRDP_MAXIMIZED:
3242                            ewmh_change_state(sw->wnd, state);
3243                            XMapWindow(g_display, sw->wnd);
3244                            break;
3245                    case SEAMLESSRDP_MINIMIZED:
3246                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3247                               the Window Manager should probably just ignore the request, since
3248                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3249                               such as minimization, rather than an independent state." Besides,
3250                               XIconifyWindow is easier. */
3251                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3252                            {
3253                                    XWMHints *hints;
3254                                    hints = XAllocWMHints();
3255                                    hints->flags = StateHint;
3256                                    hints->initial_state = IconicState;
3257                                    XSetWMHints(g_display, sw->wnd, hints);
3258                                    XFree(hints);
3259                                    XMapWindow(g_display, sw->wnd);
3260                            }
3261                            else
3262                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3263                            break;
3264                    default:
3265                            warning("SeamlessRDP: Invalid state %d\n", state);
3266                            break;
3267            }
3268    
3269            /* Handle popups without parents through some ewm hints */
3270            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3271                    ewmh_set_window_popup(sw->wnd);
3272    
3273            sw->state = state;
3274    }
3275    
3276    
3277    void
3278    ui_seamless_syncbegin(unsigned long flags)
3279    {
3280            if (!g_seamless_active)
3281                    return;
3282    
3283            /* Destroy all seamless windows */
3284            while (g_seamless_windows)
3285            {
3286                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3287                    seamless_remove_window(g_seamless_windows);
3288            }
3289    }

Legend:
Removed from v.54  
changed lines
  Added in v.1149

  ViewVC Help
Powered by ViewVC 1.1.26