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

Legend:
Removed from v.16  
changed lines
  Added in v.1144

  ViewVC Help
Powered by ViewVC 1.1.26