/[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 69 by astrand, Sat Jul 27 22:35:38 2002 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1118 by astrand, Tue Mar 14 13:56:50 2006 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2001     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <unistd.h>
24    #include <sys/time.h>
25  #include <time.h>  #include <time.h>
26  #include <errno.h>  #include <errno.h>
27  #define XK_MISCELLANY  #include <strings.h>
 #include <X11/keysymdef.h>  
28  #include "rdesktop.h"  #include "rdesktop.h"
29    #include "xproto.h"
30    
31  extern int width;  extern int g_width;
32  extern int height;  extern int g_height;
33  extern BOOL sendmotion;  extern int g_xpos;
34  extern BOOL fullscreen;  extern int g_ypos;
35    extern int g_pos;
36  Display *display = NULL;  extern BOOL g_sendmotion;
37  static int x_socket;  extern BOOL g_fullscreen;
38  static Window wnd;  extern BOOL g_grab_keyboard;
39  static GC gc;  extern BOOL g_hide_decorations;
40  static Visual *visual;  extern char g_title[];
41  static int depth;  /* Color depth of the RDP session.
42  static int bpp;     As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44    extern int g_win_button_size;
45    
46    Display *g_display;
47    Time g_last_gesturetime;
48    static int g_x_socket;
49    static Screen *g_screen;
50    Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            int xoffset, yoffset;
58            int width, height;
59            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  static XIM IM = NULL;  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
234  static XIC IC = NULL;  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
235    #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
 #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  
 #define SET_FOREGROUND(col)     XSetForeground(display, 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 85  static int rop2_map[] = { Line 253  static int rop2_map[] = {
253          GXset                   /* 1 */          GXset                   /* 1 */
254  };  };
255    
256  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
257  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
258    
259  static void  static seamless_window *
260  translate8(uint8 * data, uint8 * out, uint8 * end)  seamless_get_window_by_id(unsigned long id)
261  {  {
262          while (out < end)          seamless_window *sw;
263                  *(out++) = (uint8) colmap[*(data++)];          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  static void  
272  translate16(uint8 * data, uint16 * out, uint16 * end)  static seamless_window *
273    seamless_get_window_by_wnd(Window wnd)
274  {  {
275          while (out < end)          seamless_window *sw;
276                  *(out++) = (uint16) colmap[*(data++)];          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  /* little endian - conversion happens when colourmap is built */  
285  static void  static void
286  translate24(uint8 * data, uint8 * out, uint8 * end)  seamless_remove_window(seamless_window * win)
287  {  {
288          uint32 value;          seamless_window *sw, **prevnext = &g_seamless_windows;
289            for (sw = g_seamless_windows; sw; sw = sw->next)
         while (out < end)  
290          {          {
291                  value = colmap[*(data++)];                  if (sw == win)
292                  *(out++) = value;                  {
293                  *(out++) = value >> 8;                          *prevnext = sw->next;
294                  *(out++) = value >> 16;                          xfree(sw);
295                            return;
296                    }
297                    prevnext = &sw->next;
298          }          }
299            return;
300  }  }
301    
302    
303  static void  static void
304  translate32(uint8 * data, uint32 * out, uint32 * end)  mwm_hide_decorations(Window wnd)
305  {  {
306          while (out < end)          PropMotifWmHints motif_hints;
307                  *(out++) = colmap[*(data++)];          Atom hintsatom;
 }  
308    
309  static uint8 *          /* setup the property */
310  translate_image(int width, int height, uint8 * data)          motif_hints.flags = MWM_HINTS_DECORATIONS;
311  {          motif_hints.decorations = 0;
         int size = width * height * bpp / 8;  
         uint8 *out = xmalloc(size);  
         uint8 *end = out + size;  
312    
313          switch (bpp)          /* get the atom for the property */
314            hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
315            if (!hintsatom)
316          {          {
317                  case 8:                  warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
318                          translate8(data, out, end);                  return;
319                          break;          }
320    
321                  case 16:          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
322                          translate16(data, (uint16 *) out, (uint16 *) end);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
                         break;  
323    
324                  case 24:  }
                         translate24(data, out, end);  
                         break;  
325    
326                  case 32:  #define SPLITCOLOUR15(colour, rv) \
327                          translate32(data, (uint32 *) out, (uint32 *) end);  { \
328                          break;          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          return out;  #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)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
353  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
354  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
355                          x = (x << 16) | (x >> 16); }                          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  static uint32
368  translate_colour(uint32 colour)  translate_colour(uint32 colour)
369  {  {
370          switch (bpp)          PixelColour pc;
371            switch (g_server_depth)
372          {          {
373                    case 15:
374                            SPLITCOLOUR15(colour, pc);
375                            break;
376                  case 16:                  case 16:
377                          if (host_be != xserver_be)                          SPLITCOLOUR16(colour, pc);
                                 BSWAP16(colour);  
378                          break;                          break;
   
379                  case 24:                  case 24:
380                          if (xserver_be)                          SPLITCOLOUR24(colour, pc);
                                 BSWAP24(colour);  
381                          break;                          break;
382                    default:
383                  case 32:                          /* Avoid warning */
384                          if (host_be != xserver_be)                          pc.red = 0;
385                                  BSWAP32(colour);                          pc.green = 0;
386                            pc.blue = 0;
387                          break;                          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)
431                    *(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 */
468    static void
469    translate8to24(const uint8 * data, uint8 * out, uint8 * end)
470    {
471            uint32 value;
472    
473            if (g_compatible_arch)
474            {
475                    while (out < end)
476                    {
477                            value = g_colmap[*(data++)];
478                            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
492    translate8to32(const uint8 * data, uint8 * out, uint8 * end)
493    {
494            uint32 value;
495    
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 void
525    translate15to16(const uint16 * data, uint8 * out, uint8 * end)
526    {
527            uint16 pixel;
528            uint16 value;
529            PixelColour pc;
530    
531            if (g_xserver_be)
532            {
533                    while (out < end)
534                    {
535                            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    static void
562    translate15to24(const uint16 * data, uint8 * out, uint8 * end)
563    {
564            uint32 value;
565            uint16 pixel;
566            PixelColour pc;
567    
568            if (g_compatible_arch)
569            {
570                    /* *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    static void
612    translate15to32(const uint16 * data, uint8 * out, uint8 * end)
613    {
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    static void
663    translate16to16(const uint16 * data, uint8 * out, uint8 * end)
664    {
665            uint16 pixel;
666            uint16 value;
667            PixelColour pc;
668    
669          return colour;          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  static unsigned long  static void
720  init_inputmethod(void)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
721  {  {
722          unsigned long filtered_events;          uint32 value;
723            uint16 pixel;
724            PixelColour pc;
725    
726          IM = XOpenIM(display, NULL, NULL, NULL);          if (g_compatible_arch)
727          if (IM == NULL)          {
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                  error("Failed to open input method\n");                  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          if (IM != NULL)  static void
790    translate16to32(const uint16 * data, uint8 * out, uint8 * end)
791    {
792            uint16 pixel;
793            uint32 value;
794            PixelColour pc;
795    
796            if (g_compatible_arch)
797          {          {
798                  /* Must be done after XCreateWindow */                  /* *INDENT-OFF* */
799                  IC = XCreateIC(IM, XNInputStyle,                  REPEAT4
800                                 (XIMPreeditNothing | XIMStatusNothing),                  (
801                                 XNClientWindow, wnd, XNFocusWindow, wnd, NULL);                          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                  if (IC == NULL)          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                          error("Failed to create input context\n");                          LOUT16(out, value);
                         XCloseIM(IM);  
                         IM = NULL;  
881                  }                  }
882          }          }
883    }
884    
885          /* For correct Multi_key/Compose processing, I guess.  static void
886             It seems to work alright anyway, though. */  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
887          if (IC != NULL)  {
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                  if (XGetICValues(IC, XNFilterEvents, &filtered_events, NULL)                  while (out < end)
                     != NULL)  
907                  {                  {
908                          error("Failed to obtain XNFilterEvents value from IC\n");                          pixel = *(data++) << 16;
909                          filtered_events = 0;                          pixel |= *(data++) << 8;
910                            pixel |= *(data++);
911                            SPLITCOLOUR24(pixel, pc);
912                            value = MAKECOLOUR(pc);
913                            LOUT24(out, value);
914                  }                  }
915          }          }
         return filtered_events;  
916  }  }
917    
918  static void  static void
919  close_inputmethod(void)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
920  {  {
921          if (IC != NULL)          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                  XDestroyIC(IC);                  while (out < end)
                 if (IM != NULL)  
962                  {                  {
963                          XCloseIM(IM);                          pixel = *(data++) << 16;
964                          IM = NULL;                          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:
1003                            switch (g_bpp)
1004                            {
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;
1016                    case 16:
1017                            switch (g_bpp)
1018                            {
1019                                    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;
1061            }
1062            return out;
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 long filtered_events;          unsigned red_weight, blue_weight, green_weight;
1122    
1123          display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1124    
1125          if (display == NULL)          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1126            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          pfm = XListPixmapFormats(display, &i);                          /* Try to find a no-translation visual that'll
1146          if (pfm != NULL)                             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            g_bpp = 0;
1260            for (i = 0; i < pixmap_formats_count; ++i)
1261          {          {
1262                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1263                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1264                  {                  {
1265                          if ((pfm[i].depth == depth)                          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                  }                  }
1294                  XFree(pfm);          }
1295            XFree(pfm);
1296            pfm = NULL;
1297            return True;
1298    }
1299    
1300    BOOL
1301    ui_init(void)
1302    {
1303            int screen_num;
1304    
1305            g_display = XOpenDisplay(NULL);
1306            if (g_display == NULL)
1307            {
1308                    error("Failed to open display: %s\n", XDisplayName(NULL));
1309                    return False;
1310          }          }
1311    
         if (bpp < 8)  
1312          {          {
1313                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1314                  XCloseDisplay(display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1315            }
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            if (!select_visual())
1324                  return False;                  return False;
1325    
1326            if (g_no_translate_image)
1327            {
1328                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1329          }          }
1330    
1331          if (depth <= 8)          if (g_server_depth > g_bpp)
1332                  owncolmap = True;          {
1333          else                  warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1334                  xcolmap = DefaultColormapOfScreen(screen);                          g_server_depth, g_bpp);
1335            }
1336    
1337          test = 1;          DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1338          host_be = !(BOOL) (*(uint8 *) (&test));                 g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
         xserver_be = (ImageByteOrder(display) == MSBFirst);  
1339    
1340          white = WhitePixelOfScreen(screen);          if (!g_owncolmap)
1341          attribs.background_pixel = BlackPixelOfScreen(screen);          {
1342          attribs.backing_store = DoesBackingStore(screen);                  g_xcolmap =
1343                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1344                                            AllocNone);
1345                    if (g_depth <= 8)
1346                            warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1347            }
1348    
1349          if (attribs.backing_store == NotUseful)          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1350                  ownbackstore = True;          {
1351                    warning("External BackingStore not available. Using internal.\n");
1352                    g_ownbackstore = True;
1353            }
1354    
1355          if (fullscreen)          /*
1356             * Determine desktop size
1357             */
1358            if (g_fullscreen)
1359          {          {
1360                  attribs.override_redirect = True;                  g_width = WidthOfScreen(g_screen);
1361                  width = WidthOfScreen(screen);                  g_height = HeightOfScreen(g_screen);
1362                  height = HeightOfScreen(screen);                  g_using_full_workarea = True;
1363          }          }
1364          else          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                    /* clear to prevent rubbish being exposed at startup */
1500                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1501                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1502            }
1503    
1504          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          XStoreName(g_display, g_wnd, g_title);
                             0, 0, width, height, 0, CopyFromParent,  
                             InputOutput, CopyFromParent,  
                             CWBackingStore | CWBackPixel | CWOverrideRedirect,  
                             &attribs);  
1505    
1506          XStoreName(display, wnd, title);          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 335  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_init2();          if (g_embed_wnd)
1530            {
1531                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1532            }
1533    
1534          input_mask =          get_input_mask(&input_mask);
                 KeyPressMask | KeyReleaseMask | ButtonPressMask |  
                 ButtonReleaseMask | EnterWindowMask | LeaveWindowMask;  
         if (sendmotion)  
                 input_mask |= PointerMotionMask;  
1535    
1536          if (ownbackstore)          if (g_IM != NULL)
1537                  input_mask |= ExposureMask;          {
1538                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1539                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1540    
1541          filtered_events = init_inputmethod();                  if ((g_IC != NULL)
1542                        && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1543                            input_mask |= ic_input_mask;
1544            }
1545    
1546          XSelectInput(display, wnd, input_mask | filtered_events);          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          gc = XCreateGC(display, wnd, 0, NULL);          g_focused = False;
1560            g_mouse_in_wnd = False;
1561    
1562          if (ownbackstore)          /* handle the WM_DELETE_WINDOW protocol */
1563                  backstore = XCreatePixmap(display, wnd, width, height, depth);          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          XMapWindow(display, wnd);          /* create invisible 1x1 cursor to be used as null cursor */
1568            if (g_null_cursor == NULL)
1569                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1570    
1571          return True;          return True;
1572  }  }
1573    
1574  void  void
1575  ui_destroy_window()  ui_resize_window()
1576  {  {
1577          if (ownbackstore)          XSizeHints *sizehints;
1578                  XFreePixmap(display, backstore);          Pixmap bs;
1579    
1580          XFreeGC(display, gc);          sizehints = XAllocSizeHints();
1581            if (sizehints)
1582            {
1583                    sizehints->flags = PMinSize | PMaxSize;
1584                    sizehints->min_width = sizehints->max_width = g_width;
1585                    sizehints->min_height = sizehints->max_height = g_height;
1586                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1587                    XFree(sizehints);
1588            }
1589    
1590            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          close_inputmethod();          XDefineCursor(g_display, g_wnd, g_current_cursor);
1637    
1638          XDestroyWindow(display, wnd);          if (!g_ownbackstore)
1639          XCloseDisplay(display);          {
1640          display = NULL;                  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          XEvent xevent;          uint16 button, flags = 0;
1649            g_last_gesturetime = xevent.xbutton.time;
1650            button = xkeymap_translate_button(xevent.xbutton.button);
1651            if (button == 0)
1652                    return;
1653    
1654            if (down)
1655                    flags = MOUSE_FLAG_DOWN;
1656    
1657            /* Stop moving window when button is released, regardless of cursor position */
1658            if (g_moving_wnd && (xevent.type == ButtonRelease))
1659                    g_moving_wnd = False;
1660    
1661            /* If win_button_size is nonzero, enable single app mode */
1662            if (xevent.xbutton.y < g_win_button_size)
1663            {
1664                    /*  Check from right to left: */
1665                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1666                    {
1667                            /* The close button, continue */
1668                            ;
1669                    }
1670                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1671                    {
1672                            /* The maximize/restore button. Do not send to
1673                               server.  It might be a good idea to change the
1674                               cursor or give some other visible indication
1675                               that rdesktop inhibited this click */
1676                            if (xevent.type == ButtonPress)
1677                                    return;
1678                    }
1679                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1680                    {
1681                            /* The minimize button. Iconify window. */
1682                            if (xevent.type == ButtonRelease)
1683                            {
1684                                    /* Release the mouse button outside the minimize button, to prevent the
1685                                       actual minimazation to happen */
1686                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1687                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1688                                    return;
1689                            }
1690                    }
1691                    else if (xevent.xbutton.x <= g_win_button_size)
1692                    {
1693                            /* The system menu. Ignore. */
1694                            if (xevent.type == ButtonPress)
1695                                    return;
1696                    }
1697                    else
1698                    {
1699                            /* The title bar. */
1700                            if (xevent.type == ButtonPress)
1701                            {
1702                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1703                                    {
1704                                            g_moving_wnd = True;
1705                                            g_move_x_offset = xevent.xbutton.x;
1706                                            g_move_y_offset = xevent.xbutton.y;
1707                                    }
1708                                    return;
1709                            }
1710                    }
1711            }
1712    
1713            if (xevent.xmotion.window == g_wnd)
1714            {
1715                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1716                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1717            }
1718            else
1719            {
1720                    /* SeamlessRDP */
1721                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1722                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1723            }
1724    }
1725    
1726    /* Process events in Xlib queue
1727       Returns 0 after user quit, 1 otherwise */
1728    static int
1729    xwin_process_events(void)
1730    {
1731            XEvent xevent;
1732          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1733          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
         char *ksname = NULL;  
1734          char str[256];          char str[256];
1735          Status status;          Status status;
1736            int events = 0;
1737            seamless_window *sw;
1738    
1739          /* Refresh keyboard mapping if it has changed. This is important for          while ((XPending(g_display) > 0) && events++ < 20)
            Xvnc, since it allocates keycodes dynamically */  
         if (XCheckTypedEvent(display, MappingNotify, &xevent))  
1740          {          {
1741                  if (xevent.xmapping.request == MappingKeyboard                  XNextEvent(g_display, &xevent);
                     || xevent.xmapping.request == MappingModifier)  
                         XRefreshKeyboardMapping(&xevent.xmapping);  
         }  
1742    
1743          while (XCheckMaskEvent(display, ~0, &xevent))                  if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
         {  
                 if (XFilterEvent(&xevent, None) == True)  
1744                  {                  {
1745                          DEBUG_KBD("Filtering event\n");                          DEBUG_KBD(("Filtering event\n"));
1746                          continue;                          continue;
1747                  }                  }
1748    
                 ev_time = time(NULL);  
                 flags = 0;  
   
1749                  switch (xevent.type)                  switch (xevent.type)
1750                  {                  {
1751                            case VisibilityNotify:
1752                                    if (xevent.xvisibility.window == g_wnd)
1753                                            g_Unobscured =
1754                                                    xevent.xvisibility.state == VisibilityUnobscured;
1755    
1756                                    break;
1757                            case ClientMessage:
1758                                    /* the window manager told us to quit */
1759                                    if ((xevent.xclient.message_type == g_protocol_atom)
1760                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1761                                            /* Quit */
1762                                            return 0;
1763                                    break;
1764    
1765                          case KeyPress:                          case KeyPress:
1766                                  if (IC != NULL)                                  g_last_gesturetime = xevent.xkey.time;
1767                                    if (g_IC != NULL)
1768                                          /* Multi_key compatible version */                                          /* Multi_key compatible version */
1769                                  {                                  {
1770                                          XmbLookupString(IC,                                          XmbLookupString(g_IC,
1771                                                          (XKeyPressedEvent *) &                                                          &xevent.xkey, str, sizeof(str), &keysym,
                                                         xevent, str,  
                                                         sizeof(str), &keysym,  
1772                                                          &status);                                                          &status);
1773                                          if (!                                          if (!((status == XLookupKeySym) || (status == XLookupBoth)))
                                             ((status == XLookupKeySym)  
                                              || (status == XLookupBoth)))  
1774                                          {                                          {
1775                                                  error("XmbLookupString failed with status 0x%x\n", status);                                                  error("XmbLookupString failed with status 0x%x\n",
1776                                                          status);
1777                                                  break;                                                  break;
1778                                          }                                          }
1779                                  }                                  }
1780                                  else                                  else
1781                                  {                                  {
1782                                          /* Plain old XLookupString */                                          /* Plain old XLookupString */
1783                                          DEBUG_KBD                                          DEBUG_KBD(("\nNo input context, using XLookupString\n"));
                                                 ("No input context, using XLookupString\n");  
1784                                          XLookupString((XKeyEvent *) & xevent,                                          XLookupString((XKeyEvent *) & xevent,
1785                                                        str, sizeof(str),                                                        str, sizeof(str), &keysym, NULL);
                                                       &keysym, NULL);  
                                 }  
   
                                 ksname = get_ksname(keysym);  
                                 DEBUG_KBD  
                                         ("\nKeyPress for (keysym 0x%lx, %s)\n",  
                                          keysym, ksname);  
   
                                 if (inhibit_key(keysym))  
                                 {  
                                         DEBUG_KBD("Inhibiting key\n");  
                                         break;  
1786                                  }                                  }
1787    
1788                                  tr = xkeymap_translate_key(keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1789                                                             xevent.xkey.                                             get_ksname(keysym)));
                                                            keycode,  
                                                            xevent.xkey.state);  
   
                                 ensure_remote_modifiers(ev_time, tr);  
1790    
1791                                  if (tr.scancode == 0)                                  ev_time = time(NULL);
1792                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1793                                          break;                                          break;
1794    
1795                                  rdp_send_scancode(ev_time, RDP_KEYPRESS,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1796                                                    tr.scancode);                                                    ev_time, True, 0);
1797                                  break;                                  break;
1798    
1799                          case KeyRelease:                          case KeyRelease:
1800                                    g_last_gesturetime = xevent.xkey.time;
1801                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1802                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1803    
1804                                  ksname = get_ksname(keysym);                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1805                                  DEBUG_KBD                                             get_ksname(keysym)));
                                         ("\nKeyRelease for (keysym 0x%lx, %s)\n",  
                                          keysym, ksname);  
   
                                 if (inhibit_key(keysym))  
                                         break;  
   
                                 tr = xkeymap_translate_key(keysym,  
                                                            xevent.xkey.  
                                                            keycode,  
                                                            xevent.xkey.state);  
1806    
1807                                  if (tr.scancode == 0)                                  ev_time = time(NULL);
1808                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1809                                          break;                                          break;
1810    
1811                                  rdp_send_scancode(ev_time, RDP_KEYRELEASE,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1812                                                    tr.scancode);                                                    ev_time, False, 0);
1813                                  break;                                  break;
1814    
1815                          case ButtonPress:                          case ButtonPress:
1816                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1817                                  /* fall through */                                  break;
1818    
1819                          case ButtonRelease:                          case ButtonRelease:
1820                                  button = xkeymap_translate_button(xevent.                                  handle_button_event(xevent, False);
1821                                                                    xbutton.                                  break;
1822                                                                    button);  
1823                                  if (button == 0)                          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                                                 flags | button,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1834                                                 xevent.xbutton.x,                                                         CurrentTime);
1835                                                 xevent.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                                                 xevent.xmotion.x,                                  g_focused = True;
1854                                                 xevent.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,                                  /* we only register for this event when in fullscreen mode */
1870                                                GrabModeAsync, GrabModeAsync,                                  /* or grab_keyboard */
1871                                                CurrentTime);                                  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                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
1892                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1893                                            xevent.xexpose.height,                                                    g_gc,
1894                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
1895                                                      xevent.xexpose.width, xevent.xexpose.height,
1896                                                      xevent.xexpose.x, xevent.xexpose.y);
1897                                    }
1898                                    else
1899                                    {
1900                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1901                                            if (sw)
1902                                                    XCopyArea(g_display, g_backstore,
1903                                                              xevent.xexpose.window, g_gc,
1904                                                              xevent.xexpose.x + sw->xoffset,
1905                                                              xevent.xexpose.y + sw->yoffset,
1906                                                              xevent.xexpose.width,
1907                                                              xevent.xexpose.height, xevent.xexpose.x,
1908                                                              xevent.xexpose.y);
1909                                            else
1910                                            {
1911                                                    error("Expose for unknown window 0x%lx\n",
1912                                                          xevent.xexpose.window);
1913                                            }
1914                                    }
1915    
1916                                    break;
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          FD_ZERO(&rfds);          BOOL s_timeout = False;
1983    
1984          while (True)          while (True)
1985          {          {
1986                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1987                    /* Process any events already waiting */
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                  if (display != NULL)                  FD_SET(g_x_socket, &rfds);
1996    
1997    #ifdef WITH_RDPSND
1998                    /* FIXME: there should be an API for registering fds */
1999                    if (g_dsp_busy)
2000                  {                  {
2001                          FD_SET(x_socket, &rfds);                          FD_SET(g_dsp_fd, &wfds);
2002                          XFlush(display);                          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                  switch (select(n, &rfds, NULL, NULL, NULL))                  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
# Line 583  ui_create_bitmap(int width, int height, Line 2047  ui_create_bitmap(int width, int height,
2047          XImage *image;          XImage *image;
2048          Pixmap bitmap;          Pixmap bitmap;
2049          uint8 *tdata;          uint8 *tdata;
2050            int bitmap_pad;
2051    
2052          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, 0, tdata, width,                  bitmap_pad = 8;
2055                               height, 8, 0);          }
2056            else
2057            {
2058                    bitmap_pad = g_bpp;
2059    
2060                    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(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2070    
2071          XFree(image);          XFree(image);
2072          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, int width, int height,  ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
                 uint8 * data)  
2079  {  {
2080          XImage *image;          XImage *image;
2081          uint8 *tdata;          uint8 *tdata;
2082            int bitmap_pad;
2083    
2084            if (g_server_depth == 8)
2085            {
2086                    bitmap_pad = 8;
2087            }
2088            else
2089            {
2090                    bitmap_pad = g_bpp;
2091    
2092                    if (g_bpp == 24)
2093                            bitmap_pad = 32;
2094            }
2095    
2096          tdata = (owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2097          image = XCreateImage(display, visual, depth, ZPixmap, 0, tdata, width,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2098                               height, 8, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2099    
2100          if (ownbackstore)          if (g_ownbackstore)
2101          {          {
2102                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2103                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2104                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2105                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2106                                             x - sw->xoffset, y - sw->yoffset));
2107          }          }
2108          else          else
2109          {          {
2110                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2111                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2112                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2113                                             x - sw->xoffset, y - sw->yoffset));
2114          }          }
2115    
2116          XFree(image);          XFree(image);
2117          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
# Line 635  ui_create_glyph(int width, int height, u Line 2130  ui_create_glyph(int width, int height, u
2130          XImage *image;          XImage *image;
2131          Pixmap bitmap;          Pixmap bitmap;
2132          int scanline;          int scanline;
         GC gc;  
2133    
2134          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2135    
2136          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2137          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2138                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2139    
2140          image = XCreateImage(display, visual, 1, ZPixmap, 0, data, width,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2141                               height, 8, scanline);                               width, height, 8, scanline);
2142          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2143          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2144          XInitImage(image);          XInitImage(image);
2145    
2146          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2147    
2148          XFree(image);          XFree(image);
         XFreeGC(display, gc);  
2149          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2150  }  }
2151    
2152  void  void
2153  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(HGLYPH glyph)
2154  {  {
2155          XFreePixmap(display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2156  }  }
2157    
2158  HCURSOR  HCURSOR
# Line 677  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 722  ui_create_cursor(unsigned int x, unsigne Line 2216  ui_create_cursor(unsigned int x, unsigne
2216          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2217    
2218          xcursor =          xcursor =
2219                  XCreatePixmapCursor(display, (Pixmap) cursorglyph,                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2220                                      (Pixmap) maskglyph, &fg, &bg, x, y);                                      (Pixmap) maskglyph, &fg, &bg, x, y);
2221    
2222          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
# Line 735  ui_create_cursor(unsigned int x, unsigne Line 2229  ui_create_cursor(unsigned int x, unsigne
2229  void  void
2230  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(HCURSOR cursor)
2231  {  {
2232          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 750  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)
2262            {
2263                    uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2264                    XColor xentry;
2265                    XColor xc_cache[256];
2266                    uint32 colour;
2267                    int colLookup = 256;
2268                    for (i = 0; i < ncolours; i++)
2269                    {
2270                            entry = &colours->colours[i];
2271                            MAKE_XCOLOR(&xentry, entry);
2272    
2273                            if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2274                            {
2275                                    /* Allocation failed, find closest match. */
2276                                    int j = 256;
2277                                    int nMinDist = 3 * 256 * 256;
2278                                    long nDist = nMinDist;
2279    
2280                                    /* only get the colors once */
2281                                    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          if (owncolmap)                          map[i] = colour;
2331                    }
2332                    return map;
2333            }
2334            else
2335          {          {
2336                  XColor *xcolours, *xentry;                  XColor *xcolours, *xentry;
2337                  Colormap map;                  Colormap map;
2338    
2339                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  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];
# Line 770  ui_create_colourmap(COLOURMAP * colours) Line 2345  ui_create_colourmap(COLOURMAP * colours)
2345                          MAKE_XCOLOR(xentry, entry);                          MAKE_XCOLOR(xentry, entry);
2346                  }                  }
2347    
2348                  map = XCreateColormap(display, wnd, visual, AllocAll);                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2349                  XStoreColors(display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2350    
2351                  xfree(xcolours);                  xfree(xcolours);
2352                  return (HCOLOURMAP) map;                  return (HCOLOURMAP) map;
2353          }          }
         else  
         {  
                 uint32 *map = xmalloc(sizeof(*colmap) * ncolours);  
                 XColor xentry;  
                 uint32 colour;  
   
                 for (i = 0; i < ncolours; i++)  
                 {  
                         entry = &colours->colours[i];  
                         MAKE_XCOLOR(&xentry, entry);  
   
                         if (XAllocColor(display, xcolmap, &xentry) != 0)  
                                 colour = xentry.pixel;  
                         else  
                                 colour = white;  
   
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
                 }  
   
                 return map;  
         }  
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 857  ui_destblt(uint8 opcode, Line 2414  ui_destblt(uint8 opcode,
2414          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2415  }  }
2416    
2417    static uint8 hatch_patterns[] = {
2418            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2419            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2420            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2421            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2422            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2423            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2424    };
2425    
2426  void  void
2427  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2428            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
# Line 871  ui_patblt(uint8 opcode, Line 2437  ui_patblt(uint8 opcode,
2437          {          {
2438                  case 0: /* Solid */                  case 0: /* Solid */
2439                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2440                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2441                            break;
2442    
2443                    case 2: /* Hatch */
2444                            fill = (Pixmap) ui_create_glyph(8, 8,
2445                                                            hatch_patterns + brush->pattern[0] * 8);
2446                            SET_FOREGROUND(fgcolour);
2447                            SET_BACKGROUND(bgcolour);
2448                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2449                            XSetStipple(g_display, g_gc, fill);
2450                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2451                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2452                            XSetFillStyle(g_display, g_gc, FillSolid);
2453                            XSetTSOrigin(g_display, g_gc, 0, 0);
2454                            ui_destroy_glyph((HGLYPH) fill);
2455                          break;                          break;
2456    
2457                  case 3: /* Pattern */                  case 3: /* Pattern */
2458                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2459                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2460                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2461                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2462                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2463                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2464                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2465                          XSetTSOrigin(display, gc, brush->xorigin,                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2466                                       brush->yorigin);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2467                            XSetFillStyle(g_display, g_gc, FillSolid);
2468                          FILL_RECTANGLE(x, y, cx, cy);                          XSetTSOrigin(g_display, g_gc, 0, 0);
   
                         XSetFillStyle(display, gc, FillSolid);  
2469                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
2470                          break;                          break;
2471    
# Line 897  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 905  ui_screenblt(uint8 opcode, Line 2488  ui_screenblt(uint8 opcode,
2488               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2489  {  {
2490          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2491          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2492          if (ownbackstore)          {
2493                  XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2494                            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 918  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 938  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, brush, bgcolour,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2538                          break;                          break;
2539    
2540                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2541                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   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, brush, bgcolour,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   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 969  ui_line(uint8 opcode, Line 2561  ui_line(uint8 opcode,
2561  {  {
2562          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2563          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2564          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2565          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2566                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
2567                                                endx - sw->xoffset, endy - sw->yoffset));
2568            if (g_ownbackstore)
2569                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2570          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2571  }  }
2572    
# Line 985  ui_rect( Line 2580  ui_rect(
2580  }  }
2581    
2582  void  void
2583    ui_polygon(uint8 opcode,
2584               /* mode */ uint8 fillmode,
2585               /* dest */ POINT * point, int npoints,
2586               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2587    {
2588            uint8 style, i, ipattern[8];
2589            Pixmap fill;
2590    
2591            SET_FUNCTION(opcode);
2592    
2593            switch (fillmode)
2594            {
2595                    case ALTERNATE:
2596                            XSetFillRule(g_display, g_gc, EvenOddRule);
2597                            break;
2598                    case WINDING:
2599                            XSetFillRule(g_display, g_gc, WindingRule);
2600                            break;
2601                    default:
2602                            unimpl("fill mode %d\n", fillmode);
2603            }
2604    
2605            if (brush)
2606                    style = brush->style;
2607            else
2608                    style = 0;
2609    
2610            switch (style)
2611            {
2612                    case 0: /* Solid */
2613                            SET_FOREGROUND(fgcolour);
2614                            FILL_POLYGON((XPoint *) point, npoints);
2615                            break;
2616    
2617                    case 2: /* Hatch */
2618                            fill = (Pixmap) ui_create_glyph(8, 8,
2619                                                            hatch_patterns + brush->pattern[0] * 8);
2620                            SET_FOREGROUND(fgcolour);
2621                            SET_BACKGROUND(bgcolour);
2622                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2623                            XSetStipple(g_display, g_gc, fill);
2624                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2625                            FILL_POLYGON((XPoint *) point, npoints);
2626                            XSetFillStyle(g_display, g_gc, FillSolid);
2627                            XSetTSOrigin(g_display, g_gc, 0, 0);
2628                            ui_destroy_glyph((HGLYPH) fill);
2629                            break;
2630    
2631                    case 3: /* Pattern */
2632                            for (i = 0; i != 8; i++)
2633                                    ipattern[7 - i] = brush->pattern[i];
2634                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2635                            SET_FOREGROUND(bgcolour);
2636                            SET_BACKGROUND(fgcolour);
2637                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2638                            XSetStipple(g_display, g_gc, fill);
2639                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2640                            FILL_POLYGON((XPoint *) point, npoints);
2641                            XSetFillStyle(g_display, g_gc, FillSolid);
2642                            XSetTSOrigin(g_display, g_gc, 0, 0);
2643                            ui_destroy_glyph((HGLYPH) fill);
2644                            break;
2645    
2646                    default:
2647                            unimpl("brush %d\n", brush->style);
2648            }
2649    
2650            RESET_FUNCTION(opcode);
2651    }
2652    
2653    void
2654    ui_polyline(uint8 opcode,
2655                /* dest */ POINT * points, int npoints,
2656                /* pen */ PEN * pen)
2657    {
2658            /* TODO: set join style */
2659            SET_FUNCTION(opcode);
2660            SET_FOREGROUND(pen->colour);
2661            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2662            if (g_ownbackstore)
2663                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2664                               CoordModePrevious);
2665    
2666            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2667                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2668    
2669            RESET_FUNCTION(opcode);
2670    }
2671    
2672    void
2673    ui_ellipse(uint8 opcode,
2674               /* mode */ uint8 fillmode,
2675               /* dest */ int x, int y, int cx, int cy,
2676               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2677    {
2678            uint8 style, i, ipattern[8];
2679            Pixmap fill;
2680    
2681            SET_FUNCTION(opcode);
2682    
2683            if (brush)
2684                    style = brush->style;
2685            else
2686                    style = 0;
2687    
2688            switch (style)
2689            {
2690                    case 0: /* Solid */
2691                            SET_FOREGROUND(fgcolour);
2692                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2693                            break;
2694    
2695                    case 2: /* Hatch */
2696                            fill = (Pixmap) ui_create_glyph(8, 8,
2697                                                            hatch_patterns + brush->pattern[0] * 8);
2698                            SET_FOREGROUND(fgcolour);
2699                            SET_BACKGROUND(bgcolour);
2700                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2701                            XSetStipple(g_display, g_gc, fill);
2702                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2703                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2704                            XSetFillStyle(g_display, g_gc, FillSolid);
2705                            XSetTSOrigin(g_display, g_gc, 0, 0);
2706                            ui_destroy_glyph((HGLYPH) fill);
2707                            break;
2708    
2709                    case 3: /* Pattern */
2710                            for (i = 0; i != 8; i++)
2711                                    ipattern[7 - i] = brush->pattern[i];
2712                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2713                            SET_FOREGROUND(bgcolour);
2714                            SET_BACKGROUND(fgcolour);
2715                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2716                            XSetStipple(g_display, g_gc, fill);
2717                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2718                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2719                            XSetFillStyle(g_display, g_gc, FillSolid);
2720                            XSetTSOrigin(g_display, g_gc, 0, 0);
2721                            ui_destroy_glyph((HGLYPH) fill);
2722                            break;
2723    
2724                    default:
2725                            unimpl("brush %d\n", brush->style);
2726            }
2727    
2728            RESET_FUNCTION(opcode);
2729    }
2730    
2731    /* warning, this function only draws on wnd or backstore, not both */
2732    void
2733  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
2734                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
2735                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ HGLYPH glyph, int srcx, int srcy,
# Line 993  ui_draw_glyph(int mixmode, Line 2738  ui_draw_glyph(int mixmode,
2738          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
2739          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
2740    
2741          XSetFillStyle(display, gc,          XSetFillStyle(g_display, g_gc,
2742                        (mixmode ==                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2743                         MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
2744          XSetStipple(display, gc, (Pixmap) glyph);          XSetTSOrigin(g_display, g_gc, x, y);
         XSetTSOrigin(display, gc, x, y);  
2745    
2746          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2747    
2748          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
2749  }  }
2750    
2751  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
2752  {\  {\
2753    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
2754    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
2755      {\
2756        xyoffset = ttext[++idx];\
2757        if ((xyoffset & 0x80))\
2758      {\      {\
2759        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
2760        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[++idx] | (ttext[++idx] << 8);\  
           else\  
             x += ttext[++idx] | (ttext[++idx] << 8);\  
         }\  
2761        else\        else\
2762          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
2763            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
2764      }\      }\
2765    if (glyph != NULL)\      else\
2766      {\      {\
2767        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
2768                       y + (short) glyph->baseline,\          y += xyoffset;\
2769                       glyph->width, glyph->height,\        else\
2770                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
2771      }\      }\
2772      }\
2773      if (glyph != NULL)\
2774      {\
2775        x1 = x + glyph->offset;\
2776        y1 = y + glyph->baseline;\
2777        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2778        XSetTSOrigin(g_display, g_gc, x1, y1);\
2779        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2780        if (flags & TEXT2_IMPLICIT_X)\
2781          x += glyph->width;\
2782      }\
2783  }  }
2784    
2785  void  void
2786  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2787               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2788               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2789               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2790  {  {
2791            /* TODO: use brush appropriately */
2792    
2793          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2794          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
2795          DATABLOB *entry;          DATABLOB *entry;
2796    
2797          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2798    
2799            /* Sometimes, the boxcx value is something really large, like
2800               32691. This makes XCopyArea fail with Xvnc. The code below
2801               is a quick fix. */
2802            if (boxx + boxcx > g_width)
2803                    boxcx = g_width - boxx;
2804    
2805          if (boxcx > 1)          if (boxcx > 1)
2806          {          {
2807                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2808          }          }
2809          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
2810          {          {
2811                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2812          }          }
2813    
2814            SET_FOREGROUND(fgcolour);
2815            SET_BACKGROUND(bgcolour);
2816            XSetFillStyle(g_display, g_gc, FillStippled);
2817    
2818          /* Paint text, character by character */          /* Paint text, character by character */
2819          for (i = 0; i < length;)          for (i = 0; i < length;)
2820          {          {
2821                  switch (text[i])                  switch (text[i])
2822                  {                  {
2823                          case 0xff:                          case 0xff:
2824                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2825                                          cache_put_text(text[i + 1], text,                                  if (i + 3 > length)
                                                        text[i + 2]);  
                                 else  
2826                                  {                                  {
2827                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2828                                            for (j = 0; j < length; j++)
2829                                                    fprintf(stderr, "%02x ", text[j]);
2830                                            fprintf(stderr, "\n");
2831                                            i = length = 0;
2832                                          break;                                          break;
2833                                  }                                  }
2834                                    cache_put_text(text[i + 1], text, text[i + 2]);
2835                                    i += 3;
2836                                    length -= i;
2837                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2838                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2839                                  i = 0;                                  i = 0;
2840                                  break;                                  break;
2841    
2842                          case 0xfe:                          case 0xfe:
2843                                    /* At least one byte needs to follow */
2844                                    if (i + 2 > length)
2845                                    {
2846                                            warning("Skipping short 0xfe command:");
2847                                            for (j = 0; j < length; j++)
2848                                                    fprintf(stderr, "%02x ", text[j]);
2849                                            fprintf(stderr, "\n");
2850                                            i = length = 0;
2851                                            break;
2852                                    }
2853                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2854                                  if (entry != NULL)                                  if (entry->data != NULL)
2855                                  {                                  {
2856                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2857                                               0)                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
                                             && (!(flags & TEXT2_IMPLICIT_X)))  
2858                                          {                                          {
2859                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2860                                                          y += text[i + 2];                                                          y += text[i + 2];
2861                                                  else                                                  else
2862                                                          x += text[i + 2];                                                          x += text[i + 2];
2863                                          }                                          }
                                         if (i + 2 < length)  
                                                 i += 3;  
                                         else  
                                                 i += 2;  
                                         length -= i;  
                                         /* this will move pointer from start to first character after FE command */  
                                         text = &(text[i]);  
                                         i = 0;  
2864                                          for (j = 0; j < entry->size; j++)                                          for (j = 0; j < entry->size; j++)
2865                                                  DO_GLYPH(((uint8 *) (entry->                                                  DO_GLYPH(((uint8 *) (entry->data)), j);
                                                                      data)),  
                                                          j);  
2866                                  }                                  }
2867                                    if (i + 2 < length)
2868                                            i += 3;
2869                                    else
2870                                            i += 2;
2871                                    length -= i;
2872                                    /* this will move pointer from start to first character after FE command */
2873                                    text = &(text[i]);
2874                                    i = 0;
2875                                  break;                                  break;
2876    
2877                          default:                          default:
# Line 1112  ui_draw_text(uint8 font, uint8 flags, in Line 2881  ui_draw_text(uint8 font, uint8 flags, in
2881                  }                  }
2882          }          }
2883    
2884            XSetFillStyle(g_display, g_gc, FillSolid);
2885    
2886            if (g_ownbackstore)
2887            {
2888                    if (boxcx > 1)
2889                    {
2890                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2891                                      boxy, boxcx, boxcy, boxx, boxy);
2892                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2893                                                    (g_display, g_backstore, sw->wnd, g_gc,
2894                                                     boxx, boxy,
2895                                                     boxcx, boxcy,
2896                                                     boxx - sw->xoffset, boxy - sw->yoffset));
2897                    }
2898                    else
2899                    {
2900                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2901                                      clipy, clipcx, clipcy, clipx, clipy);
2902                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2903                                                    (g_display, g_backstore, sw->wnd, g_gc,
2904                                                     clipx, clipy,
2905                                                     clipcx, clipcy, clipx - sw->xoffset,
2906                                                     clipy - sw->yoffset));
2907                    }
2908            }
2909  }  }
2910    
2911  void  void
# Line 1121  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, bpp / 8,          cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
                           (uint8 *) image->data);  
2931    
2932          XDestroyImage(image);          XDestroyImage(image);
2933  }  }
# Line 1148  ui_desktop_restore(uint32 offset, int x, Line 2938  ui_desktop_restore(uint32 offset, int x,
2938          XImage *image;          XImage *image;
2939          uint8 *data;          uint8 *data;
2940    
2941          offset *= bpp / 8;          offset *= g_bpp / 8;
2942          data = cache_get_desktop(offset, cx, cy, bpp / 8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2943          if (data == NULL)          if (data == NULL)
2944                  return;                  return;
2945    
2946          image = XCreateImage(display, visual, depth, ZPixmap, 0, data, cx, cy,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2947                               BitmapPad(display), cx * bpp / 8);                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2948    
2949          if (ownbackstore)          if (g_ownbackstore)
2950          {          {
2951                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2952                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2953                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2954                                            (g_display, g_backstore, sw->wnd, g_gc,
2955                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2956          }          }
2957          else          else
2958          {          {
2959                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2960                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2961                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2962                                             x - sw->xoffset, y - sw->yoffset));
2963          }          }
2964    
2965          XFree(image);          XFree(image);
2966  }  }
2967    
2968    /* these do nothing here but are used in uiports */
2969    void
2970    ui_begin_update(void)
2971    {
2972    }
2973    
2974    void
2975    ui_end_update(void)
2976    {
2977    }
2978    
2979    void
2980    ui_seamless_toggle()
2981    {
2982            if (g_seamless_rdp)
2983            {
2984                    /* Deactivate */
2985                    while (g_seamless_windows)
2986                    {
2987                            XDestroyWindow(g_display, g_seamless_windows->wnd);
2988                            seamless_remove_window(g_seamless_windows);
2989                    }
2990                    XMapWindow(g_display, g_wnd);
2991            }
2992            else
2993            {
2994                    /* Activate */
2995                    if (g_win_button_size)
2996                    {
2997                            error("SeamlessRDP mode cannot be activated when using single application mode\n");
2998                            return;
2999                    }
3000                    if (!g_using_full_workarea)
3001                    {
3002                            error("SeamlessRDP mode requires a session that covers the whole screen");
3003                            return;
3004                    }
3005    
3006                    XUnmapWindow(g_display, g_wnd);
3007                    seamless_send_sync();
3008            }
3009    
3010            g_seamless_rdp = !g_seamless_rdp;
3011    }
3012    
3013    void
3014    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3015    {
3016            Window wnd;
3017            XSetWindowAttributes attribs;
3018            XClassHint *classhints;
3019            long input_mask;
3020            seamless_window *sw, *sw_parent;
3021    
3022            get_window_attribs(&attribs);
3023    
3024            attribs.override_redirect = False;
3025    
3026            /* FIXME: Do not assume that -1, -1 is outside screen Consider
3027               wait with showing the window until STATE and others have
3028               been recieved. */
3029            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0,
3030                                InputOutput, g_visual,
3031                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3032                                CWBorderPixel, &attribs);
3033    
3034            XStoreName(g_display, wnd, "rdesktop-seamless");
3035    
3036            mwm_hide_decorations(wnd);
3037    
3038            classhints = XAllocClassHint();
3039            if (classhints != NULL)
3040            {
3041                    classhints->res_name = classhints->res_class = "rdesktop";
3042                    XSetClassHint(g_display, wnd, classhints);
3043                    XFree(classhints);
3044            }
3045    
3046            /* Set WM_TRANSIENT_FOR, if necessary */
3047            if (parent)
3048            {
3049                    sw_parent = seamless_get_window_by_id(parent);
3050                    if (sw_parent)
3051                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3052                    else
3053                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3054            }
3055    
3056            /* FIXME: Support for Input Context:s */
3057    
3058            get_input_mask(&input_mask);
3059            input_mask |= PropertyChangeMask;
3060    
3061            XSelectInput(g_display, wnd, input_mask);
3062    
3063            XMapWindow(g_display, wnd);
3064    
3065            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3066               seamless window, we could try to close the window on the
3067               serverside, instead of terminating rdesktop */
3068            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3069    
3070            sw = malloc(sizeof(seamless_window));
3071            sw->wnd = wnd;
3072            sw->id = id;
3073            sw->xoffset = 0;
3074            sw->yoffset = 0;
3075            sw->width = 0;
3076            sw->height = 0;
3077            sw->next = g_seamless_windows;
3078            g_seamless_windows = sw;
3079    }
3080    
3081    
3082    void
3083    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3084    {
3085            seamless_window *sw;
3086    
3087            sw = seamless_get_window_by_id(id);
3088            if (!sw)
3089            {
3090                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3091                    return;
3092            }
3093    
3094            XDestroyWindow(g_display, sw->wnd);
3095            seamless_remove_window(sw);
3096    }
3097    
3098    
3099    void
3100    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3101    {
3102            seamless_window *sw;
3103    
3104            sw = seamless_get_window_by_id(id);
3105            if (!sw)
3106            {
3107                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3108                    return;
3109            }
3110    
3111            if (!width || !height)
3112                    /* X11 windows must be at least 1x1 */
3113                    return;
3114    
3115            /* About MAX and MIN: Windows allows moving a window outside
3116               the desktop. This happens, for example, when maximizing an
3117               application. In this case, the position is set to something
3118               like -4,-4,1288,1032. Many WMs does not allow windows
3119               outside the desktop, however. Therefore, clip the window
3120               ourselves. */
3121            sw->xoffset = MAX(0, x);
3122            sw->yoffset = MAX(0, y);
3123            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3124            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3125    
3126            /* If we move the window in a maximized state, then KDE won't
3127               accept restoration */
3128            if (sw->state != SEAMLESSRDP_NORMAL)
3129                    return;
3130    
3131            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3132            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3133    }
3134    
3135    
3136    void
3137    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3138    {
3139            seamless_window *sw;
3140    
3141            sw = seamless_get_window_by_id(id);
3142            if (!sw)
3143            {
3144                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3145                    return;
3146            }
3147    
3148            XStoreName(g_display, sw->wnd, title);
3149    }
3150    
3151    
3152    void
3153    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3154    {
3155            seamless_window *sw;
3156    
3157            sw = seamless_get_window_by_id(id);
3158            if (!sw)
3159            {
3160                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3161                    return;
3162            }
3163    
3164            sw->state = state;
3165    
3166            switch (state)
3167            {
3168                    case SEAMLESSRDP_NORMAL:
3169                    case SEAMLESSRDP_MAXIMIZED:
3170                            ewmh_change_state(sw->wnd, state);
3171                            break;
3172                    case SEAMLESSRDP_MINIMIZED:
3173                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3174                               the Window Manager should probably just ignore the request, since
3175                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3176                               such as minimization, rather than an independent state." Besides,
3177                               XIconifyWindow is easier. */
3178                            XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3179                            break;
3180                    default:
3181                            warning("SeamlessRDP: Invalid state %d\n", state);
3182                            break;
3183            }
3184    }

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

  ViewVC Help
Powered by ViewVC 1.1.26