/[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 70 by astrand, Sat Jul 27 23:09:32 2002 UTC revision 1246 by stargo, Tue Jul 11 17:22:24 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));
 /* Compose support */  
 BOOL enable_compose = False;  
   
 #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  
 #define SET_FOREGROUND(col)     XSetForeground(display, gc, TRANSLATE(col));  
 #define SET_BACKGROUND(col)     XSetBackground(display, gc, TRANSLATE(col));  
261    
262  static int rop2_map[] = {  static int rop2_map[] = {
263          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 88  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                  case 32:          sw_below = NULL;
440                          translate32(data, (uint32 *) out, (uint32 *) end);  
441            i = 0;
442            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 = 0;          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                    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                  error("Failed to open input method\n");                  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                  /* Must be done after XCreateWindow */                  /* *INDENT-OFF* */
1002                  IC = XCreateIC(IM, XNInputStyle,                  REPEAT4
1003                                 (XIMPreeditNothing | XIMStatusNothing),                  (
1004                                 XNClientWindow, wnd, XNFocusWindow, wnd, NULL);                          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                    if (g_host_be)
1016                    {
1017                            while (out < end)
1018                            {
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                            BOUT16(out, value);
1080                    }
1081                    else
1082                  {                  {
1083                          error("Failed to create input context\n");                          LOUT16(out, value);
                         XCloseIM(IM);  
                         IM = NULL;  
1084                  }                  }
1085          }          }
1086    }
1087    
1088          /* For correct Multi_key/Compose processing, I guess.  static void
1089             It seems to work alright anyway, though. */  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1090          if (IC != NULL)  {
1091            uint32 pixel;
1092            uint32 value;
1093            PixelColour pc;
1094    
1095            if (g_xserver_be)
1096            {
1097                    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                  XDestroyIC(IC);                  /* *INDENT-OFF* */
1131                  if (IM != NULL)  #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                          XCloseIM(IM);                          pixel = *(data++) << 16;
1155                          IM = NULL;                          pixel |= *(data++) << 8;
1156                            pixel |= *(data++);
1157                            SPLITCOLOUR24(pixel, pc);
1158                            value = MAKECOLOUR(pc);
1159                            BOUT32(out, value);
1160                    }
1161            }
1162            else
1163            {
1164                    while (out < end)
1165                    {
1166                            pixel = *(data++) << 16;
1167                            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(int screen_num)
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 red_weight, blue_weight, green_weight;
1325    
1326            red_weight = blue_weight = green_weight = 0;
1327    
1328          display = XOpenDisplay(NULL);          if (g_server_depth == -1)
1329            {
1330                    g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1331            }
1332    
1333          if (display == NULL)          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1334            if (pfm == NULL)
1335          {          {
1336                  error("Failed to open display\n");                  error("Unable to get list of pixmap formats from display.\n");
1337                    XCloseDisplay(g_display);
1338                  return False;                  return False;
1339          }          }
1340    
1341          x_socket = ConnectionNumber(display);          /* Search for best TrueColor visual */
1342          screen = DefaultScreenOfDisplay(display);          template.class = TrueColor;
1343          visual = DefaultVisualOfScreen(screen);          template.screen = screen_num;
1344          depth = DefaultDepthOfScreen(screen);          vmatches = XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template, &visuals_count);
1345            g_visual = NULL;
1346            g_no_translate_image = False;
1347            g_compatible_arch = False;
1348            if (vmatches != NULL)
1349            {
1350                    for (i = 0; i < visuals_count; ++i)
1351                    {
1352                            XVisualInfo *visual_info = &vmatches[i];
1353                            BOOL can_translate_to_bpp = False;
1354                            int j;
1355    
1356                            /* Try to find a no-translation visual that'll
1357                               allow us to use RDP bitmaps directly as ZPixmaps. */
1358                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1359                                                   /* R5G5B5 */
1360                                                   (visual_info->red_mask == 0x7c00) &&
1361                                                   (visual_info->green_mask == 0x3e0) &&
1362                                                   (visual_info->blue_mask == 0x1f)) ||
1363                                                  ((visual_info->depth == 16) &&
1364                                                   /* R5G6B5 */
1365                                                   (visual_info->red_mask == 0xf800) &&
1366                                                   (visual_info->green_mask == 0x7e0) &&
1367                                                   (visual_info->blue_mask == 0x1f)) ||
1368                                                  ((visual_info->depth == 24) &&
1369                                                   /* R8G8B8 */
1370                                                   (visual_info->red_mask == 0xff0000) &&
1371                                                   (visual_info->green_mask == 0xff00) &&
1372                                                   (visual_info->blue_mask == 0xff))))
1373                            {
1374                                    g_visual = visual_info->visual;
1375                                    g_depth = visual_info->depth;
1376                                    g_compatible_arch = !g_host_be;
1377                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1378                                    if (g_no_translate_image)
1379                                            /* We found the best visual */
1380                                            break;
1381                            }
1382                            else
1383                            {
1384                                    g_compatible_arch = False;
1385                            }
1386    
1387                            if (visual_info->depth > 24)
1388                            {
1389                                    /* Avoid 32-bit visuals and likes like the plague.
1390                                       They're either untested or proven to work bad
1391                                       (e.g. nvidia's Composite 32-bit visual).
1392                                       Most implementation offer a 24-bit visual anyway. */
1393                                    continue;
1394                            }
1395    
1396                            /* Only care for visuals, for whose BPPs (not depths!)
1397                               we have a translateXtoY function. */
1398                            for (j = 0; j < pixmap_formats_count; ++j)
1399                            {
1400                                    if (pfm[j].depth == visual_info->depth)
1401                                    {
1402                                            if ((pfm[j].bits_per_pixel == 16) ||
1403                                                (pfm[j].bits_per_pixel == 24) ||
1404                                                (pfm[j].bits_per_pixel == 32))
1405                                            {
1406                                                    can_translate_to_bpp = True;
1407                                            }
1408                                            break;
1409                                    }
1410                            }
1411    
1412                            /* Prefer formats which have the most colour depth.
1413                               We're being truly aristocratic here, minding each
1414                               weight on its own. */
1415                            if (can_translate_to_bpp)
1416                            {
1417                                    unsigned vis_red_weight =
1418                                            calculate_mask_weight(visual_info->red_mask);
1419                                    unsigned vis_green_weight =
1420                                            calculate_mask_weight(visual_info->green_mask);
1421                                    unsigned vis_blue_weight =
1422                                            calculate_mask_weight(visual_info->blue_mask);
1423                                    if ((vis_red_weight >= red_weight)
1424                                        && (vis_green_weight >= green_weight)
1425                                        && (vis_blue_weight >= blue_weight))
1426                                    {
1427                                            red_weight = vis_red_weight;
1428                                            green_weight = vis_green_weight;
1429                                            blue_weight = vis_blue_weight;
1430                                            g_visual = visual_info->visual;
1431                                            g_depth = visual_info->depth;
1432                                    }
1433                            }
1434                    }
1435                    XFree(vmatches);
1436            }
1437    
1438            if (g_visual != NULL)
1439            {
1440                    g_owncolmap = False;
1441                    calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1442                    calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1443                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1444            }
1445            else
1446            {
1447                    template.class = PseudoColor;
1448                    template.depth = 8;
1449                    template.colormap_size = 256;
1450                    vmatches =
1451                            XGetVisualInfo(g_display,
1452                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1453                                           &template, &visuals_count);
1454                    if (vmatches == NULL)
1455                    {
1456                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1457                            XCloseDisplay(g_display);
1458                            XFree(pfm);
1459                            return False;
1460                    }
1461    
1462                    /* we use a colourmap, so the default visual should do */
1463                    g_owncolmap = True;
1464                    g_visual = vmatches[0].visual;
1465                    g_depth = vmatches[0].depth;
1466            }
1467    
1468          pfm = XListPixmapFormats(display, &i);          g_bpp = 0;
1469          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1470          {          {
1471                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1472                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1473                  {                  {
1474                          if ((pfm[i].depth == depth)                          g_bpp = pf->bits_per_pixel;
1475                              && (pfm[i].bits_per_pixel > bpp))  
1476                            if (g_no_translate_image)
1477                          {                          {
1478                                  bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1479                                    {
1480                                            case 15:
1481                                            case 16:
1482                                                    if (g_bpp != 16)
1483                                                            g_no_translate_image = False;
1484                                                    break;
1485                                            case 24:
1486                                                    /* Yes, this will force image translation
1487                                                       on most modern servers which use 32 bits
1488                                                       for R8G8B8. */
1489                                                    if (g_bpp != 24)
1490                                                            g_no_translate_image = False;
1491                                                    break;
1492                                            default:
1493                                                    g_no_translate_image = False;
1494                                                    break;
1495                                    }
1496                          }                          }
1497    
1498                            /* Pixmap formats list is a depth-to-bpp mapping --
1499                               there's just a single entry for every depth,
1500                               so we can safely break here */
1501                            break;
1502                  }                  }
                 XFree(pfm);  
1503          }          }
1504            XFree(pfm);
1505            pfm = NULL;
1506            return True;
1507    }
1508    
1509    static XErrorHandler g_old_error_handler;
1510    
1511          if (bpp < 8)  static int
1512    error_handler(Display * dpy, XErrorEvent * eev)
1513    {
1514            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1515          {          {
1516                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1517                  XCloseDisplay(display);                  fprintf(stderr,
1518                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1519                    return 0;
1520            }
1521    
1522            return g_old_error_handler(dpy, eev);
1523    }
1524    
1525    BOOL
1526    ui_init(void)
1527    {
1528            int screen_num;
1529    
1530            g_display = XOpenDisplay(NULL);
1531            if (g_display == NULL)
1532            {
1533                    error("Failed to open display: %s\n", XDisplayName(NULL));
1534                  return False;                  return False;
1535          }          }
1536    
1537          if (depth <= 8)          {
1538                  owncolmap = True;                  uint16 endianess_test = 1;
1539          else                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1540                  xcolmap = DefaultColormapOfScreen(screen);          }
1541    
1542          test = 1;          g_old_error_handler = XSetErrorHandler(error_handler);
1543          host_be = !(BOOL) (*(uint8 *) (&test));          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1544          xserver_be = (ImageByteOrder(display) == MSBFirst);          screen_num = DefaultScreen(g_display);
1545            g_x_socket = ConnectionNumber(g_display);
1546            g_screen = ScreenOfDisplay(g_display, screen_num);
1547            g_depth = DefaultDepthOfScreen(g_screen);
1548    
1549          white = WhitePixelOfScreen(screen);          if (!select_visual(screen_num))
1550          attribs.background_pixel = BlackPixelOfScreen(screen);                  return False;
         attribs.backing_store = DoesBackingStore(screen);  
1551    
1552          if (attribs.backing_store == NotUseful)          if (g_no_translate_image)
1553                  ownbackstore = True;          {
1554                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1555            }
1556    
1557          if (fullscreen)          if (g_server_depth > g_bpp)
1558          {          {
1559                  attribs.override_redirect = True;                  warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1560                  width = WidthOfScreen(screen);                          g_server_depth, g_bpp);
                 height = HeightOfScreen(screen);  
1561          }          }
1562          else  
1563            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1564                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1565    
1566            if (!g_owncolmap)
1567          {          {
1568                  attribs.override_redirect = False;                  g_xcolmap =
1569                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1570                                            AllocNone);
1571                    if (g_depth <= 8)
1572                            warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1573          }          }
1574    
1575          width = (width + 3) & ~3;       /* make width a multiple of 32 bits */          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1576            {
1577                    warning("External BackingStore not available. Using internal.\n");
1578                    g_ownbackstore = True;
1579            }
1580    
1581          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          /*
1582                              0, 0, width, height, 0, CopyFromParent,           * Determine desktop size
1583                              InputOutput, CopyFromParent,           */
1584                              CWBackingStore | CWBackPixel | CWOverrideRedirect,          if (g_fullscreen)
1585                              &attribs);          {
1586                    g_width = WidthOfScreen(g_screen);
1587                    g_height = HeightOfScreen(g_screen);
1588                    g_using_full_workarea = True;
1589            }
1590            else if (g_width < 0)
1591            {
1592                    /* Percent of screen */
1593                    if (-g_width >= 100)
1594                            g_using_full_workarea = True;
1595                    g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1596                    g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1597            }
1598            else if (g_width == 0)
1599            {
1600                    /* Fetch geometry from _NET_WORKAREA */
1601                    uint32 x, y, cx, cy;
1602                    if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1603                    {
1604                            g_width = cx;
1605                            g_height = cy;
1606                            g_using_full_workarea = True;
1607                    }
1608                    else
1609                    {
1610                            warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1611                            g_width = WidthOfScreen(g_screen);
1612                            g_height = HeightOfScreen(g_screen);
1613                    }
1614            }
1615    
1616            /* make sure width is a multiple of 4 */
1617            g_width = (g_width + 3) & ~3;
1618    
1619            g_mod_map = XGetModifierMapping(g_display);
1620    
1621            xkeymap_init();
1622    
1623            if (g_enable_compose)
1624                    g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1625    
1626            xclip_init();
1627            ewmh_init();
1628            if (g_seamless_rdp)
1629                    seamless_init();
1630    
1631            DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1632    
1633            return True;
1634    }
1635    
1636    void
1637    ui_deinit(void)
1638    {
1639            while (g_seamless_windows)
1640            {
1641                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1642                    sw_remove_window(g_seamless_windows);
1643            }
1644    
1645            xclip_deinit();
1646    
1647            if (g_IM != NULL)
1648                    XCloseIM(g_IM);
1649    
1650            if (g_null_cursor != NULL)
1651                    ui_destroy_cursor(g_null_cursor);
1652    
1653            XFreeModifiermap(g_mod_map);
1654    
1655            if (g_ownbackstore)
1656                    XFreePixmap(g_display, g_backstore);
1657    
1658            XFreeGC(g_display, g_gc);
1659            XCloseDisplay(g_display);
1660            g_display = NULL;
1661    }
1662    
1663    
1664    static void
1665    get_window_attribs(XSetWindowAttributes * attribs)
1666    {
1667            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1668            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1669            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1670            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1671            attribs->override_redirect = g_fullscreen;
1672            attribs->colormap = g_xcolmap;
1673    }
1674    
1675    static void
1676    get_input_mask(long *input_mask)
1677    {
1678            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1679                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1680    
1681          XStoreName(display, wnd, title);          if (g_sendmotion)
1682                    *input_mask |= PointerMotionMask;
1683            if (g_ownbackstore)
1684                    *input_mask |= ExposureMask;
1685            if (g_fullscreen || g_grab_keyboard)
1686                    *input_mask |= EnterWindowMask;
1687            if (g_grab_keyboard)
1688                    *input_mask |= LeaveWindowMask;
1689    }
1690    
1691    BOOL
1692    ui_create_window(void)
1693    {
1694            uint8 null_pointer_mask[1] = { 0x80 };
1695            uint8 null_pointer_data[24] = { 0x00 };
1696    
1697            XSetWindowAttributes attribs;
1698            XClassHint *classhints;
1699            XSizeHints *sizehints;
1700            int wndwidth, wndheight;
1701            long input_mask, ic_input_mask;
1702            XEvent xevent;
1703    
1704            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1705            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1706    
1707            /* Handle -x-y portion of geometry string */
1708            if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1709                    g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1710            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1711                    g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1712    
1713            get_window_attribs(&attribs);
1714    
1715            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1716                                  wndheight, 0, g_depth, InputOutput, g_visual,
1717                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1718                                  CWBorderPixel, &attribs);
1719    
1720            if (g_gc == NULL)
1721            {
1722                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1723                    ui_reset_clip();
1724            }
1725    
1726            if (g_create_bitmap_gc == NULL)
1727                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1728    
1729            if ((g_ownbackstore) && (g_backstore == 0))
1730            {
1731                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1732    
1733                    /* clear to prevent rubbish being exposed at startup */
1734                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1735                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1736            }
1737    
1738            XStoreName(g_display, g_wnd, g_title);
1739    
1740            if (g_hide_decorations)
1741                    mwm_hide_decorations(g_wnd);
1742    
1743          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1744          if (classhints != NULL)          if (classhints != NULL)
1745          {          {
1746                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = classhints->res_class = "rdesktop";
1747                  XSetClassHint(display, wnd, classhints);                  XSetClassHint(g_display, g_wnd, classhints);
1748                  XFree(classhints);                  XFree(classhints);
1749          }          }
1750    
# Line 337  ui_create_window(char *title) Line 1752  ui_create_window(char *title)
1752          if (sizehints)          if (sizehints)
1753          {          {
1754                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1755                  sizehints->min_width = sizehints->max_width = width;                  if (g_pos)
1756                  sizehints->min_height = sizehints->max_height = height;                          sizehints->flags |= PPosition;
1757                  XSetWMNormalHints(display, wnd, sizehints);                  sizehints->min_width = sizehints->max_width = g_width;
1758                    sizehints->min_height = sizehints->max_height = g_height;
1759                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1760                  XFree(sizehints);                  XFree(sizehints);
1761          }          }
1762    
1763          xkeymap_init2();          if (g_embed_wnd)
1764            {
1765                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1766            }
1767    
1768          input_mask =          get_input_mask(&input_mask);
                 KeyPressMask | KeyReleaseMask | ButtonPressMask |  
                 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;  
         if (sendmotion)  
                 input_mask |= PointerMotionMask;  
1769    
1770          if (ownbackstore)          if (g_IM != NULL)
1771                  input_mask |= ExposureMask;          {
1772                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1773                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1774    
1775          if (enable_compose)                  if ((g_IC != NULL)
1776                  input_mask |= init_inputmethod();                      && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1777                            input_mask |= ic_input_mask;
1778            }
1779    
1780          XSelectInput(display, wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
1781            XMapWindow(g_display, g_wnd);
1782    
1783          gc = XCreateGC(display, wnd, 0, NULL);          /* wait for VisibilityNotify */
1784            do
1785            {
1786                    XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1787            }
1788            while (xevent.type != VisibilityNotify);
1789            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1790    
1791          if (ownbackstore)          g_focused = False;
1792                  backstore = XCreatePixmap(display, wnd, width, height, depth);          g_mouse_in_wnd = False;
1793    
1794          XMapWindow(display, wnd);          /* handle the WM_DELETE_WINDOW protocol */
1795            g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1796            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1797            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1798    
1799            /* create invisible 1x1 cursor to be used as null cursor */
1800            if (g_null_cursor == NULL)
1801                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1802    
1803          return True;          return True;
1804  }  }
1805    
1806  void  void
1807  ui_destroy_window()  ui_resize_window()
1808  {  {
1809          if (ownbackstore)          XSizeHints *sizehints;
1810                  XFreePixmap(display, backstore);          Pixmap bs;
1811    
1812          XFreeGC(display, gc);          sizehints = XAllocSizeHints();
1813            if (sizehints)
1814            {
1815                    sizehints->flags = PMinSize | PMaxSize;
1816                    sizehints->min_width = sizehints->max_width = g_width;
1817                    sizehints->min_height = sizehints->max_height = g_height;
1818                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1819                    XFree(sizehints);
1820            }
1821    
1822            if (!(g_fullscreen || g_embed_wnd))
1823            {
1824                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1825            }
1826    
1827            /* create new backstore pixmap */
1828            if (g_backstore != 0)
1829            {
1830                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1831                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1832                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1833                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1834                    XFreePixmap(g_display, g_backstore);
1835                    g_backstore = bs;
1836            }
1837    }
1838    
1839    void
1840    ui_destroy_window(void)
1841    {
1842            if (g_IC != NULL)
1843                    XDestroyIC(g_IC);
1844    
1845            XDestroyWindow(g_display, g_wnd);
1846    }
1847    
1848    void
1849    xwin_toggle_fullscreen(void)
1850    {
1851            Pixmap contents = 0;
1852    
1853            if (g_seamless_active)
1854                    /* Turn off SeamlessRDP mode */
1855                    ui_seamless_toggle();
1856    
1857          close_inputmethod();          if (!g_ownbackstore)
1858            {
1859                    /* need to save contents of window */
1860                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1861                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1862            }
1863    
1864            ui_destroy_window();
1865            g_fullscreen = !g_fullscreen;
1866            ui_create_window();
1867    
1868          XDestroyWindow(display, wnd);          XDefineCursor(g_display, g_wnd, g_current_cursor);
1869          XCloseDisplay(display);  
1870          display = NULL;          if (!g_ownbackstore)
1871            {
1872                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1873                    XFreePixmap(g_display, contents);
1874            }
1875  }  }
1876    
1877  static void  static void
1878  xwin_process_events()  handle_button_event(XEvent xevent, BOOL down)
1879  {  {
1880          XEvent xevent;          uint16 button, flags = 0;
1881            g_last_gesturetime = xevent.xbutton.time;
1882            button = xkeymap_translate_button(xevent.xbutton.button);
1883            if (button == 0)
1884                    return;
1885    
1886            if (down)
1887                    flags = MOUSE_FLAG_DOWN;
1888    
1889            /* Stop moving window when button is released, regardless of cursor position */
1890            if (g_moving_wnd && (xevent.type == ButtonRelease))
1891                    g_moving_wnd = False;
1892    
1893            /* If win_button_size is nonzero, enable single app mode */
1894            if (xevent.xbutton.y < g_win_button_size)
1895            {
1896                    /*  Check from right to left: */
1897                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1898                    {
1899                            /* The close button, continue */
1900                            ;
1901                    }
1902                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1903                    {
1904                            /* The maximize/restore button. Do not send to
1905                               server.  It might be a good idea to change the
1906                               cursor or give some other visible indication
1907                               that rdesktop inhibited this click */
1908                            if (xevent.type == ButtonPress)
1909                                    return;
1910                    }
1911                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1912                    {
1913                            /* The minimize button. Iconify window. */
1914                            if (xevent.type == ButtonRelease)
1915                            {
1916                                    /* Release the mouse button outside the minimize button, to prevent the
1917                                       actual minimazation to happen */
1918                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1919                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1920                                    return;
1921                            }
1922                    }
1923                    else if (xevent.xbutton.x <= g_win_button_size)
1924                    {
1925                            /* The system menu. Ignore. */
1926                            if (xevent.type == ButtonPress)
1927                                    return;
1928                    }
1929                    else
1930                    {
1931                            /* The title bar. */
1932                            if (xevent.type == ButtonPress)
1933                            {
1934                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1935                                    {
1936                                            g_moving_wnd = True;
1937                                            g_move_x_offset = xevent.xbutton.x;
1938                                            g_move_y_offset = xevent.xbutton.y;
1939                                    }
1940                                    return;
1941                            }
1942                    }
1943            }
1944    
1945            if (xevent.xmotion.window == g_wnd)
1946            {
1947                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1948                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1949            }
1950            else
1951            {
1952                    /* SeamlessRDP */
1953                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1954                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1955            }
1956    }
1957    
1958    
1959    /* Process events in Xlib queue
1960       Returns 0 after user quit, 1 otherwise */
1961    static int
1962    xwin_process_events(void)
1963    {
1964            XEvent xevent;
1965          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1966          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
         char *ksname = NULL;  
1967          char str[256];          char str[256];
1968          Status status;          Status status;
1969            int events = 0;
1970            seamless_window *sw;
1971    
1972          /* 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))  
1973          {          {
1974                  if (xevent.xmapping.request == MappingKeyboard                  XNextEvent(g_display, &xevent);
                     || xevent.xmapping.request == MappingModifier)  
                         XRefreshKeyboardMapping(&xevent.xmapping);  
         }  
1975    
1976          while (XCheckMaskEvent(display, ~0, &xevent))                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
         {  
                 if (enable_compose && (XFilterEvent(&xevent, None) == True))  
1977                  {                  {
1978                          DEBUG_KBD("Filtering event\n");                          DEBUG_KBD(("Filtering event\n"));
1979                          continue;                          continue;
1980                  }                  }
1981    
                 ev_time = time(NULL);  
                 flags = 0;  
   
1982                  switch (xevent.type)                  switch (xevent.type)
1983                  {                  {
1984                            case VisibilityNotify:
1985                                    if (xevent.xvisibility.window == g_wnd)
1986                                            g_Unobscured =
1987                                                    xevent.xvisibility.state == VisibilityUnobscured;
1988    
1989                                    break;
1990                            case ClientMessage:
1991                                    /* the window manager told us to quit */
1992                                    if ((xevent.xclient.message_type == g_protocol_atom)
1993                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1994                                            /* Quit */
1995                                            return 0;
1996                                    break;
1997    
1998                          case KeyPress:                          case KeyPress:
1999                                  if (IC != NULL)                                  g_last_gesturetime = xevent.xkey.time;
2000                                    if (g_IC != NULL)
2001                                          /* Multi_key compatible version */                                          /* Multi_key compatible version */
2002                                  {                                  {
2003                                          XmbLookupString(IC,                                          XmbLookupString(g_IC,
2004                                                          (XKeyPressedEvent *) &                                                          &xevent.xkey, str, sizeof(str), &keysym,
                                                         xevent, str,  
                                                         sizeof(str), &keysym,  
2005                                                          &status);                                                          &status);
2006                                          if (!                                          if (!((status == XLookupKeySym) || (status == XLookupBoth)))
                                             ((status == XLookupKeySym)  
                                              || (status == XLookupBoth)))  
2007                                          {                                          {
2008                                                  error("XmbLookupString failed with status 0x%x\n", status);                                                  error("XmbLookupString failed with status 0x%x\n",
2009                                                          status);
2010                                                  break;                                                  break;
2011                                          }                                          }
2012                                  }                                  }
2013                                  else                                  else
2014                                  {                                  {
2015                                          /* Plain old XLookupString */                                          /* Plain old XLookupString */
2016                                          DEBUG_KBD                                          DEBUG_KBD(("\nNo input context, using XLookupString\n"));
                                                 ("No input context, using XLookupString\n");  
2017                                          XLookupString((XKeyEvent *) & xevent,                                          XLookupString((XKeyEvent *) & xevent,
2018                                                        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;  
2019                                  }                                  }
2020    
2021                                  tr = xkeymap_translate_key(keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2022                                                             xevent.xkey.                                             get_ksname(keysym)));
                                                            keycode,  
                                                            xevent.xkey.state);  
2023    
2024                                  ensure_remote_modifiers(ev_time, tr);                                  ev_time = time(NULL);
2025                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
                                 if (tr.scancode == 0)  
2026                                          break;                                          break;
2027    
2028                                  rdp_send_scancode(ev_time, RDP_KEYPRESS,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2029                                                    tr.scancode);                                                    ev_time, True, 0);
2030                                  break;                                  break;
2031    
2032                          case KeyRelease:                          case KeyRelease:
2033                                    g_last_gesturetime = xevent.xkey.time;
2034                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2035                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2036    
2037                                  ksname = get_ksname(keysym);                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2038                                  DEBUG_KBD                                             get_ksname(keysym)));
                                         ("\nKeyRelease for (keysym 0x%lx, %s)\n",  
                                          keysym, ksname);  
2039    
2040                                  if (inhibit_key(keysym))                                  ev_time = time(NULL);
2041                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2042                                          break;                                          break;
2043    
2044                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2045                                                             xevent.xkey.                                                    ev_time, False, 0);
2046                                                             keycode,                                  break;
                                                            xevent.xkey.state);  
2047    
2048                                  if (tr.scancode == 0)                          case ButtonPress:
2049                                    handle_button_event(xevent, True);
2050                                    break;
2051    
2052                            case ButtonRelease:
2053                                    handle_button_event(xevent, False);
2054                                    break;
2055    
2056                            case MotionNotify:
2057                                    if (g_moving_wnd)
2058                                    {
2059                                            XMoveWindow(g_display, g_wnd,
2060                                                        xevent.xmotion.x_root - g_move_x_offset,
2061                                                        xevent.xmotion.y_root - g_move_y_offset);
2062                                          break;                                          break;
2063                                    }
2064    
2065                                    if (g_fullscreen && !g_focused)
2066                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2067                                                           CurrentTime);
2068    
2069                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE,                                  if (xevent.xmotion.window == g_wnd)
2070                                                    tr.scancode);                                  {
2071                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2072                                                           xevent.xmotion.x, xevent.xmotion.y);
2073                                    }
2074                                    else
2075                                    {
2076                                            /* SeamlessRDP */
2077                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2078                                                           xevent.xmotion.x_root,
2079                                                           xevent.xmotion.y_root);
2080                                    }
2081                                  break;                                  break;
2082    
2083                          case ButtonPress:                          case FocusIn:
2084                                  flags = MOUSE_FLAG_DOWN;                                  if (xevent.xfocus.mode == NotifyGrab)
2085                                  /* fall through */                                          break;
2086                                    g_focused = True;
2087                                    reset_modifier_keys();
2088                                    if (g_grab_keyboard && g_mouse_in_wnd)
2089                                            XGrabKeyboard(g_display, g_wnd, True,
2090                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2091    
2092                          case ButtonRelease:                                  sw = sw_get_window_by_wnd(xevent.xfocus.window);
2093                                  button = xkeymap_translate_button(xevent.                                  if (!sw)
                                                                   xbutton.  
                                                                   button);  
                                 if (button == 0)  
2094                                          break;                                          break;
2095    
2096                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (sw->id != g_seamless_focused)
2097                                                 flags | button,                                  {
2098                                                 xevent.xbutton.x,                                          seamless_send_focus(sw->id, 0);
2099                                                 xevent.xbutton.y);                                          g_seamless_focused = sw->id;
2100                                    }
2101                                  break;                                  break;
2102    
2103                          case MotionNotify:                          case FocusOut:
2104                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (xevent.xfocus.mode == NotifyUngrab)
2105                                                 MOUSE_FLAG_MOVE,                                          break;
2106                                                 xevent.xmotion.x,                                  g_focused = False;
2107                                                 xevent.xmotion.y);                                  if (xevent.xfocus.mode == NotifyWhileGrabbed)
2108                                            XUngrabKeyboard(g_display, CurrentTime);
2109                                  break;                                  break;
2110    
2111                          case EnterNotify:                          case EnterNotify:
2112                                  XGrabKeyboard(display, wnd, True,                                  /* we only register for this event when in fullscreen mode */
2113                                                GrabModeAsync, GrabModeAsync,                                  /* or grab_keyboard */
2114                                                CurrentTime);                                  g_mouse_in_wnd = True;
2115                                    if (g_fullscreen)
2116                                    {
2117                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2118                                                           CurrentTime);
2119                                            break;
2120                                    }
2121                                    if (g_focused)
2122                                            XGrabKeyboard(g_display, g_wnd, True,
2123                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2124                                  break;                                  break;
2125    
2126                          case LeaveNotify:                          case LeaveNotify:
2127                                  XUngrabKeyboard(display, CurrentTime);                                  /* we only register for this event when grab_keyboard */
2128                                    g_mouse_in_wnd = False;
2129                                    XUngrabKeyboard(g_display, CurrentTime);
2130                                  break;                                  break;
2131    
2132                          case Expose:                          case Expose:
2133                                  XCopyArea(display, backstore, wnd, gc,                                  if (xevent.xexpose.window == g_wnd)
2134                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2135                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2136                                            xevent.xexpose.height,                                                    g_gc,
2137                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2138                                                      xevent.xexpose.width, xevent.xexpose.height,
2139                                                      xevent.xexpose.x, xevent.xexpose.y);
2140                                    }
2141                                    else
2142                                    {
2143                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2144                                            if (!sw)
2145                                                    break;
2146                                            XCopyArea(g_display, g_backstore,
2147                                                      xevent.xexpose.window, g_gc,
2148                                                      xevent.xexpose.x + sw->xoffset,
2149                                                      xevent.xexpose.y + sw->yoffset,
2150                                                      xevent.xexpose.width,
2151                                                      xevent.xexpose.height, xevent.xexpose.x,
2152                                                      xevent.xexpose.y);
2153                                    }
2154    
2155                                    break;
2156    
2157                            case MappingNotify:
2158                                    /* Refresh keyboard mapping if it has changed. This is important for
2159                                       Xvnc, since it allocates keycodes dynamically */
2160                                    if (xevent.xmapping.request == MappingKeyboard
2161                                        || xevent.xmapping.request == MappingModifier)
2162                                            XRefreshKeyboardMapping(&xevent.xmapping);
2163    
2164                                    if (xevent.xmapping.request == MappingModifier)
2165                                    {
2166                                            XFreeModifiermap(g_mod_map);
2167                                            g_mod_map = XGetModifierMapping(g_display);
2168                                    }
2169                                    break;
2170    
2171                                    /* clipboard stuff */
2172                            case SelectionNotify:
2173                                    xclip_handle_SelectionNotify(&xevent.xselection);
2174                                    break;
2175                            case SelectionRequest:
2176                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2177                                    break;
2178                            case SelectionClear:
2179                                    xclip_handle_SelectionClear();
2180                                    break;
2181                            case PropertyNotify:
2182                                    xclip_handle_PropertyNotify(&xevent.xproperty);
2183                                    if (xevent.xproperty.window == g_wnd)
2184                                            break;
2185                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2186                                            break;
2187    
2188                                    /* seamless */
2189                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2190                                    if (!sw)
2191                                            break;
2192    
2193                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2194                                        && (xevent.xproperty.state == PropertyNewValue))
2195                                    {
2196                                            sw->state = ewmh_get_window_state(sw->wnd);
2197                                            seamless_send_state(sw->id, sw->state, 0);
2198                                    }
2199    
2200                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2201                                        && (xevent.xproperty.state == PropertyNewValue))
2202                                    {
2203                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2204                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2205                                    }
2206    
2207                                    break;
2208                            case MapNotify:
2209                                    if (!g_seamless_active)
2210                                            rdp_send_client_window_status(1);
2211                                    break;
2212                            case UnmapNotify:
2213                                    if (!g_seamless_active)
2214                                            rdp_send_client_window_status(0);
2215                                    break;
2216                            case ConfigureNotify:
2217                                    if (!g_seamless_active)
2218                                            break;
2219    
2220                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2221                                    if (!sw)
2222                                            break;
2223    
2224                                    gettimeofday(sw->position_timer, NULL);
2225                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2226                                        1000000)
2227                                    {
2228                                            sw->position_timer->tv_usec +=
2229                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2230                                            sw->position_timer->tv_sec += 1;
2231                                    }
2232                                    else
2233                                    {
2234                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2235                                    }
2236    
2237                                    sw_handle_restack(sw);
2238                                  break;                                  break;
2239                  }                  }
2240          }          }
2241            /* Keep going */
2242            return 1;
2243  }  }
2244    
2245  void  /* Returns 0 after user quit, 1 otherwise */
2246    int
2247  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2248  {  {
2249          int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;          int n;
2250          fd_set rfds;          fd_set rfds, wfds;
2251            struct timeval tv;
2252          FD_ZERO(&rfds);          BOOL s_timeout = False;
2253    
2254          while (True)          while (True)
2255          {          {
2256                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2257                    /* Process any events already waiting */
2258                    if (!xwin_process_events())
2259                            /* User quit */
2260                            return 0;
2261    
2262                    if (g_seamless_active)
2263                            sw_check_timers();
2264    
2265                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2266                    FD_ZERO(&wfds);
2267                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2268                  if (display != NULL)                  FD_SET(g_x_socket, &rfds);
2269    
2270    #ifdef WITH_RDPSND
2271                    /* FIXME: there should be an API for registering fds */
2272                    if (g_dsp_busy)
2273                  {                  {
2274                          FD_SET(x_socket, &rfds);                          FD_SET(g_dsp_fd, &wfds);
2275                          XFlush(display);                          n = (g_dsp_fd > n) ? g_dsp_fd : n;
2276                  }                  }
2277    #endif
2278                    /* default timeout */
2279                    tv.tv_sec = 60;
2280                    tv.tv_usec = 0;
2281    
2282                    /* add redirection handles */
2283                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2284                    seamless_select_timeout(&tv);
2285    
2286                    n++;
2287    
2288                  switch (select(n, &rfds, NULL, NULL, NULL))                  switch (select(n, &rfds, &wfds, NULL, &tv))
2289                  {                  {
2290                          case -1:                          case -1:
2291                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2292    
2293                          case 0:                          case 0:
2294                                    /* Abort serial read calls */
2295                                    if (s_timeout)
2296                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2297                                  continue;                                  continue;
2298                  }                  }
2299    
2300                  if (FD_ISSET(x_socket, &rfds))                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
                         xwin_process_events();  
2301    
2302                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2303                          return;                          return 1;
2304    
2305    #ifdef WITH_RDPSND
2306                    if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2307                            wave_out_play();
2308    #endif
2309          }          }
2310  }  }
2311    
2312  void  void
2313  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
2314  {  {
2315          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2316  }  }
2317    
2318  HBITMAP  HBITMAP
# Line 586  ui_create_bitmap(int width, int height, Line 2321  ui_create_bitmap(int width, int height,
2321          XImage *image;          XImage *image;
2322          Pixmap bitmap;          Pixmap bitmap;
2323          uint8 *tdata;          uint8 *tdata;
2324            int bitmap_pad;
2325    
2326            if (g_server_depth == 8)
2327            {
2328                    bitmap_pad = 8;
2329            }
2330            else
2331            {
2332                    bitmap_pad = g_bpp;
2333    
2334          tdata = (owncolmap ? data : translate_image(width, height, data));                  if (g_bpp == 24)
2335          bitmap = XCreatePixmap(display, wnd, width, height, depth);                          bitmap_pad = 32;
2336          image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width,          }
2337                               height, 8, 0);  
2338            tdata = (g_owncolmap ? data : translate_image(width, height, data));
2339            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2340            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2341                                 (char *) tdata, width, height, bitmap_pad, 0);
2342    
2343          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);
2344    
2345          XFree(image);          XFree(image);
2346          if (!owncolmap)          if (tdata != data)
2347                  xfree(tdata);                  xfree(tdata);
2348          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2349  }  }
2350    
2351  void  void
2352  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)  
2353  {  {
2354          XImage *image;          XImage *image;
2355          uint8 *tdata;          uint8 *tdata;
2356            int bitmap_pad;
2357    
2358            if (g_server_depth == 8)
2359            {
2360                    bitmap_pad = 8;
2361            }
2362            else
2363            {
2364                    bitmap_pad = g_bpp;
2365    
2366                    if (g_bpp == 24)
2367                            bitmap_pad = 32;
2368            }
2369    
2370          tdata = (owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2371          image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2372                               height, 8, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2373    
2374          if (ownbackstore)          if (g_ownbackstore)
2375          {          {
2376                  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);
2377                  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);
2378                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2379                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2380                                             x - sw->xoffset, y - sw->yoffset));
2381          }          }
2382          else          else
2383          {          {
2384                  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);
2385                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2386                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2387                                             x - sw->xoffset, y - sw->yoffset));
2388          }          }
2389    
2390          XFree(image);          XFree(image);
2391          if (!owncolmap)          if (tdata != data)
2392                  xfree(tdata);                  xfree(tdata);
2393  }  }
2394    
2395  void  void
2396  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(HBITMAP bmp)
2397  {  {
2398          XFreePixmap(display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2399  }  }
2400    
2401  HGLYPH  HGLYPH
# Line 638  ui_create_glyph(int width, int height, u Line 2404  ui_create_glyph(int width, int height, u
2404          XImage *image;          XImage *image;
2405          Pixmap bitmap;          Pixmap bitmap;
2406          int scanline;          int scanline;
         GC gc;  
2407    
2408          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2409    
2410          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2411          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2412                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2413    
2414          image = XCreateImage(display, visual, 1, ZPixmap, 0, data, width,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2415                               height, 8, scanline);                               width, height, 8, scanline);
2416          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2417          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2418          XInitImage(image);          XInitImage(image);
2419    
2420          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);
2421    
2422          XFree(image);          XFree(image);
         XFreeGC(display, gc);  
2423          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2424  }  }
2425    
2426  void  void
2427  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
2428  {  {
2429          XFreePixmap(display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2430  }  }
2431    
2432  HCURSOR  HCURSOR
# Line 680  ui_create_cursor(unsigned int x, unsigne Line 2445  ui_create_cursor(unsigned int x, unsigne
2445          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2446          offset = scanline * height;          offset = scanline * height;
2447    
2448          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
2449          memset(cursor, 0, offset);          memset(cursor, 0, offset);
2450    
2451          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
2452          memset(mask, 0, offset);          memset(mask, 0, offset);
2453    
2454          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 725  ui_create_cursor(unsigned int x, unsigne Line 2490  ui_create_cursor(unsigned int x, unsigne
2490          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2491    
2492          xcursor =          xcursor =
2493                  XCreatePixmapCursor(display, (Pixmap) cursorglyph,                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2494                                      (Pixmap) maskglyph, &fg, &bg, x, y);                                      (Pixmap) maskglyph, &fg, &bg, x, y);
2495    
2496          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
# Line 738  ui_create_cursor(unsigned int x, unsigne Line 2503  ui_create_cursor(unsigned int x, unsigne
2503  void  void
2504  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2505  {  {
2506          XDefineCursor(display, wnd, (Cursor) cursor);          g_current_cursor = (Cursor) cursor;
2507            XDefineCursor(g_display, g_wnd, g_current_cursor);
2508            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2509  }  }
2510    
2511  void  void
2512  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(HCURSOR cursor)
2513  {  {
2514          XFreeCursor(display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2515    }
2516    
2517    void
2518    ui_set_null_cursor(void)
2519    {
2520            ui_set_cursor(g_null_cursor);
2521  }  }
2522    
2523  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 753  ui_destroy_cursor(HCURSOR cursor) Line 2526  ui_destroy_cursor(HCURSOR cursor)
2526                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2527                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2528    
2529    
2530  HCOLOURMAP  HCOLOURMAP
2531  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2532  {  {
2533          COLOURENTRY *entry;          COLOURENTRY *entry;
2534          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2535            if (!g_owncolmap)
2536            {
2537                    uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2538                    XColor xentry;
2539                    XColor xc_cache[256];
2540                    uint32 colour;
2541                    int colLookup = 256;
2542                    for (i = 0; i < ncolours; i++)
2543                    {
2544                            entry = &colours->colours[i];
2545                            MAKE_XCOLOR(&xentry, entry);
2546    
2547                            if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2548                            {
2549                                    /* Allocation failed, find closest match. */
2550                                    int j = 256;
2551                                    int nMinDist = 3 * 256 * 256;
2552                                    long nDist = nMinDist;
2553    
2554          if (owncolmap)                                  /* only get the colors once */
2555                                    while (colLookup--)
2556                                    {
2557                                            xc_cache[colLookup].pixel = colLookup;
2558                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2559                                                    xc_cache[colLookup].blue = 0;
2560                                            xc_cache[colLookup].flags = 0;
2561                                            XQueryColor(g_display,
2562                                                        DefaultColormap(g_display,
2563                                                                        DefaultScreen(g_display)),
2564                                                        &xc_cache[colLookup]);
2565                                    }
2566                                    colLookup = 0;
2567    
2568                                    /* approximate the pixel */
2569                                    while (j--)
2570                                    {
2571                                            if (xc_cache[j].flags)
2572                                            {
2573                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2574                                                             (long) (xentry.red >> 8)) *
2575                                                            ((long) (xc_cache[j].red >> 8) -
2576                                                             (long) (xentry.red >> 8)) +
2577                                                            ((long) (xc_cache[j].green >> 8) -
2578                                                             (long) (xentry.green >> 8)) *
2579                                                            ((long) (xc_cache[j].green >> 8) -
2580                                                             (long) (xentry.green >> 8)) +
2581                                                            ((long) (xc_cache[j].blue >> 8) -
2582                                                             (long) (xentry.blue >> 8)) *
2583                                                            ((long) (xc_cache[j].blue >> 8) -
2584                                                             (long) (xentry.blue >> 8));
2585                                            }
2586                                            if (nDist < nMinDist)
2587                                            {
2588                                                    nMinDist = nDist;
2589                                                    xentry.pixel = j;
2590                                            }
2591                                    }
2592                            }
2593                            colour = xentry.pixel;
2594    
2595                            /* update our cache */
2596                            if (xentry.pixel < 256)
2597                            {
2598                                    xc_cache[xentry.pixel].red = xentry.red;
2599                                    xc_cache[xentry.pixel].green = xentry.green;
2600                                    xc_cache[xentry.pixel].blue = xentry.blue;
2601    
2602                            }
2603    
2604                            map[i] = colour;
2605                    }
2606                    return map;
2607            }
2608            else
2609          {          {
2610                  XColor *xcolours, *xentry;                  XColor *xcolours, *xentry;
2611                  Colormap map;                  Colormap map;
2612    
2613                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2614                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2615                  {                  {
2616                          entry = &colours->colours[i];                          entry = &colours->colours[i];
# Line 773  ui_create_colourmap(COLOURMAP * colours) Line 2619  ui_create_colourmap(COLOURMAP * colours)
2619                          MAKE_XCOLOR(xentry, entry);                          MAKE_XCOLOR(xentry, entry);
2620                  }                  }
2621    
2622                  map = XCreateColormap(display, wnd, visual, AllocAll);                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2623                  XStoreColors(display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2624    
2625                  xfree(xcolours);                  xfree(xcolours);
2626                  return (HCOLOURMAP) map;                  return (HCOLOURMAP) map;
2627          }          }
         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;  
         }  
2628  }  }
2629    
2630  void  void
2631  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(HCOLOURMAP map)
2632  {  {
2633          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap) map);  
         else  
2634                  xfree(map);                  xfree(map);
2635            else
2636                    XFreeColormap(g_display, (Colormap) map);
2637  }  }
2638    
2639  void  void
2640  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(HCOLOURMAP map)
2641  {  {
2642          if (owncolmap)          if (!g_owncolmap)
2643                  XSetWindowColormap(display, wnd, (Colormap) map);          {
2644                    if (g_colmap)
2645                            xfree(g_colmap);
2646    
2647                    g_colmap = (uint32 *) map;
2648            }
2649          else          else
2650                  colmap = map;          {
2651                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2652                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2653            }
2654  }  }
2655    
2656  void  void
2657  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2658  {  {
2659          XRectangle rect;          g_clip_rectangle.x = x;
2660            g_clip_rectangle.y = y;
2661          rect.x = x;          g_clip_rectangle.width = cx;
2662          rect.y = y;          g_clip_rectangle.height = cy;
2663          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);  
2664  }  }
2665    
2666  void  void
2667  ui_reset_clip()  ui_reset_clip(void)
2668  {  {
2669          XRectangle rect;          g_clip_rectangle.x = 0;
2670            g_clip_rectangle.y = 0;
2671          rect.x = 0;          g_clip_rectangle.width = g_width;
2672          rect.y = 0;          g_clip_rectangle.height = g_height;
2673          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);  
2674  }  }
2675    
2676  void  void
2677  ui_bell()  ui_bell(void)
2678  {  {
2679          XBell(display, 0);          XBell(g_display, 0);
2680  }  }
2681    
2682  void  void
# Line 860  ui_destblt(uint8 opcode, Line 2688  ui_destblt(uint8 opcode,
2688          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2689  }  }
2690    
2691    static uint8 hatch_patterns[] = {
2692            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2693            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2694            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2695            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2696            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2697            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2698    };
2699    
2700  void  void
2701  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2702            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
# Line 874  ui_patblt(uint8 opcode, Line 2711  ui_patblt(uint8 opcode,
2711          {          {
2712                  case 0: /* Solid */                  case 0: /* Solid */
2713                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2714                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2715                            break;
2716    
2717                    case 2: /* Hatch */
2718                            fill = (Pixmap) ui_create_glyph(8, 8,
2719                                                            hatch_patterns + brush->pattern[0] * 8);
2720                            SET_FOREGROUND(fgcolour);
2721                            SET_BACKGROUND(bgcolour);
2722                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2723                            XSetStipple(g_display, g_gc, fill);
2724                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2725                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2726                            XSetFillStyle(g_display, g_gc, FillSolid);
2727                            XSetTSOrigin(g_display, g_gc, 0, 0);
2728                            ui_destroy_glyph((HGLYPH) fill);
2729                          break;                          break;
2730    
2731                  case 3: /* Pattern */                  case 3: /* Pattern */
2732                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2733                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2734                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2735                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2736                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2737                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2738                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2739                          XSetTSOrigin(display, gc, brush->xorigin,                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2740                                       brush->yorigin);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2741                            XSetFillStyle(g_display, g_gc, FillSolid);
2742                          FILL_RECTANGLE(x, y, cx, cy);                          XSetTSOrigin(g_display, g_gc, 0, 0);
   
                         XSetFillStyle(display, gc, FillSolid);  
2743                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
2744                          break;                          break;
2745    
# Line 900  ui_patblt(uint8 opcode, Line 2748  ui_patblt(uint8 opcode,
2748          }          }
2749    
2750          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2751    
2752            if (g_ownbackstore)
2753                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2754            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2755                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2756                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2757  }  }
2758    
2759  void  void
# Line 908  ui_screenblt(uint8 opcode, Line 2762  ui_screenblt(uint8 opcode,
2762               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2763  {  {
2764          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2765          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2766          if (ownbackstore)          {
2767                  XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2768                            cy, x, y);                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2769                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2770            }
2771            else
2772            {
2773                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2774            }
2775    
2776            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2777                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2778                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2779    
2780          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2781  }  }
2782    
# Line 921  ui_memblt(uint8 opcode, Line 2786  ui_memblt(uint8 opcode,
2786            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ HBITMAP src, int srcx, int srcy)
2787  {  {
2788          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2789          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);
2790          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2791                  XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
2792                            cx, cy, x, y);                                   srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2793            if (g_ownbackstore)
2794                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2795          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2796  }  }
2797    
# Line 941  ui_triblt(uint8 opcode, Line 2808  ui_triblt(uint8 opcode,
2808          {          {
2809                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
2810                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2811                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2812                          break;                          break;
2813    
2814                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2815                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2816                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2817                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2818                          break;                          break;
2819    
2820                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
2821                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2822                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2823                          break;                          break;
2824    
2825                  default:                  default:
# Line 972  ui_line(uint8 opcode, Line 2835  ui_line(uint8 opcode,
2835  {  {
2836          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2837          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2838          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2839          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2840                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
2841                                                endx - sw->xoffset, endy - sw->yoffset));
2842            if (g_ownbackstore)
2843                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2844          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2845  }  }
2846    
# Line 988  ui_rect( Line 2854  ui_rect(
2854  }  }
2855    
2856  void  void
2857    ui_polygon(uint8 opcode,
2858               /* mode */ uint8 fillmode,
2859               /* dest */ POINT * point, int npoints,
2860               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2861    {
2862            uint8 style, i, ipattern[8];
2863            Pixmap fill;
2864    
2865            SET_FUNCTION(opcode);
2866    
2867            switch (fillmode)
2868            {
2869                    case ALTERNATE:
2870                            XSetFillRule(g_display, g_gc, EvenOddRule);
2871                            break;
2872                    case WINDING:
2873                            XSetFillRule(g_display, g_gc, WindingRule);
2874                            break;
2875                    default:
2876                            unimpl("fill mode %d\n", fillmode);
2877            }
2878    
2879            if (brush)
2880                    style = brush->style;
2881            else
2882                    style = 0;
2883    
2884            switch (style)
2885            {
2886                    case 0: /* Solid */
2887                            SET_FOREGROUND(fgcolour);
2888                            FILL_POLYGON((XPoint *) point, npoints);
2889                            break;
2890    
2891                    case 2: /* Hatch */
2892                            fill = (Pixmap) ui_create_glyph(8, 8,
2893                                                            hatch_patterns + brush->pattern[0] * 8);
2894                            SET_FOREGROUND(fgcolour);
2895                            SET_BACKGROUND(bgcolour);
2896                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2897                            XSetStipple(g_display, g_gc, fill);
2898                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2899                            FILL_POLYGON((XPoint *) point, npoints);
2900                            XSetFillStyle(g_display, g_gc, FillSolid);
2901                            XSetTSOrigin(g_display, g_gc, 0, 0);
2902                            ui_destroy_glyph((HGLYPH) fill);
2903                            break;
2904    
2905                    case 3: /* Pattern */
2906                            for (i = 0; i != 8; i++)
2907                                    ipattern[7 - i] = brush->pattern[i];
2908                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2909                            SET_FOREGROUND(bgcolour);
2910                            SET_BACKGROUND(fgcolour);
2911                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2912                            XSetStipple(g_display, g_gc, fill);
2913                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2914                            FILL_POLYGON((XPoint *) point, npoints);
2915                            XSetFillStyle(g_display, g_gc, FillSolid);
2916                            XSetTSOrigin(g_display, g_gc, 0, 0);
2917                            ui_destroy_glyph((HGLYPH) fill);
2918                            break;
2919    
2920                    default:
2921                            unimpl("brush %d\n", brush->style);
2922            }
2923    
2924            RESET_FUNCTION(opcode);
2925    }
2926    
2927    void
2928    ui_polyline(uint8 opcode,
2929                /* dest */ POINT * points, int npoints,
2930                /* pen */ PEN * pen)
2931    {
2932            /* TODO: set join style */
2933            SET_FUNCTION(opcode);
2934            SET_FOREGROUND(pen->colour);
2935            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2936            if (g_ownbackstore)
2937                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2938                               CoordModePrevious);
2939    
2940            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2941                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2942    
2943            RESET_FUNCTION(opcode);
2944    }
2945    
2946    void
2947    ui_ellipse(uint8 opcode,
2948               /* mode */ uint8 fillmode,
2949               /* dest */ int x, int y, int cx, int cy,
2950               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2951    {
2952            uint8 style, i, ipattern[8];
2953            Pixmap fill;
2954    
2955            SET_FUNCTION(opcode);
2956    
2957            if (brush)
2958                    style = brush->style;
2959            else
2960                    style = 0;
2961    
2962            switch (style)
2963            {
2964                    case 0: /* Solid */
2965                            SET_FOREGROUND(fgcolour);
2966                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2967                            break;
2968    
2969                    case 2: /* Hatch */
2970                            fill = (Pixmap) ui_create_glyph(8, 8,
2971                                                            hatch_patterns + brush->pattern[0] * 8);
2972                            SET_FOREGROUND(fgcolour);
2973                            SET_BACKGROUND(bgcolour);
2974                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2975                            XSetStipple(g_display, g_gc, fill);
2976                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2977                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2978                            XSetFillStyle(g_display, g_gc, FillSolid);
2979                            XSetTSOrigin(g_display, g_gc, 0, 0);
2980                            ui_destroy_glyph((HGLYPH) fill);
2981                            break;
2982    
2983                    case 3: /* Pattern */
2984                            for (i = 0; i != 8; i++)
2985                                    ipattern[7 - i] = brush->pattern[i];
2986                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2987                            SET_FOREGROUND(bgcolour);
2988                            SET_BACKGROUND(fgcolour);
2989                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2990                            XSetStipple(g_display, g_gc, fill);
2991                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2992                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2993                            XSetFillStyle(g_display, g_gc, FillSolid);
2994                            XSetTSOrigin(g_display, g_gc, 0, 0);
2995                            ui_destroy_glyph((HGLYPH) fill);
2996                            break;
2997    
2998                    default:
2999                            unimpl("brush %d\n", brush->style);
3000            }
3001    
3002            RESET_FUNCTION(opcode);
3003    }
3004    
3005    /* warning, this function only draws on wnd or backstore, not both */
3006    void
3007  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3008                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3009                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ HGLYPH glyph, int srcx, int srcy,
# Line 996  ui_draw_glyph(int mixmode, Line 3012  ui_draw_glyph(int mixmode,
3012          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
3013          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
3014    
3015          XSetFillStyle(display, gc,          XSetFillStyle(g_display, g_gc,
3016                        (mixmode ==                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3017                         MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
3018          XSetStipple(display, gc, (Pixmap) glyph);          XSetTSOrigin(g_display, g_gc, x, y);
         XSetTSOrigin(display, gc, x, y);  
3019    
3020          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3021    
3022          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
3023  }  }
3024    
3025  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
3026  {\  {\
3027    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3028    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3029      {\
3030        xyoffset = ttext[++idx];\
3031        if ((xyoffset & 0x80))\
3032      {\      {\
3033        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3034        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);\  
         }\  
3035        else\        else\
3036          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3037            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3038      }\      }\
3039    if (glyph != NULL)\      else\
3040      {\      {\
3041        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3042                       y + (short) glyph->baseline,\          y += xyoffset;\
3043                       glyph->width, glyph->height,\        else\
3044                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3045      }\      }\
3046      }\
3047      if (glyph != NULL)\
3048      {\
3049        x1 = x + glyph->offset;\
3050        y1 = y + glyph->baseline;\
3051        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3052        XSetTSOrigin(g_display, g_gc, x1, y1);\
3053        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3054        if (flags & TEXT2_IMPLICIT_X)\
3055          x += glyph->width;\
3056      }\
3057  }  }
3058    
3059  void  void
3060  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,
3061               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3062               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3063               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3064  {  {
3065            /* TODO: use brush appropriately */
3066    
3067          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3068          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3069          DATABLOB *entry;          DATABLOB *entry;
3070    
3071          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3072    
3073            /* Sometimes, the boxcx value is something really large, like
3074               32691. This makes XCopyArea fail with Xvnc. The code below
3075               is a quick fix. */
3076            if (boxx + boxcx > g_width)
3077                    boxcx = g_width - boxx;
3078    
3079          if (boxcx > 1)          if (boxcx > 1)
3080          {          {
3081                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3082          }          }
3083          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
3084          {          {
3085                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3086          }          }
3087    
3088            SET_FOREGROUND(fgcolour);
3089            SET_BACKGROUND(bgcolour);
3090            XSetFillStyle(g_display, g_gc, FillStippled);
3091    
3092          /* Paint text, character by character */          /* Paint text, character by character */
3093          for (i = 0; i < length;)          for (i = 0; i < length;)
3094          {          {
3095                  switch (text[i])                  switch (text[i])
3096                  {                  {
3097                          case 0xff:                          case 0xff:
3098                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3099                                          cache_put_text(text[i + 1], text,                                  if (i + 3 > length)
                                                        text[i + 2]);  
                                 else  
3100                                  {                                  {
3101                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3102                                            for (j = 0; j < length; j++)
3103                                                    fprintf(stderr, "%02x ", text[j]);
3104                                            fprintf(stderr, "\n");
3105                                            i = length = 0;
3106                                          break;                                          break;
3107                                  }                                  }
3108                                    cache_put_text(text[i + 1], text, text[i + 2]);
3109                                    i += 3;
3110                                    length -= i;
3111                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3112                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3113                                  i = 0;                                  i = 0;
3114                                  break;                                  break;
3115    
3116                          case 0xfe:                          case 0xfe:
3117                                    /* At least one byte needs to follow */
3118                                    if (i + 2 > length)
3119                                    {
3120                                            warning("Skipping short 0xfe command:");
3121                                            for (j = 0; j < length; j++)
3122                                                    fprintf(stderr, "%02x ", text[j]);
3123                                            fprintf(stderr, "\n");
3124                                            i = length = 0;
3125                                            break;
3126                                    }
3127                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3128                                  if (entry != NULL)                                  if (entry->data != NULL)
3129                                  {                                  {
3130                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3131                                               0)                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
                                             && (!(flags & TEXT2_IMPLICIT_X)))  
3132                                          {                                          {
3133                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3134                                                          y += text[i + 2];                                                          y += text[i + 2];
3135                                                  else                                                  else
3136                                                          x += text[i + 2];                                                          x += text[i + 2];
3137                                          }                                          }
                                         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;  
3138                                          for (j = 0; j < entry->size; j++)                                          for (j = 0; j < entry->size; j++)
3139                                                  DO_GLYPH(((uint8 *) (entry->                                                  DO_GLYPH(((uint8 *) (entry->data)), j);
                                                                      data)),  
                                                          j);  
3140                                  }                                  }
3141                                    if (i + 2 < length)
3142                                            i += 3;
3143                                    else
3144                                            i += 2;
3145                                    length -= i;
3146                                    /* this will move pointer from start to first character after FE command */
3147                                    text = &(text[i]);
3148                                    i = 0;
3149                                  break;                                  break;
3150    
3151                          default:                          default:
# Line 1115  ui_draw_text(uint8 font, uint8 flags, in Line 3155  ui_draw_text(uint8 font, uint8 flags, in
3155                  }                  }
3156          }          }
3157    
3158            XSetFillStyle(g_display, g_gc, FillSolid);
3159    
3160            if (g_ownbackstore)
3161            {
3162                    if (boxcx > 1)
3163                    {
3164                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3165                                      boxy, boxcx, boxcy, boxx, boxy);
3166                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3167                                                    (g_display, g_backstore, sw->wnd, g_gc,
3168                                                     boxx, boxy,
3169                                                     boxcx, boxcy,
3170                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3171                    }
3172                    else
3173                    {
3174                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3175                                      clipy, clipcx, clipcy, clipx, clipy);
3176                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3177                                                    (g_display, g_backstore, sw->wnd, g_gc,
3178                                                     clipx, clipy,
3179                                                     clipcx, clipcy, clipx - sw->xoffset,
3180                                                     clipy - sw->yoffset));
3181                    }
3182            }
3183  }  }
3184    
3185  void  void
# Line 1124  ui_desktop_save(uint32 offset, int x, in Line 3188  ui_desktop_save(uint32 offset, int x, in
3188          Pixmap pix;          Pixmap pix;
3189          XImage *image;          XImage *image;
3190    
3191          if (ownbackstore)          if (g_ownbackstore)
3192          {          {
3193                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
                                   ZPixmap);  
3194          }          }
3195          else          else
3196          {          {
3197                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3198                  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);
3199                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3200                                    ZPixmap);                  XFreePixmap(g_display, pix);
                 XFreePixmap(display, pix);  
3201          }          }
3202    
3203          offset *= bpp / 8;          offset *= g_bpp / 8;
3204          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);  
3205    
3206          XDestroyImage(image);          XDestroyImage(image);
3207  }  }
# Line 1151  ui_desktop_restore(uint32 offset, int x, Line 3212  ui_desktop_restore(uint32 offset, int x,
3212          XImage *image;          XImage *image;
3213          uint8 *data;          uint8 *data;
3214    
3215          offset *= bpp / 8;          offset *= g_bpp / 8;
3216          data = cache_get_desktop(offset, cx, cy, bpp / 8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3217          if (data == NULL)          if (data == NULL)
3218                  return;                  return;
3219    
3220          image = XCreateImage(display, visual, depth, ZPixmap, 0, data, cx, cy,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3221                               BitmapPad(display), cx * bpp / 8);                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
3222    
3223          if (ownbackstore)          if (g_ownbackstore)
3224          {          {
3225                  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);
3226                  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);
3227                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3228                                            (g_display, g_backstore, sw->wnd, g_gc,
3229                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3230          }          }
3231          else          else
3232          {          {
3233                  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);
3234                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3235                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3236                                             x - sw->xoffset, y - sw->yoffset));
3237          }          }
3238    
3239          XFree(image);          XFree(image);
3240  }  }
3241    
3242    /* these do nothing here but are used in uiports */
3243    void
3244    ui_begin_update(void)
3245    {
3246    }
3247    
3248    void
3249    ui_end_update(void)
3250    {
3251    }
3252    
3253    
3254    void
3255    ui_seamless_begin(BOOL hidden)
3256    {
3257            if (!g_seamless_rdp)
3258                    return;
3259    
3260            if (g_seamless_started)
3261                    return;
3262    
3263            g_seamless_started = True;
3264            g_seamless_hidden = hidden;
3265    
3266            if (!hidden)
3267                    ui_seamless_toggle();
3268    }
3269    
3270    
3271    void
3272    ui_seamless_hide_desktop()
3273    {
3274            if (!g_seamless_rdp)
3275                    return;
3276    
3277            if (!g_seamless_started)
3278                    return;
3279    
3280            if (g_seamless_active)
3281                    ui_seamless_toggle();
3282    
3283            g_seamless_hidden = True;
3284    }
3285    
3286    
3287    void
3288    ui_seamless_unhide_desktop()
3289    {
3290            if (!g_seamless_rdp)
3291                    return;
3292    
3293            if (!g_seamless_started)
3294                    return;
3295    
3296            g_seamless_hidden = False;
3297    
3298            ui_seamless_toggle();
3299    }
3300    
3301    
3302    void
3303    ui_seamless_toggle()
3304    {
3305            if (!g_seamless_rdp)
3306                    return;
3307    
3308            if (!g_seamless_started)
3309                    return;
3310    
3311            if (g_seamless_hidden)
3312                    return;
3313    
3314            if (g_seamless_active)
3315            {
3316                    /* Deactivate */
3317                    while (g_seamless_windows)
3318                    {
3319                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3320                            sw_remove_window(g_seamless_windows);
3321                    }
3322                    XMapWindow(g_display, g_wnd);
3323            }
3324            else
3325            {
3326                    /* Activate */
3327                    XUnmapWindow(g_display, g_wnd);
3328                    seamless_send_sync();
3329            }
3330    
3331            g_seamless_active = !g_seamless_active;
3332    }
3333    
3334    
3335    void
3336    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3337                              unsigned long flags)
3338    {
3339            Window wnd;
3340            XSetWindowAttributes attribs;
3341            XClassHint *classhints;
3342            XSizeHints *sizehints;
3343            XWMHints *wmhints;
3344            long input_mask;
3345            seamless_window *sw, *sw_parent;
3346    
3347            if (!g_seamless_active)
3348                    return;
3349    
3350            /* Ignore CREATEs for existing windows */
3351            sw = sw_get_window_by_id(id);
3352            if (sw)
3353                    return;
3354    
3355            get_window_attribs(&attribs);
3356            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3357                                InputOutput, g_visual,
3358                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3359    
3360            XStoreName(g_display, wnd, "SeamlessRDP");
3361            ewmh_set_wm_name(wnd, "SeamlessRDP");
3362    
3363            mwm_hide_decorations(wnd);
3364    
3365            classhints = XAllocClassHint();
3366            if (classhints != NULL)
3367            {
3368                    classhints->res_name = "rdesktop";
3369                    classhints->res_class = "SeamlessRDP";
3370                    XSetClassHint(g_display, wnd, classhints);
3371                    XFree(classhints);
3372            }
3373    
3374            /* WM_NORMAL_HINTS */
3375            sizehints = XAllocSizeHints();
3376            if (sizehints != NULL)
3377            {
3378                    sizehints->flags = USPosition;
3379                    XSetWMNormalHints(g_display, wnd, sizehints);
3380                    XFree(sizehints);
3381            }
3382    
3383            /* Parent-less transient windows */
3384            if (parent == 0xFFFFFFFF)
3385            {
3386                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3387                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3388                       using some other hints. */
3389                    ewmh_set_window_popup(wnd);
3390            }
3391            /* Normal transient windows */
3392            else if (parent != 0x00000000)
3393            {
3394                    sw_parent = sw_get_window_by_id(parent);
3395                    if (sw_parent)
3396                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3397                    else
3398                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3399            }
3400    
3401            if (flags & SEAMLESSRDP_CREATE_MODAL)
3402            {
3403                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3404                       somewhat at least */
3405                    if (parent == 0x00000000)
3406                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3407                    ewmh_set_window_modal(wnd);
3408            }
3409    
3410            /* FIXME: Support for Input Context:s */
3411    
3412            get_input_mask(&input_mask);
3413            input_mask |= PropertyChangeMask;
3414    
3415            XSelectInput(g_display, wnd, input_mask);
3416    
3417            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3418               seamless window, we could try to close the window on the
3419               serverside, instead of terminating rdesktop */
3420            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3421    
3422            sw = xmalloc(sizeof(seamless_window));
3423            sw->wnd = wnd;
3424            sw->id = id;
3425            sw->behind = 0;
3426            sw->group = sw_find_group(group, False);
3427            sw->group->refcnt++;
3428            sw->xoffset = 0;
3429            sw->yoffset = 0;
3430            sw->width = 0;
3431            sw->height = 0;
3432            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3433            sw->desktop = 0;
3434            sw->position_timer = xmalloc(sizeof(struct timeval));
3435            timerclear(sw->position_timer);
3436    
3437            sw->outstanding_position = False;
3438            sw->outpos_serial = 0;
3439            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3440            sw->outpos_width = sw->outpos_height = 0;
3441    
3442            sw->next = g_seamless_windows;
3443            g_seamless_windows = sw;
3444    
3445            /* WM_HINTS */
3446            wmhints = XAllocWMHints();
3447            if (wmhints)
3448            {
3449                    wmhints->flags = WindowGroupHint;
3450                    wmhints->window_group = sw->group->wnd;
3451                    XSetWMHints(g_display, sw->wnd, wmhints);
3452                    XFree(wmhints);
3453            }
3454    }
3455    
3456    
3457    void
3458    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3459    {
3460            seamless_window *sw;
3461    
3462            if (!g_seamless_active)
3463                    return;
3464    
3465            sw = sw_get_window_by_id(id);
3466            if (!sw)
3467            {
3468                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3469                    return;
3470            }
3471    
3472            XDestroyWindow(g_display, sw->wnd);
3473            sw_remove_window(sw);
3474    }
3475    
3476    
3477    void
3478    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3479    {
3480            seamless_window *sw, *sw_next;
3481    
3482            if (!g_seamless_active)
3483                    return;
3484    
3485            for (sw = g_seamless_windows; sw; sw = sw_next)
3486            {
3487                    sw_next = sw->next;
3488    
3489                    if (sw->group->id == id)
3490                    {
3491                            XDestroyWindow(g_display, sw->wnd);
3492                            sw_remove_window(sw);
3493                    }
3494            }
3495    }
3496    
3497    
3498    void
3499    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3500    {
3501            seamless_window *sw;
3502    
3503            if (!g_seamless_active)
3504                    return;
3505    
3506            sw = sw_get_window_by_id(id);
3507            if (!sw)
3508            {
3509                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3510                    return;
3511            }
3512    
3513            /* We ignore server updates until it has handled our request. */
3514            if (sw->outstanding_position)
3515                    return;
3516    
3517            if (!width || !height)
3518                    /* X11 windows must be at least 1x1 */
3519                    return;
3520    
3521            sw->xoffset = x;
3522            sw->yoffset = y;
3523            sw->width = width;
3524            sw->height = height;
3525    
3526            /* If we move the window in a maximized state, then KDE won't
3527               accept restoration */
3528            switch (sw->state)
3529            {
3530                    case SEAMLESSRDP_MINIMIZED:
3531                    case SEAMLESSRDP_MAXIMIZED:
3532                            return;
3533            }
3534    
3535            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3536            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3537    }
3538    
3539    
3540    void
3541    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3542    {
3543            seamless_window *sw;
3544    
3545            if (!g_seamless_active)
3546                    return;
3547    
3548            sw = sw_get_window_by_id(id);
3549            if (!sw)
3550            {
3551                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3552                    return;
3553            }
3554    
3555            if (behind)
3556            {
3557                    seamless_window *sw_behind;
3558                    Window wnds[2];
3559    
3560                    sw_behind = sw_get_window_by_id(behind);
3561                    if (!sw_behind)
3562                    {
3563                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3564                                    behind);
3565                            return;
3566                    }
3567    
3568                    wnds[1] = sw_behind->wnd;
3569                    wnds[0] = sw->wnd;
3570    
3571                    XRestackWindows(g_display, wnds, 2);
3572            }
3573            else
3574            {
3575                    XRaiseWindow(g_display, sw->wnd);
3576            }
3577    
3578            sw_restack_window(sw, behind);
3579    }
3580    
3581    
3582    void
3583    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3584    {
3585            seamless_window *sw;
3586    
3587            if (!g_seamless_active)
3588                    return;
3589    
3590            sw = sw_get_window_by_id(id);
3591            if (!sw)
3592            {
3593                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3594                    return;
3595            }
3596    
3597            /* FIXME: Might want to convert the name for non-EWMH WMs */
3598            XStoreName(g_display, sw->wnd, title);
3599            ewmh_set_wm_name(sw->wnd, title);
3600    }
3601    
3602    
3603    void
3604    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3605    {
3606            seamless_window *sw;
3607    
3608            if (!g_seamless_active)
3609                    return;
3610    
3611            sw = sw_get_window_by_id(id);
3612            if (!sw)
3613            {
3614                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3615                    return;
3616            }
3617    
3618            switch (state)
3619            {
3620                    case SEAMLESSRDP_NORMAL:
3621                    case SEAMLESSRDP_MAXIMIZED:
3622                            ewmh_change_state(sw->wnd, state);
3623                            XMapWindow(g_display, sw->wnd);
3624                            break;
3625                    case SEAMLESSRDP_MINIMIZED:
3626                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3627                               the Window Manager should probably just ignore the request, since
3628                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3629                               such as minimization, rather than an independent state." Besides,
3630                               XIconifyWindow is easier. */
3631                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3632                            {
3633                                    XWMHints *hints;
3634                                    hints = XGetWMHints(g_display, sw->wnd);
3635                                    if (hints)
3636                                    {
3637                                            hints->flags |= StateHint;
3638                                            hints->initial_state = IconicState;
3639                                            XSetWMHints(g_display, sw->wnd, hints);
3640                                            XFree(hints);
3641                                    }
3642                                    XMapWindow(g_display, sw->wnd);
3643                            }
3644                            else
3645                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3646                            break;
3647                    default:
3648                            warning("SeamlessRDP: Invalid state %d\n", state);
3649                            break;
3650            }
3651    
3652            sw->state = state;
3653    }
3654    
3655    
3656    void
3657    ui_seamless_syncbegin(unsigned long flags)
3658    {
3659            if (!g_seamless_active)
3660                    return;
3661    
3662            /* Destroy all seamless windows */
3663            while (g_seamless_windows)
3664            {
3665                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3666                    sw_remove_window(g_seamless_windows);
3667            }
3668    }
3669    
3670    
3671    void
3672    ui_seamless_ack(unsigned int serial)
3673    {
3674            seamless_window *sw;
3675            for (sw = g_seamless_windows; sw; sw = sw->next)
3676            {
3677                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3678                    {
3679                            sw->xoffset = sw->outpos_xoffset;
3680                            sw->yoffset = sw->outpos_yoffset;
3681                            sw->width = sw->outpos_width;
3682                            sw->height = sw->outpos_height;
3683                            sw->outstanding_position = False;
3684    
3685                            /* Do a complete redraw of the window as part of the
3686                               completion of the move. This is to remove any
3687                               artifacts caused by our lack of synchronization. */
3688                            XCopyArea(g_display, g_backstore,
3689                                      sw->wnd, g_gc,
3690                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3691    
3692                            break;
3693                    }
3694            }
3695    }

Legend:
Removed from v.70  
changed lines
  Added in v.1246

  ViewVC Help
Powered by ViewVC 1.1.26