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

Legend:
Removed from v.194  
changed lines
  Added in v.1155

  ViewVC Help
Powered by ViewVC 1.1.26