/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/xwin.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26