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

Legend:
Removed from v.288  
changed lines
  Added in v.1403

  ViewVC Help
Powered by ViewVC 1.1.26