/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26