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

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

  ViewVC Help
Powered by ViewVC 1.1.26