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

Legend:
Removed from v.69  
changed lines
  Added in v.1199

  ViewVC Help
Powered by ViewVC 1.1.26