/[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 38 by matthewc, Thu Apr 4 12:04:33 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
8     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.     (at your option) any later version.
10      
11     This program is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.     GNU General Public License for more details.
15      
16     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# 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 char keymapname[16];  extern int g_width;
32  extern int keylayout;  extern int g_height;
33  extern int width;  extern int g_xpos;
34  extern int height;  extern int g_ypos;
35  extern BOOL sendmotion;  extern int g_pos;
36  extern BOOL fullscreen;  extern BOOL g_sendmotion;
37    extern BOOL g_fullscreen;
38  static Display *display;  extern BOOL g_grab_keyboard;
39  static int x_socket;  extern BOOL g_hide_decorations;
40  static Window wnd;  extern char g_title[];
41  static GC gc;  /* Color depth of the RDP session.
42  static Visual *visual;     As of RDP 5.1, it may be 8, 15, 16 or 24. */
43  static int depth;  extern int g_server_depth;
44  static int bpp;  extern int g_win_button_size;
45    
46    Display *g_display;
47    Time g_last_gesturetime;
48    static int g_x_socket;
49    static Screen *g_screen;
50    Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            int xoffset, yoffset;
58            int width, height;
59            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    #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
196    { \
197            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 DRAW_ELLIPSE(x,y,cx,cy,m)\
209    { \
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 */  /* colour maps */
229  static BOOL owncolmap;  extern BOOL g_owncolmap;
230  static Colormap xcolmap;  static Colormap g_xcolmap;
231  static uint32 white;  static uint32 *g_colmap = NULL;
232  static uint32 *colmap;  
233    #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
234  #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
235  #define SET_FOREGROUND(col)     XSetForeground(display, gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
 #define SET_BACKGROUND(col)     XSetBackground(display, gc, TRANSLATE(col));  
236    
237  static int rop2_map[] = {  static int rop2_map[] = {
238          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 83  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  ui_create_window(char *title)  get_key_state(unsigned int state, uint32 keysym)
1067    {
1068            int modifierpos, key, keysymMask = 0;
1069            int offset;
1070    
1071            KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1072    
1073            if (keycode == NoSymbol)
1074                    return False;
1075    
1076            for (modifierpos = 0; modifierpos < 8; modifierpos++)
1077            {
1078                    offset = g_mod_map->max_keypermod * modifierpos;
1079    
1080                    for (key = 0; key < g_mod_map->max_keypermod; key++)
1081                    {
1082                            if (g_mod_map->modifiermap[offset + key] == keycode)
1083                                    keysymMask |= 1 << modifierpos;
1084                    }
1085            }
1086    
1087            return (state & keysymMask) ? True : False;
1088    }
1089    
1090    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    /* 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    static BOOL
1114    select_visual()
1115  {  {
         XSetWindowAttributes attribs;  
         XClassHint *classhints;  
         XSizeHints *sizehints;  
         unsigned long input_mask;  
1116          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1117          Screen *screen;          int pixmap_formats_count, visuals_count;
1118          uint16 test;          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                    /* we use a colourmap, so the default visual should do */
1254                    g_owncolmap = True;
1255                    g_visual = vmatches[0].visual;
1256                    g_depth = vmatches[0].depth;
1257            }
1258    
1259          pfm = XListPixmapFormats(display, &i);          g_bpp = 0;
1260          if (pfm != NULL)          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)                          g_bpp = pf->bits_per_pixel;
1266                              && (pfm[i].bits_per_pixel > bpp))  
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          if (bpp < 8)  BOOL
1301    ui_init(void)
1302    {
1303            int screen_num;
1304    
1305            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          if (depth <= 8)          {
1313                  owncolmap = True;                  uint16 endianess_test = 1;
1314          else                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1315                  xcolmap = DefaultColormapOfScreen(screen);          }
1316    
1317            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1318            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          white = WhitePixelOfScreen(screen);          if (g_no_translate_image)
1327          attribs.background_pixel = BlackPixelOfScreen(screen);          {
1328          attribs.backing_store = DoesBackingStore(screen);                  DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1329            }
1330    
1331          if (attribs.backing_store == NotUseful)          if (g_server_depth > g_bpp)
1332                  ownbackstore = True;          {
1333                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1334                            g_server_depth, g_bpp);
1335            }
1336    
1337            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 (fullscreen)          if (!g_owncolmap)
1341          {          {
1342                  attribs.override_redirect = True;                  g_xcolmap =
1343                  width = WidthOfScreen(screen);                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1344                  height = HeightOfScreen(screen);                                          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          else  
1349            if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1350            {
1351                    warning("External BackingStore not available. Using internal.\n");
1352                    g_ownbackstore = True;
1353            }
1354    
1355            /*
1356             * 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();
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;
1408    }
1409    
1410    void
1411    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            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1434            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    static void
1442    get_input_mask(long *input_mask)
1443    {
1444            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1445                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1446    
1447            if (g_sendmotion)
1448                    *input_mask |= PointerMotionMask;
1449            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
1458    ui_create_window(void)
1459    {
1460            uint8 null_pointer_mask[1] = { 0x80 };
1461            uint8 null_pointer_data[24] = { 0x00 };
1462    
1463            XSetWindowAttributes attribs;
1464            XClassHint *classhints;
1465            XSizeHints *sizehints;
1466            int wndwidth, wndheight;
1467            long input_mask, ic_input_mask;
1468            XEvent xevent;
1469    
1470            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1471            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1472    
1473            /* Handle -x-y portion of geometry string */
1474            if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1475                    g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1476            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1477                    g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1478    
1479            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                  attribs.override_redirect = False;                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1489                    ui_reset_clip();
1490          }          }
1491    
1492          width = (width + 3) & ~3; /* make width a multiple of 32 bits */          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          wnd = XCreateWindow(display, RootWindowOfScreen(screen),                  /* clear to prevent rubbish being exposed at startup */
1500                              0, 0, width, height, 0, CopyFromParent,                  XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1501                              InputOutput, CopyFromParent,                  XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1502                              CWBackingStore | CWBackPixel | CWOverrideRedirect,          }
                             &attribs);  
1503    
1504          XStoreName(display, wnd, title);          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 276  ui_create_window(char *title) Line 1518  ui_create_window(char *title)
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          xkeymap_init(display);          if (g_embed_wnd)
1530            {
1531                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1532            }
1533    
1534          input_mask = KeyPressMask | KeyReleaseMask          get_input_mask(&input_mask);
                         | ButtonPressMask | ButtonReleaseMask  
                         | EnterWindowMask | LeaveWindowMask;  
1535    
1536          if (sendmotion)          if (g_IM != NULL)
1537                  input_mask |= PointerMotionMask;          {
1538                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1539                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1540    
1541                    if ((g_IC != NULL)
1542                        && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1543                            input_mask |= ic_input_mask;
1544            }
1545    
1546            XSelectInput(g_display, g_wnd, input_mask);
1547            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          if (ownbackstore)          g_focused = False;
1560                  input_mask |= ExposureMask;          g_mouse_in_wnd = False;
1561    
1562          XSelectInput(display, wnd, input_mask);          /* handle the WM_DELETE_WINDOW protocol */
1563          gc = XCreateGC(display, wnd, 0, NULL);          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          if (ownbackstore)          /* create invisible 1x1 cursor to be used as null cursor */
1568                  backstore = XCreatePixmap(display, wnd, width, height, depth);          if (g_null_cursor == NULL)
1569                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1570    
         XMapWindow(display, wnd);  
1571          return True;          return True;
1572  }  }
1573    
1574  void  void
1575  ui_destroy_window()  ui_resize_window()
1576  {  {
1577          if (ownbackstore)          XSizeHints *sizehints;
1578                  XFreePixmap(display, backstore);          Pixmap bs;
1579    
1580          XFreeGC(display, gc);          sizehints = XAllocSizeHints();
1581          XDestroyWindow(display, wnd);          if (sizehints)
1582          XCloseDisplay(display);          {
1583          display = NULL;                  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            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
1608    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;
1620    
1621            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 */
1628                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1629                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1630            }
1631    
1632            ui_destroy_window();
1633            g_fullscreen = !g_fullscreen;
1634            ui_create_window();
1635    
1636            XDefineCursor(g_display, g_wnd, g_current_cursor);
1637    
1638            if (!g_ownbackstore)
1639            {
1640                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1641                    XFreePixmap(g_display, contents);
1642            }
1643  }  }
1644    
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 event;          XEvent xevent;
1732          KeySym keysym;          KeySym keysym;
         uint8 scancode;  
         uint16 button;  
1733          uint32 ev_time;          uint32 ev_time;
1734            char str[256];
1735            Status status;
1736            int events = 0;
1737            seamless_window *sw;
1738    
1739          if (display == NULL)          while ((XPending(g_display) > 0) && events++ < 20)
                 return;  
   
         while (XCheckWindowEvent(display, wnd, ~0, &event))  
1740          {          {
1741                  ev_time = time(NULL);                  XNextEvent(g_display, &xevent);
1742    
1743                  switch (event.type)                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1744                  {                  {
1745                            DEBUG_KBD(("Filtering event\n"));
1746                            continue;
1747                    }
1748    
1749                    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                                  keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0);                                  g_last_gesturetime = xevent.xkey.time;
1767                                  scancode = xkeymap_translate_key(keysym, event.xkey.keycode);                                  if (g_IC != NULL)
1768                                  if (scancode == 0)                                          /* Multi_key compatible version */
1769                                    {
1770                                            XmbLookupString(g_IC,
1771                                                            &xevent.xkey, str, sizeof(str), &keysym,
1772                                                            &status);
1773                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1774                                            {
1775                                                    error("XmbLookupString failed with status 0x%x\n",
1776                                                          status);
1777                                                    break;
1778                                            }
1779                                    }
1780                                    else
1781                                    {
1782                                            /* Plain old XLookupString */
1783                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1784                                            XLookupString((XKeyEvent *) & xevent,
1785                                                          str, sizeof(str), &keysym, NULL);
1786                                    }
1787    
1788                                    DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1789                                               get_ksname(keysym)));
1790    
1791                                    ev_time = time(NULL);
1792                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1793                                          break;                                          break;
1794    
1795                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1796                                                 scancode, 0);                                                    ev_time, True, 0);
1797                                  break;                                  break;
1798    
1799                          case KeyRelease:                          case KeyRelease:
1800                                  keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0);                                  g_last_gesturetime = xevent.xkey.time;
1801                                  scancode = xkeymap_translate_key(keysym, event.xkey.keycode);                                  XLookupString((XKeyEvent *) & xevent, str,
1802                                  if (scancode == 0)                                                sizeof(str), &keysym, NULL);
1803    
1804                                    DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1805                                               get_ksname(keysym)));
1806    
1807                                    ev_time = time(NULL);
1808                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1809                                          break;                                          break;
1810    
1811                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1812                                                 KBD_FLAG_DOWN | KBD_FLAG_UP,                                                    ev_time, False, 0);
                                                scancode, 0);  
1813                                  break;                                  break;
1814    
1815                          case ButtonPress:                          case ButtonPress:
1816                                  button = xkeymap_translate_button(event.xbutton.button);                                  handle_button_event(xevent, True);
                                 if (button == 0)  
                                         break;  
   
                                 rdp_send_input(ev_time, RDP_INPUT_MOUSE,  
                                                button | MOUSE_FLAG_DOWN,  
                                                event.xbutton.x,  
                                                event.xbutton.y);  
1817                                  break;                                  break;
1818    
1819                          case ButtonRelease:                          case ButtonRelease:
1820                                  button = xkeymap_translate_button(event.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                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (g_fullscreen && !g_focused)
1833                                                 button,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1834                                                 event.xbutton.x,                                                         CurrentTime);
1835                                                 event.xbutton.y);  
1836                                    if (xevent.xmotion.window == g_wnd)
1837                                    {
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,                                          break;
1853                                                 event.xmotion.x,                                  g_focused = True;
1854                                                 event.xmotion.y);                                  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                                  XGrabKeyboard(display, wnd, True, GrabModeAsync,                                  /* we only register for this event when in fullscreen mode */
1870                                                GrabModeAsync, CurrentTime);                                  /* 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);
1881                                  break;                                  break;
1882    
1883                          case LeaveNotify:                          case LeaveNotify:
1884                                  XUngrabKeyboard(display, CurrentTime);                                  /* we only register for this event when grab_keyboard */
1885                                    g_mouse_in_wnd = False;
1886                                    XUngrabKeyboard(g_display, CurrentTime);
1887                                  break;                                  break;
1888    
1889                          case Expose:                          case Expose:
1890                                  XCopyArea(display, backstore, wnd, gc,                                  if (xevent.xexpose.window == g_wnd)
1891                                            event.xexpose.x, event.xexpose.y,                                  {
1892                                            event.xexpose.width, event.xexpose.height,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1893                                            event.xexpose.x, event.xexpose.y);                                                    g_gc,
1894                                                      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;
1917    
1918                            case MappingNotify:
1919                                    /* Refresh keyboard mapping if it has changed. This is important for
1920                                       Xvnc, since it allocates keycodes dynamically */
1921                                    if (xevent.xmapping.request == MappingKeyboard
1922                                        || xevent.xmapping.request == MappingModifier)
1923                                            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;
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;                                  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          XFlush(display);          BOOL s_timeout = False;
   
         FD_ZERO(&rfds);  
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 */
1988                    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                  if (FD_ISSET(x_socket, &rfds))                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
                         xwin_process_events();  
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
2045  ui_create_bitmap(int width, int height, uint8 *data)  ui_create_bitmap(int width, int height, uint8 * data)
2046  {  {
2047          XImage *image;          XImage *image;
2048          Pixmap bitmap;          Pixmap bitmap;
2049          uint8 *tdata;          uint8 *tdata;
2050            int bitmap_pad;
2051    
2052          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2053          bitmap = XCreatePixmap(display, wnd, width, height, depth);          {
2054          image = XCreateImage(display, visual, depth, ZPixmap,                  bitmap_pad = 8;
2055                               0, tdata, width, height, 8, 0);          }
2056            else
2057            {
2058                    bitmap_pad = g_bpp;
2059    
2060          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);                  if (g_bpp == 24)
2061                            bitmap_pad = 32;
2062            }
2063    
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(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2070    
2071          XFree(image);          XFree(image);
2072          if (!owncolmap)          if (tdata != data)
2073                  xfree(tdata);                  xfree(tdata);
2074          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2075  }  }
2076    
2077  void  void
2078  ui_paint_bitmap(int x, int y, int cx, int cy,  ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
                 int width, int height, uint8 *data)  
2079  {  {
2080          XImage *image;          XImage *image;
2081          uint8 *tdata;          uint8 *tdata;
2082            int bitmap_pad;
2083    
2084          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2085          image = XCreateImage(display, visual, depth, ZPixmap,          {
2086                               0, tdata, width, height, 8, 0);                  bitmap_pad = 8;
2087            }
2088            else
2089            {
2090                    bitmap_pad = g_bpp;
2091    
2092          if (ownbackstore)                  if (g_bpp == 24)
2093                            bitmap_pad = 32;
2094            }
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 (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          if (!owncolmap)          if (tdata != data)
2118                  xfree(tdata);                  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
2128  ui_create_glyph(int width, int height, uint8 *data)  ui_create_glyph(int width, int height, uint8 * data)
2129  {  {
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,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2141                               data, 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);
2149          XFreeGC(display, gc);          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
2159  ui_create_cursor(unsigned int x, unsigned int y, int width,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2160                   int height, uint8 *andmask, uint8 *xormask)                   uint8 * andmask, uint8 * xormask)
2161  {  {
2162          HGLYPH maskglyph, cursorglyph;          HGLYPH maskglyph, cursorglyph;
2163          XColor bg, fg;          XColor bg, fg;
# Line 542  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 585  ui_create_cursor(unsigned int x, unsigne Line 2214  ui_create_cursor(unsigned int x, unsigne
2214    
2215          cursorglyph = ui_create_glyph(width, height, cursor);          cursorglyph = ui_create_glyph(width, height, cursor);
2216          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2217            
2218          xcursor = XCreatePixmapCursor(display, (Pixmap)cursorglyph,          xcursor =
2219                                  (Pixmap)maskglyph, &fg, &bg, x, y);                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2220                                        (Pixmap) maskglyph, &fg, &bg, x, y);
2221    
2222          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
2223          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2224          xfree(mask);          xfree(mask);
2225          xfree(cursor);          xfree(cursor);
2226          return (HCURSOR)xcursor;          return (HCURSOR) xcursor;
2227  }  }
2228    
2229  void  void
2230  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2231  {  {
2232          XDefineCursor(display, wnd, (Cursor)cursor);          g_current_cursor = (Cursor) cursor;
2233            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 614  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            if (!g_owncolmap)
         if (owncolmap)  
2262          {          {
2263                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2264                  Colormap map;                  XColor xentry;
2265                    XColor xc_cache[256];
2266                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
2267                    int colLookup = 256;
2268                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2269                  {                  {
2270                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2271                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
                         xentry->pixel = i;  
                         MAKE_XCOLOR(xentry, entry);  
                 }  
2272    
2273                  map = XCreateColormap(display, wnd, visual, AllocAll);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2274                  XStoreColors(display, map, xcolours, ncolours);                          {
2275                                    /* Allocation failed, find closest match. */
2276                                    int j = 256;
2277                                    int nMinDist = 3 * 256 * 256;
2278                                    long nDist = nMinDist;
2279    
2280                  xfree(xcolours);                                  /* only get the colors once */
2281                  return (HCOLOURMAP)map;                                  while (colLookup--)
2282                                    {
2283                                            xc_cache[colLookup].pixel = colLookup;
2284                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2285                                                    xc_cache[colLookup].blue = 0;
2286                                            xc_cache[colLookup].flags = 0;
2287                                            XQueryColor(g_display,
2288                                                        DefaultColormap(g_display,
2289                                                                        DefaultScreen(g_display)),
2290                                                        &xc_cache[colLookup]);
2291                                    }
2292                                    colLookup = 0;
2293    
2294                                    /* 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    
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                            }
2329    
2330                            map[i] = colour;
2331                    }
2332                    return map;
2333          }          }
2334          else          else
2335          {          {
2336                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
2337                  XColor xentry;                  Colormap map;
                 uint32 colour;  
2338    
2339                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2340                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2341                  {                  {
2342                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2343                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
2344                            xentry->pixel = i;
2345                          if (XAllocColor(display, xcolmap, &xentry) != 0)                          MAKE_XCOLOR(xentry, entry);
                                 colour = xentry.pixel;  
                         else  
                                 colour = white;  
   
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
2346                  }                  }
2347    
2348                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2349                    XStoreColors(g_display, map, xcolours, ncolours);
2350    
2351                    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          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap)map);  
         else  
2360                  xfree(map);                  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          if (owncolmap)          if (!g_owncolmap)
2369                  XSetWindowColormap(display, wnd, (Colormap)map);          {
2370                    if (g_colmap)
2371                            xfree(g_colmap);
2372    
2373                    g_colmap = (uint32 *) map;
2374            }
2375          else          else
2376                  colmap = map;          {
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 721  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,
2429            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2430  {  {
2431          Pixmap fill;          Pixmap fill;
2432            uint8 i, ipattern[8];
2433    
2434          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2435    
# Line 734  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;                          break;
2442    
2443                  case 3: /* Pattern */                  case 2: /* Hatch */
2444                          fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);                          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;
2456    
2457                    case 3: /* Pattern */
2458                            for (i = 0; i != 8; i++)
2459                                    ipattern[7 - i] = brush->pattern[i];
2460                            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);
2469                          XSetFillStyle(display, gc, FillSolid);                          ui_destroy_glyph((HGLYPH) fill);
                         ui_destroy_glyph((HGLYPH)fill);  
2470                          break;                          break;
2471    
2472                  default:                  default:
# Line 757  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 765  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,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2494                            cx, cy, x, y);                            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 778  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,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
2518                            cx, cy, x, y);                                   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 789  void Line 2525  void
2525  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2526            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2527            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ HBITMAP src, int srcx, int srcy,
2528            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2529  {  {
2530          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
2531             comes up with a more efficient way of doing it I am using cases. */             comes up with a more efficient way of doing it I am using cases. */
# Line 798  ui_triblt(uint8 opcode, Line 2534  ui_triblt(uint8 opcode,
2534          {          {
2535                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
2536                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2537                          ui_patblt(ROP2_NXOR, x, y, cx, cy,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2538                          break;                          break;
2539    
2540                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2541                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2542                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2543                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2544                          break;                          break;
2545    
2546                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
2547                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2548                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2549                          break;                          break;
2550    
2551                  default:                  default:
# Line 825  ui_triblt(uint8 opcode, Line 2557  ui_triblt(uint8 opcode,
2557  void  void
2558  ui_line(uint8 opcode,  ui_line(uint8 opcode,
2559          /* dest */ int startx, int starty, int endx, int endy,          /* dest */ int startx, int starty, int endx, int endy,
2560          /* pen */ PEN *pen)          /* pen */ PEN * pen)
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 845  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, int bgcolour,                /* src */ HGLYPH glyph, int srcx, int srcy,
2736                int fgcolour)                int bgcolour, int fgcolour)
2737  {  {
2738          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
2739          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
2740    
2741          XSetFillStyle(display, gc, (mixmode == MIX_TRANSPARENT)          XSetFillStyle(g_display, g_gc,
2742                        ? 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) \
2752    {\
2753      glyph = cache_get_font (font, ttext[idx]);\
2754      if (!(flags & TEXT2_IMPLICIT_X))\
2755      {\
2756        xyoffset = ttext[++idx];\
2757        if ((xyoffset & 0x80))\
2758        {\
2759          if (flags & TEXT2_VERTICAL)\
2760            y += ttext[idx+1] | (ttext[idx+2] << 8);\
2761          else\
2762            x += ttext[idx+1] | (ttext[idx+2] << 8);\
2763          idx += 2;\
2764        }\
2765        else\
2766        {\
2767          if (flags & TEXT2_VERTICAL)\
2768            y += xyoffset;\
2769          else\
2770            x += xyoffset;\
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 boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2789               int bgcolour, 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, offset;          int i, j, xyoffset, x1, y1;
2795            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; i++)          for (i = 0; i < length;)
2820          {          {
2821                  glyph = cache_get_font(font, text[i]);                  switch (text[i])
   
                 if (!(flags & TEXT2_IMPLICIT_X))  
2822                  {                  {
2823                          offset = text[++i];                          case 0xff:
2824                          if (offset & 0x80)                                  /* At least two bytes needs to follow */
2825                                  offset = ((offset & 0x7f) << 8) | text[++i];                                  if (i + 3 > length)
2826                                    {
2827                                            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;
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 */
2838                                    text = &(text[i]);
2839                                    i = 0;
2840                                    break;
2841    
2842                          if (flags & TEXT2_VERTICAL)                          case 0xfe:
2843                                  y += offset;                                  /* At least one byte needs to follow */
2844                          else                                  if (i + 2 > length)
2845                                  x += offset;                                  {
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]);
2854                                    if (entry->data != NULL)
2855                                    {
2856                                            if ((((uint8 *) (entry->data))[1] == 0)
2857                                                && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2858                                            {
2859                                                    if (flags & TEXT2_VERTICAL)
2860                                                            y += text[i + 2];
2861                                                    else
2862                                                            x += text[i + 2];
2863                                            }
2864                                            for (j = 0; j < entry->size; j++)
2865                                                    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;
2876    
2877                            default:
2878                                    DO_GLYPH(text, i);
2879                                    i++;
2880                                    break;
2881                  }                  }
2882            }
2883    
2884                  if (glyph != NULL)          XSetFillStyle(g_display, g_gc, FillSolid);
                 {  
                         ui_draw_glyph(mixmode, x + (short) glyph->offset,  
                                       y + (short) glyph->baseline,  
                                       glyph->width, glyph->height,  
                                       glyph->pixmap, 0, 0,  
                                       bgcolour, fgcolour);  
2885    
2886                          if (flags & TEXT2_IMPLICIT_X)          if (g_ownbackstore)
2887                                  x += glyph->width;          {
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  }  }
# Line 920  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,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
                                   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,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2926                                    ZPixmap);                  XFreePixmap(g_display, pix);
                 XFreePixmap(display, pix);  
2927          }          }
2928    
2929          offset *= bpp/8;          offset *= g_bpp / 8;
2930          cache_put_desktop(offset, cx, cy, image->bytes_per_line,          cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
                           bpp/8, (uint8 *)image->data);  
2931    
2932          XDestroyImage(image);          XDestroyImage(image);
2933  }  }
# Line 947  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,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2947                               0, data, cx, cy, BitmapPad(display),                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
                              cx * 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.38  
changed lines
  Added in v.1118

  ViewVC Help
Powered by ViewVC 1.1.26