/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

Legend:
Removed from v.10  
changed lines
  Added in v.1155

  ViewVC Help
Powered by ViewVC 1.1.26