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

Legend:
Removed from v.190  
changed lines
  Added in v.1118

  ViewVC Help
Powered by ViewVC 1.1.26