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

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

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

Legend:
Removed from v.66  
changed lines
  Added in v.1372

  ViewVC Help
Powered by ViewVC 1.1.26