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

Legend:
Removed from v.25  
changed lines
  Added in v.1132

  ViewVC Help
Powered by ViewVC 1.1.26