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

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

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

Legend:
Removed from v.7  
changed lines
  Added in v.1407

  ViewVC Help
Powered by ViewVC 1.1.26