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

Legend:
Removed from v.263  
changed lines
  Added in v.1142

  ViewVC Help
Powered by ViewVC 1.1.26