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

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

  ViewVC Help
Powered by ViewVC 1.1.26