/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 643 by jsorg71, Wed Mar 24 18:16:58 2004 UTC revision 1372 by jsorg71, Mon Jan 8 04:47:06 2007 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- 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-2007
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 <X11/Xproto.h>
24  #include <unistd.h>  #include <unistd.h>
25  #include <sys/time.h>  #include <sys/time.h>
26  #include <time.h>  #include <time.h>
# Line 30  Line 31 
31    
32  extern int g_width;  extern int g_width;
33  extern int g_height;  extern int g_height;
34  extern BOOL g_sendmotion;  extern int g_xpos;
35  extern BOOL g_fullscreen;  extern int g_ypos;
36  extern BOOL g_grab_keyboard;  extern int g_pos;
37  extern BOOL g_hide_decorations;  extern RD_BOOL g_sendmotion;
38    extern RD_BOOL g_fullscreen;
39    extern RD_BOOL g_grab_keyboard;
40    extern RD_BOOL g_hide_decorations;
41  extern char g_title[];  extern char g_title[];
42  extern int g_server_bpp;  /* Color depth of the RDP session.
43       As of RDP 5.1, it may be 8, 15, 16 or 24. */
44    extern int g_server_depth;
45  extern int g_win_button_size;  extern int g_win_button_size;
46    
47  Display *g_display;  Display *g_display;
# Line 43  Time g_last_gesturetime; Line 49  Time g_last_gesturetime;
49  static int g_x_socket;  static int g_x_socket;
50  static Screen *g_screen;  static Screen *g_screen;
51  Window g_wnd;  Window g_wnd;
52  uint32 g_embed_wnd;  
53  BOOL g_enable_compose = False;  /* SeamlessRDP support */
54    typedef struct _seamless_group
55    {
56            Window wnd;
57            unsigned long id;
58            unsigned int refcnt;
59    } seamless_group;
60    typedef struct _seamless_window
61    {
62            Window wnd;
63            unsigned long id;
64            unsigned long behind;
65            seamless_group *group;
66            int xoffset, yoffset;
67            int width, height;
68            int state;              /* normal/minimized/maximized. */
69            unsigned int desktop;
70            struct timeval *position_timer;
71    
72            RD_BOOL outstanding_position;
73            unsigned int outpos_serial;
74            int outpos_xoffset, outpos_yoffset;
75            int outpos_width, outpos_height;
76    
77            struct _seamless_window *next;
78    } seamless_window;
79    static seamless_window *g_seamless_windows = NULL;
80    static unsigned long g_seamless_focused = 0;
81    static RD_BOOL g_seamless_started = False;      /* Server end is up and running */
82    static RD_BOOL g_seamless_active = False;       /* We are currently in seamless mode */
83    static RD_BOOL g_seamless_hidden = False;       /* Desktop is hidden on server */
84    extern RD_BOOL g_seamless_rdp;
85    
86    extern uint32 g_embed_wnd;
87    RD_BOOL g_enable_compose = False;
88    RD_BOOL g_Unobscured;           /* used for screenblt */
89  static GC g_gc = NULL;  static GC g_gc = NULL;
90    static GC g_create_bitmap_gc = NULL;
91    static GC g_create_glyph_gc = NULL;
92    static XRectangle g_clip_rectangle;
93  static Visual *g_visual;  static Visual *g_visual;
94    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
95       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
96       as far as we're concerned. */
97  static int g_depth;  static int g_depth;
98    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
99       This may be larger than g_depth, in which case some of the bits would
100       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
101  static int g_bpp;  static int g_bpp;
102  static XIM g_IM;  static XIM g_IM;
103  static XIC g_IC;  static XIC g_IC;
104  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
105  static Cursor g_current_cursor;  static Cursor g_current_cursor;
106  static HCURSOR g_null_cursor = NULL;  static RD_HCURSOR g_null_cursor = NULL;
107  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
108  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
109  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
110    static RD_BOOL g_focused;
111    static RD_BOOL g_mouse_in_wnd;
112    /* Indicates that:
113       1) visual has 15, 16 or 24 depth and the same color channel masks
114          as its RDP equivalent (implies X server is LE),
115       2) host is LE
116       This will trigger an optimization whose real value is questionable.
117    */
118    static RD_BOOL g_compatible_arch;
119    /* Indicates whether RDP's bitmaps and our XImages have the same
120       binary format. If so, we can avoid an expensive translation.
121       Note that this can be true when g_compatible_arch is false,
122       e.g.:
123      
124         RDP(LE) <-> host(BE) <-> X-Server(LE)
125        
126       ('host' is the machine running rdesktop; the host simply memcpy's
127        so its endianess doesn't matter)
128     */
129    static RD_BOOL g_no_translate_image = False;
130    
131  /* endianness */  /* endianness */
132  static BOOL g_host_be;  static RD_BOOL g_host_be;
133  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
134  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
135  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
136    
137  /* software backing store */  /* software backing store */
138  BOOL g_ownbackstore = True;     /* We can't rely on external BackingStore */  extern RD_BOOL g_ownbackstore;
139  static Pixmap g_backstore = 0;  static Pixmap g_backstore = 0;
140    
141  /* Moving in single app mode */  /* Moving in single app mode */
142  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
143  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
144  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
145    static RD_BOOL g_using_full_workarea = False;
146    
147  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
148  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
149  #endif  #endif
150    
151  /* MWM decorations */  /* MWM decorations */
# Line 84  extern BOOL g_rdpsnd; Line 153  extern BOOL g_rdpsnd;
153  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
154  typedef struct  typedef struct
155  {  {
156          uint32 flags;          unsigned long flags;
157          uint32 functions;          unsigned long functions;
158          uint32 decorations;          unsigned long decorations;
159          sint32 inputMode;          long inputMode;
160          uint32 status;          unsigned long status;
161  }  }
162  PropMotifWmHints;  PropMotifWmHints;
163    
# Line 100  typedef struct Line 169  typedef struct
169  }  }
170  PixelColour;  PixelColour;
171    
172    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
173            do { \
174                    seamless_window *sw; \
175                    XRectangle rect; \
176                    if (!g_seamless_windows) break; \
177                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
178                        rect.x = g_clip_rectangle.x - sw->xoffset; \
179                        rect.y = g_clip_rectangle.y - sw->yoffset; \
180                        rect.width = g_clip_rectangle.width; \
181                        rect.height = g_clip_rectangle.height; \
182                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
183                        func args; \
184                    } \
185                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
186            } while (0)
187    
188    static void
189    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
190    {
191            points[0].x -= xoffset;
192            points[0].y -= yoffset;
193            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
194            points[0].x += xoffset;
195            points[0].y += yoffset;
196    }
197    
198    static void
199    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
200    {
201            points[0].x -= xoffset;
202            points[0].y -= yoffset;
203            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
204            points[0].x += xoffset;
205            points[0].y += yoffset;
206    }
207    
208  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
209  { \  { \
210          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
211            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
212          if (g_ownbackstore) \          if (g_ownbackstore) \
213                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
214  }  }
# Line 113  PixelColour; Line 218  PixelColour;
218          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
219  }  }
220    
221    #define FILL_POLYGON(p,np)\
222    { \
223            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
224            if (g_ownbackstore) \
225                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
226            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
227    }
228    
229    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
230    { \
231            switch (m) \
232            { \
233                    case 0: /* Outline */ \
234                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
235                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
236                            if (g_ownbackstore) \
237                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
238                            break; \
239                    case 1: /* Filled */ \
240                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
241                            ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
242                            if (g_ownbackstore) \
243                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
244                            break; \
245            } \
246    }
247    
248  /* colour maps */  /* colour maps */
249  BOOL g_owncolmap = False;  extern RD_BOOL g_owncolmap;
250  static Colormap g_xcolmap;  static Colormap g_xcolmap;
251  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
252    
253  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
254  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
255  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
256    
# Line 144  static int rop2_map[] = { Line 276  static int rop2_map[] = {
276  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
277  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
278    
279    static seamless_window *
280    sw_get_window_by_id(unsigned long id)
281    {
282            seamless_window *sw;
283            for (sw = g_seamless_windows; sw; sw = sw->next)
284            {
285                    if (sw->id == id)
286                            return sw;
287            }
288            return NULL;
289    }
290    
291    
292    static seamless_window *
293    sw_get_window_by_wnd(Window wnd)
294    {
295            seamless_window *sw;
296            for (sw = g_seamless_windows; sw; sw = sw->next)
297            {
298                    if (sw->wnd == wnd)
299                            return sw;
300            }
301            return NULL;
302    }
303    
304    
305    static void
306    sw_remove_window(seamless_window * win)
307    {
308            seamless_window *sw, **prevnext = &g_seamless_windows;
309            for (sw = g_seamless_windows; sw; sw = sw->next)
310            {
311                    if (sw == win)
312                    {
313                            *prevnext = sw->next;
314                            sw->group->refcnt--;
315                            if (sw->group->refcnt == 0)
316                            {
317                                    XDestroyWindow(g_display, sw->group->wnd);
318                                    xfree(sw->group);
319                            }
320                            xfree(sw->position_timer);
321                            xfree(sw);
322                            return;
323                    }
324                    prevnext = &sw->next;
325            }
326            return;
327    }
328    
329    
330    /* Move all windows except wnd to new desktop */
331    static void
332    sw_all_to_desktop(Window wnd, unsigned int desktop)
333    {
334            seamless_window *sw;
335            for (sw = g_seamless_windows; sw; sw = sw->next)
336            {
337                    if (sw->wnd == wnd)
338                            continue;
339                    if (sw->desktop != desktop)
340                    {
341                            ewmh_move_to_desktop(sw->wnd, desktop);
342                            sw->desktop = desktop;
343                    }
344            }
345    }
346    
347    
348    /* Send our position */
349    static void
350    sw_update_position(seamless_window * sw)
351    {
352            XWindowAttributes wa;
353            int x, y;
354            Window child_return;
355            unsigned int serial;
356    
357            XGetWindowAttributes(g_display, sw->wnd, &wa);
358            XTranslateCoordinates(g_display, sw->wnd, wa.root,
359                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
360    
361            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
362    
363            sw->outstanding_position = True;
364            sw->outpos_serial = serial;
365    
366            sw->outpos_xoffset = x;
367            sw->outpos_yoffset = y;
368            sw->outpos_width = wa.width;
369            sw->outpos_height = wa.height;
370    }
371    
372    
373    /* Check if it's time to send our position */
374  static void  static void
375  mwm_hide_decorations(void)  sw_check_timers()
376    {
377            seamless_window *sw;
378            struct timeval now;
379    
380            gettimeofday(&now, NULL);
381            for (sw = g_seamless_windows; sw; sw = sw->next)
382            {
383                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
384                    {
385                            timerclear(sw->position_timer);
386                            sw_update_position(sw);
387                    }
388            }
389    }
390    
391    
392    static void
393    sw_restack_window(seamless_window * sw, unsigned long behind)
394    {
395            seamless_window *sw_above;
396    
397            /* Remove window from stack */
398            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
399            {
400                    if (sw_above->behind == sw->id)
401                            break;
402            }
403    
404            if (sw_above)
405                    sw_above->behind = sw->behind;
406    
407            /* And then add it at the new position */
408            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
409            {
410                    if (sw_above->behind == behind)
411                            break;
412            }
413    
414            if (sw_above)
415                    sw_above->behind = sw->id;
416    
417            sw->behind = behind;
418    }
419    
420    
421    static void
422    sw_handle_restack(seamless_window * sw)
423    {
424            Status status;
425            Window root, parent, *children;
426            unsigned int nchildren, i;
427            seamless_window *sw_below;
428    
429            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
430                                &root, &parent, &children, &nchildren);
431            if (!status || !nchildren)
432                    return;
433    
434            sw_below = NULL;
435    
436            i = 0;
437            while (children[i] != sw->wnd)
438            {
439                    i++;
440                    if (i >= nchildren)
441                            goto end;
442            }
443    
444            for (i++; i < nchildren; i++)
445            {
446                    sw_below = sw_get_window_by_wnd(children[i]);
447                    if (sw_below)
448                            break;
449            }
450    
451            if (!sw_below && !sw->behind)
452                    goto end;
453            if (sw_below && (sw_below->id == sw->behind))
454                    goto end;
455    
456            if (sw_below)
457            {
458                    seamless_send_zchange(sw->id, sw_below->id, 0);
459                    sw_restack_window(sw, sw_below->id);
460            }
461            else
462            {
463                    seamless_send_zchange(sw->id, 0, 0);
464                    sw_restack_window(sw, 0);
465            }
466    
467          end:
468            XFree(children);
469    }
470    
471    
472    static seamless_group *
473    sw_find_group(unsigned long id, RD_BOOL dont_create)
474    {
475            seamless_window *sw;
476            seamless_group *sg;
477            XSetWindowAttributes attribs;
478    
479            for (sw = g_seamless_windows; sw; sw = sw->next)
480            {
481                    if (sw->group->id == id)
482                            return sw->group;
483            }
484    
485            if (dont_create)
486                    return NULL;
487    
488            sg = xmalloc(sizeof(seamless_group));
489    
490            sg->wnd =
491                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
492                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
493    
494            sg->id = id;
495            sg->refcnt = 0;
496    
497            return sg;
498    }
499    
500    
501    static void
502    mwm_hide_decorations(Window wnd)
503  {  {
504          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
505          Atom hintsatom;          Atom hintsatom;
# Line 162  mwm_hide_decorations(void) Line 516  mwm_hide_decorations(void)
516                  return;                  return;
517          }          }
518    
519          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
520                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
521    
522  }  }
523    
524  static PixelColour  #define SPLITCOLOUR15(colour, rv) \
525  split_colour15(uint32 colour)  { \
526  {          rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
527          PixelColour rv;          rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
528          rv.red = (colour & 0x7c00) >> 7;          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
         rv.green = (colour & 0x03e0) >> 2;  
         rv.blue = (colour & 0x001f) << 3;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour16(uint32 colour)  
 {  
         PixelColour rv;  
         rv.red = (colour & 0xf800) >> 8;  
         rv.green = (colour & 0x07e0) >> 3;  
         rv.blue = (colour & 0x001f) << 3;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour24(uint32 colour)  
 {  
         PixelColour rv;  
         rv.blue = (colour & 0xff0000) >> 16;  
         rv.green = (colour & 0x00ff00) >> 8;  
         rv.red = (colour & 0x0000ff);  
         return rv;  
529  }  }
530    
531  static uint32  #define SPLITCOLOUR16(colour, rv) \
532  make_colour(PixelColour pc)  { \
533  {          rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
534          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
535                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
536                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));  } \
537    
538    #define SPLITCOLOUR24(colour, rv) \
539    { \
540            rv.blue = (colour & 0xff0000) >> 16; \
541            rv.green = (colour & 0x00ff00) >> 8; \
542            rv.red = (colour & 0x0000ff); \
543  }  }
544    
545    #define MAKECOLOUR(pc) \
546            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
547                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
548                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
549    
550  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
551  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
552  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
553                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
554    
555    /* The following macros output the same octet sequences
556       on both BE and LE hosts: */
557    
558    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
559    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
560    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
561    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
562    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
563    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
564    
565  static uint32  static uint32
566  translate_colour(uint32 colour)  translate_colour(uint32 colour)
567  {  {
568          PixelColour pc;          PixelColour pc;
569          switch (g_server_bpp)          switch (g_server_depth)
570          {          {
571                  case 15:                  case 15:
572                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
573                          break;                          break;
574                  case 16:                  case 16:
575                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
576                          break;                          break;
577                  case 24:                  case 24:
578                          pc = split_colour24(colour);                          SPLITCOLOUR24(colour, pc);
579                            break;
580                    default:
581                            /* Avoid warning */
582                            pc.red = 0;
583                            pc.green = 0;
584                            pc.blue = 0;
585                          break;                          break;
586          }          }
587          return make_colour(pc);          return MAKECOLOUR(pc);
588  }  }
589    
590    /* indent is confused by UNROLL8 */
591    /* *INDENT-OFF* */
592    
593    /* repeat and unroll, similar to bitmap.c */
594    /* potentialy any of the following translate */
595    /* functions can use repeat but just doing */
596    /* the most common ones */
597    
598    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
599    /* 2 byte output repeat */
600    #define REPEAT2(stm) \
601    { \
602            while (out <= end - 8 * 2) \
603                    UNROLL8(stm) \
604            while (out < end) \
605                    { stm } \
606    }
607    /* 3 byte output repeat */
608    #define REPEAT3(stm) \
609    { \
610            while (out <= end - 8 * 3) \
611                    UNROLL8(stm) \
612            while (out < end) \
613                    { stm } \
614    }
615    /* 4 byte output repeat */
616    #define REPEAT4(stm) \
617    { \
618            while (out <= end - 8 * 4) \
619                    UNROLL8(stm) \
620            while (out < end) \
621                    { stm } \
622    }
623    /* *INDENT-ON* */
624    
625  static void  static void
626  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
627  {  {
628          while (out < end)          while (out < end)
629                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
630  }  }
631    
632  static void  static void
633  translate8to16(uint8 * data, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
634  {  {
635          uint16 value;          uint16 value;
636    
637          if (g_xserver_be)          if (g_compatible_arch)
638            {
639                    /* *INDENT-OFF* */
640                    REPEAT2
641                    (
642                            *((uint16 *) out) = g_colmap[*(data++)];
643                            out += 2;
644                    )
645                    /* *INDENT-ON* */
646            }
647            else if (g_xserver_be)
648          {          {
649                  while (out < end)                  while (out < end)
650                  {                  {
651                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
652                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
653                  }                  }
654          }          }
655          else          else
# Line 254  translate8to16(uint8 * data, uint8 * out Line 657  translate8to16(uint8 * data, uint8 * out
657                  while (out < end)                  while (out < end)
658                  {                  {
659                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
660                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
661                  }                  }
662          }          }
663  }  }
664    
665  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
666  static void  static void
667  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
668  {  {
669          uint32 value;          uint32 value;
670    
671          if (g_xserver_be)          if (g_compatible_arch)
672          {          {
673                  while (out < end)                  while (out < end)
674                  {                  {
675                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
676                          *(out++) = value >> 16;                          BOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
677                  }                  }
678          }          }
679          else          else
# Line 281  translate8to24(uint8 * data, uint8 * out Line 681  translate8to24(uint8 * data, uint8 * out
681                  while (out < end)                  while (out < end)
682                  {                  {
683                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
684                          *(out++) = value;                          LOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
685                  }                  }
686          }          }
687  }  }
688    
689  static void  static void
690  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
691  {  {
692          uint32 value;          uint32 value;
693    
694          if (g_xserver_be)          if (g_compatible_arch)
695            {
696                    /* *INDENT-OFF* */
697                    REPEAT4
698                    (
699                            *((uint32 *) out) = g_colmap[*(data++)];
700                            out += 4;
701                    )
702                    /* *INDENT-ON* */
703            }
704            else if (g_xserver_be)
705          {          {
706                  while (out < end)                  while (out < end)
707                  {                  {
708                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
709                          *(out++) = value >> 24;                          BOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 8;  
                         *(out++) = value;  
710                  }                  }
711          }          }
712          else          else
# Line 309  translate8to32(uint8 * data, uint8 * out Line 714  translate8to32(uint8 * data, uint8 * out
714                  while (out < end)                  while (out < end)
715                  {                  {
716                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
717                          *(out++) = value;                          LOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
718                  }                  }
719          }          }
720  }  }
721    
722  static void  static void
723  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
724  {  {
725          uint16 pixel;          uint16 pixel;
726          uint16 value;          uint16 value;
727            PixelColour pc;
728    
729          while (out < end)          if (g_xserver_be)
730          {          {
731                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                         BSWAP16(pixel);  
                 }  
   
                 value = make_colour(split_colour15(pixel));  
   
                 if (g_xserver_be)  
732                  {                  {
733                          *(out++) = value >> 8;                          pixel = *(data++);
734                          *(out++) = value;                          if (g_host_be)
735                            {
736                                    BSWAP16(pixel);
737                            }
738                            SPLITCOLOUR15(pixel, pc);
739                            value = MAKECOLOUR(pc);
740                            BOUT16(out, value);
741                  }                  }
742                  else          }
743            else
744            {
745                    while (out < end)
746                  {                  {
747                          *(out++) = value;                          pixel = *(data++);
748                          *(out++) = value >> 8;                          if (g_host_be)
749                            {
750                                    BSWAP16(pixel);
751                            }
752                            SPLITCOLOUR15(pixel, pc);
753                            value = MAKECOLOUR(pc);
754                            LOUT16(out, value);
755                  }                  }
756          }          }
757  }  }
758    
759  static void  static void
760  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
761  {  {
762          uint32 value;          uint32 value;
763          uint16 pixel;          uint16 pixel;
764            PixelColour pc;
765    
766          while (out < end)          if (g_compatible_arch)
767          {          {
768                  pixel = *(data++);                  /* *INDENT-OFF* */
769                    REPEAT3
770                  if (g_host_be)                  (
771                  {                          pixel = *(data++);
772                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
773                  }                          *(out++) = pc.blue;
774                            *(out++) = pc.green;
775                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
776                  if (g_xserver_be)                  )
777                    /* *INDENT-ON* */
778            }
779            else if (g_xserver_be)
780            {
781                    while (out < end)
782                  {                  {
783                          *(out++) = value >> 16;                          pixel = *(data++);
784                          *(out++) = value >> 8;                          if (g_host_be)
785                          *(out++) = value;                          {
786                                    BSWAP16(pixel);
787                            }
788                            SPLITCOLOUR15(pixel, pc);
789                            value = MAKECOLOUR(pc);
790                            BOUT24(out, value);
791                  }                  }
792                  else          }
793            else
794            {
795                    while (out < end)
796                  {                  {
797                          *(out++) = value;                          pixel = *(data++);
798                          *(out++) = value >> 8;                          if (g_host_be)
799                          *(out++) = value >> 16;                          {
800                                    BSWAP16(pixel);
801                            }
802                            SPLITCOLOUR15(pixel, pc);
803                            value = MAKECOLOUR(pc);
804                            LOUT24(out, value);
805                  }                  }
806          }          }
807  }  }
808    
809  static void  static void
810  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
811  {  {
812          uint16 pixel;          uint16 pixel;
813          uint32 value;          uint32 value;
814            PixelColour pc;
815    
816          while (out < end)          if (g_compatible_arch)
817          {          {
818                  pixel = *(data++);                  /* *INDENT-OFF* */
819                    REPEAT4
820                  if (g_host_be)                  (
821                  {                          pixel = *(data++);
822                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
823                  }                          *(out++) = pc.blue;
824                            *(out++) = pc.green;
825                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
826                            *(out++) = 0;
827                  if (g_xserver_be)                  )
828                    /* *INDENT-ON* */
829            }
830            else if (g_xserver_be)
831            {
832                    while (out < end)
833                  {                  {
834                          *(out++) = value >> 24;                          pixel = *(data++);
835                          *(out++) = value >> 16;                          if (g_host_be)
836                          *(out++) = value >> 8;                          {
837                          *(out++) = value;                                  BSWAP16(pixel);
838                            }
839                            SPLITCOLOUR15(pixel, pc);
840                            value = MAKECOLOUR(pc);
841                            BOUT32(out, value);
842                  }                  }
843                  else          }
844            else
845            {
846                    while (out < end)
847                  {                  {
848                          *(out++) = value;                          pixel = *(data++);
849                          *(out++) = value >> 8;                          if (g_host_be)
850                          *(out++) = value >> 16;                          {
851                          *(out++) = value >> 24;                                  BSWAP16(pixel);
852                            }
853                            SPLITCOLOUR15(pixel, pc);
854                            value = MAKECOLOUR(pc);
855                            LOUT32(out, value);
856                  }                  }
857          }          }
858  }  }
859    
860  static void  static void
861  translate16to16(uint16 * data, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
862  {  {
863          uint16 pixel;          uint16 pixel;
864          uint16 value;          uint16 value;
865            PixelColour pc;
866    
867          while (out < end)          if (g_xserver_be)
868          {          {
                 pixel = *(data++);  
   
869                  if (g_host_be)                  if (g_host_be)
870                  {                  {
871                          BSWAP16(pixel);                          while (out < end)
872                            {
873                                    pixel = *(data++);
874                                    BSWAP16(pixel);
875                                    SPLITCOLOUR16(pixel, pc);
876                                    value = MAKECOLOUR(pc);
877                                    BOUT16(out, value);
878                            }
879                  }                  }
880                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
881                  {                  {
882                          *(out++) = value >> 8;                          while (out < end)
883                          *(out++) = value;                          {
884                                    pixel = *(data++);
885                                    SPLITCOLOUR16(pixel, pc);
886                                    value = MAKECOLOUR(pc);
887                                    BOUT16(out, value);
888                            }
889                    }
890            }
891            else
892            {
893                    if (g_host_be)
894                    {
895                            while (out < end)
896                            {
897                                    pixel = *(data++);
898                                    BSWAP16(pixel);
899                                    SPLITCOLOUR16(pixel, pc);
900                                    value = MAKECOLOUR(pc);
901                                    LOUT16(out, value);
902                            }
903                  }                  }
904                  else                  else
905                  {                  {
906                          *(out++) = value;                          while (out < end)
907                          *(out++) = value >> 8;                          {
908                                    pixel = *(data++);
909                                    SPLITCOLOUR16(pixel, pc);
910                                    value = MAKECOLOUR(pc);
911                                    LOUT16(out, value);
912                            }
913                  }                  }
914          }          }
915  }  }
916    
917  static void  static void
918  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
919  {  {
920          uint32 value;          uint32 value;
921          uint16 pixel;          uint16 pixel;
922            PixelColour pc;
923    
924          while (out < end)          if (g_compatible_arch)
925            {
926                    /* *INDENT-OFF* */
927                    REPEAT3
928                    (
929                            pixel = *(data++);
930                            SPLITCOLOUR16(pixel, pc);
931                            *(out++) = pc.blue;
932                            *(out++) = pc.green;
933                            *(out++) = pc.red;
934                    )
935                    /* *INDENT-ON* */
936            }
937            else if (g_xserver_be)
938          {          {
                 pixel = *(data++);  
   
939                  if (g_host_be)                  if (g_host_be)
940                  {                  {
941                          BSWAP16(pixel);                          while (out < end)
942                            {
943                                    pixel = *(data++);
944                                    BSWAP16(pixel);
945                                    SPLITCOLOUR16(pixel, pc);
946                                    value = MAKECOLOUR(pc);
947                                    BOUT24(out, value);
948                            }
949                  }                  }
950                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
951                  {                  {
952                          *(out++) = value >> 16;                          while (out < end)
953                          *(out++) = value >> 8;                          {
954                          *(out++) = value;                                  pixel = *(data++);
955                                    SPLITCOLOUR16(pixel, pc);
956                                    value = MAKECOLOUR(pc);
957                                    BOUT24(out, value);
958                            }
959                    }
960            }
961            else
962            {
963                    if (g_host_be)
964                    {
965                            while (out < end)
966                            {
967                                    pixel = *(data++);
968                                    BSWAP16(pixel);
969                                    SPLITCOLOUR16(pixel, pc);
970                                    value = MAKECOLOUR(pc);
971                                    LOUT24(out, value);
972                            }
973                  }                  }
974                  else                  else
975                  {                  {
976                          *(out++) = value;                          while (out < end)
977                          *(out++) = value >> 8;                          {
978                          *(out++) = value >> 16;                                  pixel = *(data++);
979                                    SPLITCOLOUR16(pixel, pc);
980                                    value = MAKECOLOUR(pc);
981                                    LOUT24(out, value);
982                            }
983                  }                  }
984          }          }
985  }  }
986    
987  static void  static void
988  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
989  {  {
990          uint16 pixel;          uint16 pixel;
991          uint32 value;          uint32 value;
992            PixelColour pc;
993    
994          while (out < end)          if (g_compatible_arch)
995            {
996                    /* *INDENT-OFF* */
997                    REPEAT4
998                    (
999                            pixel = *(data++);
1000                            SPLITCOLOUR16(pixel, pc);
1001                            *(out++) = pc.blue;
1002                            *(out++) = pc.green;
1003                            *(out++) = pc.red;
1004                            *(out++) = 0;
1005                    )
1006                    /* *INDENT-ON* */
1007            }
1008            else if (g_xserver_be)
1009          {          {
                 pixel = *(data++);  
   
1010                  if (g_host_be)                  if (g_host_be)
1011                  {                  {
1012                          BSWAP16(pixel);                          while (out < end)
1013                            {
1014                                    pixel = *(data++);
1015                                    BSWAP16(pixel);
1016                                    SPLITCOLOUR16(pixel, pc);
1017                                    value = MAKECOLOUR(pc);
1018                                    BOUT32(out, value);
1019                            }
1020                  }                  }
1021                    else
1022                  value = make_colour(split_colour16(pixel));                  {
1023                            while (out < end)
1024                  if (g_xserver_be)                          {
1025                                    pixel = *(data++);
1026                                    SPLITCOLOUR16(pixel, pc);
1027                                    value = MAKECOLOUR(pc);
1028                                    BOUT32(out, value);
1029                            }
1030                    }
1031            }
1032            else
1033            {
1034                    if (g_host_be)
1035                  {                  {
1036                          *(out++) = value >> 24;                          while (out < end)
1037                          *(out++) = value >> 16;                          {
1038                          *(out++) = value >> 8;                                  pixel = *(data++);
1039                          *(out++) = value;                                  BSWAP16(pixel);
1040                                    SPLITCOLOUR16(pixel, pc);
1041                                    value = MAKECOLOUR(pc);
1042                                    LOUT32(out, value);
1043                            }
1044                  }                  }
1045                  else                  else
1046                  {                  {
1047                          *(out++) = value;                          while (out < end)
1048                          *(out++) = value >> 8;                          {
1049                          *(out++) = value >> 16;                                  pixel = *(data++);
1050                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
1051                                    value = MAKECOLOUR(pc);
1052                                    LOUT32(out, value);
1053                            }
1054                  }                  }
1055          }          }
1056  }  }
1057    
1058  static void  static void
1059  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1060  {  {
1061          uint32 pixel = 0;          uint32 pixel = 0;
1062          uint16 value;          uint16 value;
1063            PixelColour pc;
1064    
1065          while (out < end)          while (out < end)
1066          {          {
1067                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1068                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1069                  pixel |= *(data++);                  pixel |= *(data++);
1070                    SPLITCOLOUR24(pixel, pc);
1071                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1072                  if (g_xserver_be)                  if (g_xserver_be)
1073                  {                  {
1074                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1075                  }                  }
1076                  else                  else
1077                  {                  {
1078                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1079                  }                  }
1080          }          }
1081  }  }
1082    
1083  static void  static void
1084  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1085  {  {
1086          uint32 pixel;          uint32 pixel;
1087          uint32 value;          uint32 value;
1088            PixelColour pc;
1089    
1090          while (out < end)          if (g_xserver_be)
1091          {          {
1092                  pixel = *(data++) << 16;                  while (out < end)
                 pixel |= *(data++) << 8;  
                 pixel |= *(data++);  
   
                 value = make_colour(split_colour24(pixel));  
   
                 if (g_xserver_be)  
1093                  {                  {
1094                          *(out++) = value >> 16;                          pixel = *(data++) << 16;
1095                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1096                          *(out++) = value;                          pixel |= *(data++);
1097                            SPLITCOLOUR24(pixel, pc);
1098                            value = MAKECOLOUR(pc);
1099                            BOUT24(out, value);
1100                  }                  }
1101                  else          }
1102            else
1103            {
1104                    while (out < end)
1105                  {                  {
1106                          *(out++) = value;                          pixel = *(data++) << 16;
1107                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1108                          *(out++) = value >> 16;                          pixel |= *(data++);
1109                            SPLITCOLOUR24(pixel, pc);
1110                            value = MAKECOLOUR(pc);
1111                            LOUT24(out, value);
1112                  }                  }
1113          }          }
1114  }  }
1115    
1116  static void  static void
1117  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1118  {  {
1119          uint32 pixel;          uint32 pixel;
1120          uint32 value;          uint32 value;
1121            PixelColour pc;
1122    
1123          while (out < end)          if (g_compatible_arch)
1124          {          {
1125                  pixel = *(data++) << 16;                  /* *INDENT-OFF* */
1126                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
1127                  pixel |= *(data++);                  REPEAT4
1128                    (
1129                  value = make_colour(split_colour24(pixel));                          *(out++) = *(data++);
1130                            *(out++) = *(data++);
1131                  if (g_xserver_be)                          *(out++) = *(data++);
1132                            *(out++) = 0;
1133                    )
1134    #else
1135                    REPEAT4
1136                    (
1137                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1138                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1139                     out += 4;
1140                     data += 3;
1141                    )
1142    #endif
1143                    /* *INDENT-ON* */
1144            }
1145            else if (g_xserver_be)
1146            {
1147                    while (out < end)
1148                  {                  {
1149                          *(out++) = value >> 24;                          pixel = *(data++) << 16;
1150                          *(out++) = value >> 16;                          pixel |= *(data++) << 8;
1151                          *(out++) = value >> 8;                          pixel |= *(data++);
1152                          *(out++) = value;                          SPLITCOLOUR24(pixel, pc);
1153                            value = MAKECOLOUR(pc);
1154                            BOUT32(out, value);
1155                  }                  }
1156                  else          }
1157            else
1158            {
1159                    while (out < end)
1160                  {                  {
1161                          *(out++) = value;                          pixel = *(data++) << 16;
1162                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1163                          *(out++) = value >> 16;                          pixel |= *(data++);
1164                          *(out++) = value >> 24;                          SPLITCOLOUR24(pixel, pc);
1165                            value = MAKECOLOUR(pc);
1166                            LOUT32(out, value);
1167                  }                  }
1168          }          }
1169  }  }
# Line 597  translate24to32(uint8 * data, uint8 * ou Line 1171  translate24to32(uint8 * data, uint8 * ou
1171  static uint8 *  static uint8 *
1172  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1173  {  {
1174          int size = width * height * g_bpp / 8;          int size;
1175          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1176          uint8 *end = out + size;          uint8 *end;
1177    
1178            /*
1179               If RDP depth and X Visual depths match,
1180               and arch(endian) matches, no need to translate:
1181               just return data.
1182               Note: select_visual should've already ensured g_no_translate
1183               is only set for compatible depths, but the RDP depth might've
1184               changed during connection negotiations.
1185             */
1186            if (g_no_translate_image)
1187            {
1188                    if ((g_depth == 15 && g_server_depth == 15) ||
1189                        (g_depth == 16 && g_server_depth == 16) ||
1190                        (g_depth == 24 && g_server_depth == 24))
1191                            return data;
1192            }
1193    
1194            size = width * height * (g_bpp / 8);
1195            out = (uint8 *) xmalloc(size);
1196            end = out + size;
1197    
1198          switch (g_server_bpp)          switch (g_server_depth)
1199          {          {
1200                  case 24:                  case 24:
1201                          switch (g_bpp)                          switch (g_bpp)
# Line 666  translate_image(int width, int height, u Line 1260  translate_image(int width, int height, u
1260          return out;          return out;
1261  }  }
1262    
1263  BOOL  RD_BOOL
1264  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1265  {  {
1266          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 699  calculate_shifts(uint32 mask, int *shift Line 1293  calculate_shifts(uint32 mask, int *shift
1293          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1294  }  }
1295    
1296  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1297  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1298     */
1299    static unsigned
1300    calculate_mask_weight(uint32 mask)
1301    {
1302            unsigned weight = 0;
1303            do
1304            {
1305                    weight += (mask & 1);
1306            }
1307            while (mask >>= 1);
1308            return weight;
1309    }
1310    
1311    static RD_BOOL
1312    select_visual(int screen_num)
1313  {  {
         XVisualInfo vi;  
1314          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1315          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1316          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1317          XVisualInfo template;          XVisualInfo template;
1318          Bool TrueColorVisual = False;          int i;
1319            unsigned red_weight, blue_weight, green_weight;
1320    
1321          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1322          if (g_display == NULL)  
1323            if (g_server_depth == -1)
1324          {          {
1325                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1326          }          }
1327    
1328          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1329          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1330          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1331          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1332                    XCloseDisplay(g_display);
1333                    return False;
1334            }
1335    
1336          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1337          template.class = TrueColor;          template.class = TrueColor;
1338          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          template.screen = screen_num;
1339            vmatches =
1340                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1341                                   &visuals_count);
1342            g_visual = NULL;
1343            g_no_translate_image = False;
1344            g_compatible_arch = False;
1345            if (vmatches != NULL)
1346            {
1347                    for (i = 0; i < visuals_count; ++i)
1348                    {
1349                            XVisualInfo *visual_info = &vmatches[i];
1350                            RD_BOOL can_translate_to_bpp = False;
1351                            int j;
1352    
1353                            /* Try to find a no-translation visual that'll
1354                               allow us to use RDP bitmaps directly as ZPixmaps. */
1355                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1356                                                   /* R5G5B5 */
1357                                                   (visual_info->red_mask == 0x7c00) &&
1358                                                   (visual_info->green_mask == 0x3e0) &&
1359                                                   (visual_info->blue_mask == 0x1f)) ||
1360                                                  ((visual_info->depth == 16) &&
1361                                                   /* R5G6B5 */
1362                                                   (visual_info->red_mask == 0xf800) &&
1363                                                   (visual_info->green_mask == 0x7e0) &&
1364                                                   (visual_info->blue_mask == 0x1f)) ||
1365                                                  ((visual_info->depth == 24) &&
1366                                                   /* R8G8B8 */
1367                                                   (visual_info->red_mask == 0xff0000) &&
1368                                                   (visual_info->green_mask == 0xff00) &&
1369                                                   (visual_info->blue_mask == 0xff))))
1370                            {
1371                                    g_visual = visual_info->visual;
1372                                    g_depth = visual_info->depth;
1373                                    g_compatible_arch = !g_host_be;
1374                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1375                                    if (g_no_translate_image)
1376                                            /* We found the best visual */
1377                                            break;
1378                            }
1379                            else
1380                            {
1381                                    g_compatible_arch = False;
1382                            }
1383    
1384          nvisuals--;                          if (visual_info->depth > 24)
1385          while (nvisuals >= 0)                          {
1386          {                                  /* Avoid 32-bit visuals and likes like the plague.
1387                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1388                  {                                     (e.g. nvidia's Composite 32-bit visual).
1389                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1390                                    continue;
1391                            }
1392    
1393                            /* Only care for visuals, for whose BPPs (not depths!)
1394                               we have a translateXtoY function. */
1395                            for (j = 0; j < pixmap_formats_count; ++j)
1396                            {
1397                                    if (pfm[j].depth == visual_info->depth)
1398                                    {
1399                                            if ((pfm[j].bits_per_pixel == 16) ||
1400                                                (pfm[j].bits_per_pixel == 24) ||
1401                                                (pfm[j].bits_per_pixel == 32))
1402                                            {
1403                                                    can_translate_to_bpp = True;
1404                                            }
1405                                            break;
1406                                    }
1407                            }
1408    
1409                            /* Prefer formats which have the most colour depth.
1410                               We're being truly aristocratic here, minding each
1411                               weight on its own. */
1412                            if (can_translate_to_bpp)
1413                            {
1414                                    unsigned vis_red_weight =
1415                                            calculate_mask_weight(visual_info->red_mask);
1416                                    unsigned vis_green_weight =
1417                                            calculate_mask_weight(visual_info->green_mask);
1418                                    unsigned vis_blue_weight =
1419                                            calculate_mask_weight(visual_info->blue_mask);
1420                                    if ((vis_red_weight >= red_weight)
1421                                        && (vis_green_weight >= green_weight)
1422                                        && (vis_blue_weight >= blue_weight))
1423                                    {
1424                                            red_weight = vis_red_weight;
1425                                            green_weight = vis_green_weight;
1426                                            blue_weight = vis_blue_weight;
1427                                            g_visual = visual_info->visual;
1428                                            g_depth = visual_info->depth;
1429                                    }
1430                            }
1431                  }                  }
1432                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1433          }          }
1434    
1435          if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))          if (g_visual != NULL)
1436          {          {
1437                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1438                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1439                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1440                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
                 /* Do not allocate colours on a TrueColor visual */  
                 if (g_visual->class == TrueColor)  
                 {  
                         g_owncolmap = False;  
                 }  
1441          }          }
1442          else          else
1443          {          {
1444                  /* need a truecolour visual */                  template.class = PseudoColor;
1445                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1446                  {                  template.colormap_size = 256;
1447                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1448                            XGetVisualInfo(g_display,
1449                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1450                                           &template, &visuals_count);
1451                    if (vmatches == NULL)
1452                    {
1453                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1454                            XCloseDisplay(g_display);
1455                            XFree(pfm);
1456                          return False;                          return False;
1457                  }                  }
1458    
1459                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1460                  g_owncolmap = False;                  g_owncolmap = True;
1461                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1462                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
                 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);  
1463          }          }
1464    
1465          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1466          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1467          {          {
1468                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1469                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1470                  {                  {
1471                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1472    
1473                            if (g_no_translate_image)
1474                          {                          {
1475                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1476                                    {
1477                                            case 15:
1478                                            case 16:
1479                                                    if (g_bpp != 16)
1480                                                            g_no_translate_image = False;
1481                                                    break;
1482                                            case 24:
1483                                                    /* Yes, this will force image translation
1484                                                       on most modern servers which use 32 bits
1485                                                       for R8G8B8. */
1486                                                    if (g_bpp != 24)
1487                                                            g_no_translate_image = False;
1488                                                    break;
1489                                            default:
1490                                                    g_no_translate_image = False;
1491                                                    break;
1492                                    }
1493                          }                          }
1494    
1495                            /* Pixmap formats list is a depth-to-bpp mapping --
1496                               there's just a single entry for every depth,
1497                               so we can safely break here */
1498                            break;
1499                  }                  }
                 XFree(pfm);  
1500          }          }
1501            XFree(pfm);
1502            pfm = NULL;
1503            return True;
1504    }
1505    
1506          if (g_bpp < 8)  static XErrorHandler g_old_error_handler;
1507    
1508    static int
1509    error_handler(Display * dpy, XErrorEvent * eev)
1510    {
1511            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1512          {          {
1513                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1514                  XCloseDisplay(g_display);                  fprintf(stderr,
1515                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1516                    return 0;
1517            }
1518    
1519            return g_old_error_handler(dpy, eev);
1520    }
1521    
1522    RD_BOOL
1523    ui_init(void)
1524    {
1525            int screen_num;
1526    
1527            g_display = XOpenDisplay(NULL);
1528            if (g_display == NULL)
1529            {
1530                    error("Failed to open display: %s\n", XDisplayName(NULL));
1531                    return False;
1532            }
1533    
1534            {
1535                    uint16 endianess_test = 1;
1536                    g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1537            }
1538    
1539            g_old_error_handler = XSetErrorHandler(error_handler);
1540            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1541            screen_num = DefaultScreen(g_display);
1542            g_x_socket = ConnectionNumber(g_display);
1543            g_screen = ScreenOfDisplay(g_display, screen_num);
1544            g_depth = DefaultDepthOfScreen(g_screen);
1545    
1546            if (!select_visual(screen_num))
1547                  return False;                  return False;
1548    
1549            if (g_no_translate_image)
1550            {
1551                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1552            }
1553    
1554            if (g_server_depth > g_bpp)
1555            {
1556                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1557                            g_server_depth, g_bpp);
1558          }          }
1559    
1560            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1561                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1562    
1563          if (!g_owncolmap)          if (!g_owncolmap)
1564          {          {
1565                  g_xcolmap =                  g_xcolmap =
1566                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1567                                          AllocNone);                                          AllocNone);
1568                  if (g_depth <= 8)                  if (g_depth <= 8)
1569                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");                          warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1570          }          }
1571    
1572          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1573          {          {
1574                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1575                  g_ownbackstore = True;                  g_ownbackstore = True;
1576          }          }
1577    
         test = 1;  
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
1578          /*          /*
1579           * Determine desktop size           * Determine desktop size
1580           */           */
# Line 813  ui_init(void) Line 1582  ui_init(void)
1582          {          {
1583                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1584                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1585                    g_using_full_workarea = True;
1586          }          }
1587          else if (g_width < 0)          else if (g_width < 0)
1588          {          {
1589                  /* Percent of screen */                  /* Percent of screen */
1590                    if (-g_width >= 100)
1591                            g_using_full_workarea = True;
1592                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1593                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1594          }          }
# Line 824  ui_init(void) Line 1596  ui_init(void)
1596          {          {
1597                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1598                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1599                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1600                  {                  {
1601                          g_width = cx;                          g_width = cx;
1602                          g_height = cy;                          g_height = cy;
1603                            g_using_full_workarea = True;
1604                  }                  }
1605                  else                  else
1606                  {                  {
1607                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1608                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1609                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1610                  }                  }
1611          }          }
1612    
# Line 849  ui_init(void) Line 1621  ui_init(void)
1621                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1622    
1623          xclip_init();          xclip_init();
1624            ewmh_init();
1625            if (g_seamless_rdp)
1626                    seamless_init();
1627    
1628          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1629    
1630          return True;          return True;
1631  }  }
# Line 858  ui_init(void) Line 1633  ui_init(void)
1633  void  void
1634  ui_deinit(void)  ui_deinit(void)
1635  {  {
1636            while (g_seamless_windows)
1637            {
1638                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1639                    sw_remove_window(g_seamless_windows);
1640            }
1641    
1642            xclip_deinit();
1643    
1644          if (g_IM != NULL)          if (g_IM != NULL)
1645                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1646    
# Line 874  ui_deinit(void) Line 1657  ui_deinit(void)
1657          g_display = NULL;          g_display = NULL;
1658  }  }
1659    
1660  BOOL  
1661    static void
1662    get_window_attribs(XSetWindowAttributes * attribs)
1663    {
1664            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1665            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1666            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1667            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1668            attribs->override_redirect = g_fullscreen;
1669            attribs->colormap = g_xcolmap;
1670    }
1671    
1672    static void
1673    get_input_mask(long *input_mask)
1674    {
1675            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1676                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1677    
1678            if (g_sendmotion)
1679                    *input_mask |= PointerMotionMask;
1680            if (g_ownbackstore)
1681                    *input_mask |= ExposureMask;
1682            if (g_fullscreen || g_grab_keyboard)
1683                    *input_mask |= EnterWindowMask;
1684            if (g_grab_keyboard)
1685                    *input_mask |= LeaveWindowMask;
1686    }
1687    
1688    RD_BOOL
1689  ui_create_window(void)  ui_create_window(void)
1690  {  {
1691          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1692          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1693    
1694          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1695          XClassHint *classhints;          XClassHint *classhints;
1696          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 889  ui_create_window(void) Line 1701  ui_create_window(void)
1701          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1702          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1703    
1704          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1705          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1706          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1707          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1708          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1709    
1710          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,          get_window_attribs(&attribs);
1711                                0, g_depth, InputOutput, g_visual,  
1712                                CWBackPixel | CWBackingStore | CWOverrideRedirect |          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1713                                CWColormap | CWBorderPixel, &attribs);                                wndheight, 0, g_depth, InputOutput, g_visual,
1714                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1715                                  CWBorderPixel, &attribs);
1716    
1717          if (g_gc == NULL)          if (g_gc == NULL)
1718            {
1719                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1720                    ui_reset_clip();
1721            }
1722    
1723            if (g_create_bitmap_gc == NULL)
1724                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1725    
1726          if ((g_ownbackstore) && (g_backstore == 0))          if ((g_ownbackstore) && (g_backstore == 0))
1727          {          {
# Line 915  ui_create_window(void) Line 1735  ui_create_window(void)
1735          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1736    
1737          if (g_hide_decorations)          if (g_hide_decorations)
1738                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1739    
1740          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1741          if (classhints != NULL)          if (classhints != NULL)
# Line 929  ui_create_window(void) Line 1749  ui_create_window(void)
1749          if (sizehints)          if (sizehints)
1750          {          {
1751                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1752                    if (g_pos)
1753                            sizehints->flags |= PPosition;
1754                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1755                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1756                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1757                  XFree(sizehints);                  XFree(sizehints);
1758          }          }
1759    
1760          if ( g_embed_wnd )          if (g_embed_wnd)
1761          {          {
1762                  XReparentWindow(g_display, g_wnd, (Window)g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1763          }          }
   
         input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |  
                 VisibilityChangeMask | FocusChangeMask;  
1764    
1765          if (g_sendmotion)          get_input_mask(&input_mask);
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
1766    
1767          if (g_IM != NULL)          if (g_IM != NULL)
1768          {          {
# Line 971  ui_create_window(void) Line 1783  ui_create_window(void)
1783                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1784          }          }
1785          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1786            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1787    
1788          g_focused = False;          g_focused = False;
1789          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 988  ui_create_window(void) Line 1801  ui_create_window(void)
1801  }  }
1802    
1803  void  void
1804    ui_resize_window()
1805    {
1806            XSizeHints *sizehints;
1807            Pixmap bs;
1808    
1809            sizehints = XAllocSizeHints();
1810            if (sizehints)
1811            {
1812                    sizehints->flags = PMinSize | PMaxSize;
1813                    sizehints->min_width = sizehints->max_width = g_width;
1814                    sizehints->min_height = sizehints->max_height = g_height;
1815                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1816                    XFree(sizehints);
1817            }
1818    
1819            if (!(g_fullscreen || g_embed_wnd))
1820            {
1821                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1822            }
1823    
1824            /* create new backstore pixmap */
1825            if (g_backstore != 0)
1826            {
1827                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1828                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1829                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1830                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1831                    XFreePixmap(g_display, g_backstore);
1832                    g_backstore = bs;
1833            }
1834    }
1835    
1836    void
1837  ui_destroy_window(void)  ui_destroy_window(void)
1838  {  {
1839          if (g_IC != NULL)          if (g_IC != NULL)
# Line 1001  xwin_toggle_fullscreen(void) Line 1847  xwin_toggle_fullscreen(void)
1847  {  {
1848          Pixmap contents = 0;          Pixmap contents = 0;
1849    
1850            if (g_seamless_active)
1851                    /* Turn off SeamlessRDP mode */
1852                    ui_seamless_toggle();
1853    
1854          if (!g_ownbackstore)          if (!g_ownbackstore)
1855          {          {
1856                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1021  xwin_toggle_fullscreen(void) Line 1871  xwin_toggle_fullscreen(void)
1871          }          }
1872  }  }
1873    
1874  /* Process all events in Xlib queue  static void
1875    handle_button_event(XEvent xevent, RD_BOOL down)
1876    {
1877            uint16 button, flags = 0;
1878            g_last_gesturetime = xevent.xbutton.time;
1879            button = xkeymap_translate_button(xevent.xbutton.button);
1880            if (button == 0)
1881                    return;
1882    
1883            if (down)
1884                    flags = MOUSE_FLAG_DOWN;
1885    
1886            /* Stop moving window when button is released, regardless of cursor position */
1887            if (g_moving_wnd && (xevent.type == ButtonRelease))
1888                    g_moving_wnd = False;
1889    
1890            /* If win_button_size is nonzero, enable single app mode */
1891            if (xevent.xbutton.y < g_win_button_size)
1892            {
1893                    /*  Check from right to left: */
1894                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1895                    {
1896                            /* The close button, continue */
1897                            ;
1898                    }
1899                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1900                    {
1901                            /* The maximize/restore button. Do not send to
1902                               server.  It might be a good idea to change the
1903                               cursor or give some other visible indication
1904                               that rdesktop inhibited this click */
1905                            if (xevent.type == ButtonPress)
1906                                    return;
1907                    }
1908                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1909                    {
1910                            /* The minimize button. Iconify window. */
1911                            if (xevent.type == ButtonRelease)
1912                            {
1913                                    /* Release the mouse button outside the minimize button, to prevent the
1914                                       actual minimazation to happen */
1915                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1916                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1917                                    return;
1918                            }
1919                    }
1920                    else if (xevent.xbutton.x <= g_win_button_size)
1921                    {
1922                            /* The system menu. Ignore. */
1923                            if (xevent.type == ButtonPress)
1924                                    return;
1925                    }
1926                    else
1927                    {
1928                            /* The title bar. */
1929                            if (xevent.type == ButtonPress)
1930                            {
1931                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1932                                    {
1933                                            g_moving_wnd = True;
1934                                            g_move_x_offset = xevent.xbutton.x;
1935                                            g_move_y_offset = xevent.xbutton.y;
1936                                    }
1937                                    return;
1938                            }
1939                    }
1940            }
1941    
1942            if (xevent.xmotion.window == g_wnd)
1943            {
1944                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1945                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1946            }
1947            else
1948            {
1949                    /* SeamlessRDP */
1950                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1951                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1952            }
1953    }
1954    
1955    
1956    /* Process events in Xlib queue
1957     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1958  static int  static int
1959  xwin_process_events(void)  xwin_process_events(void)
1960  {  {
1961          XEvent xevent;          XEvent xevent;
1962          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1963          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1964          char str[256];          char str[256];
1965          Status status;          Status status;
1966            int events = 0;
1967            seamless_window *sw;
1968    
1969          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1970          {          {
1971                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1972    
# Line 1044  xwin_process_events(void) Line 1976  xwin_process_events(void)
1976                          continue;                          continue;
1977                  }                  }
1978    
                 flags = 0;  
   
1979                  switch (xevent.type)                  switch (xevent.type)
1980                  {                  {
1981                            case VisibilityNotify:
1982                                    if (xevent.xvisibility.window == g_wnd)
1983                                            g_Unobscured =
1984                                                    xevent.xvisibility.state == VisibilityUnobscured;
1985    
1986                                    break;
1987                          case ClientMessage:                          case ClientMessage:
1988                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
1989                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 1079  xwin_process_events(void) Line 2015  xwin_process_events(void)
2015                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2016                                  }                                  }
2017    
2018                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2019                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2020    
2021                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2022                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2023                                          break;                                          break;
2024    
2025                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2026                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
2027                                  break;                                  break;
2028    
2029                          case KeyRelease:                          case KeyRelease:
# Line 1104  xwin_process_events(void) Line 2031  xwin_process_events(void)
2031                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2032                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2033    
2034                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2035                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2036    
2037                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2038                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2039                                          break;                                          break;
2040    
2041                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2042                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2043                                  break;                                  break;
2044    
2045                          case ButtonPress:                          case ButtonPress:
2046                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2047                                  /* fall through */                                  break;
2048    
2049                          case ButtonRelease:                          case ButtonRelease:
2050                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
2051                                  break;                                  break;
2052    
2053                          case MotionNotify:                          case MotionNotify:
# Line 1197  xwin_process_events(void) Line 2062  xwin_process_events(void)
2062                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2063                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2064                                                         CurrentTime);                                                         CurrentTime);
2065                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2066                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2067                                    {
2068                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2069                                                           xevent.xmotion.x, xevent.xmotion.y);
2070                                    }
2071                                    else
2072                                    {
2073                                            /* SeamlessRDP */
2074                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2075                                                           xevent.xmotion.x_root,
2076                                                           xevent.xmotion.y_root);
2077                                    }
2078                                  break;                                  break;
2079    
2080                          case FocusIn:                          case FocusIn:
# Line 1209  xwin_process_events(void) Line 2085  xwin_process_events(void)
2085                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2086                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2087                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2088    
2089                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2090                                    if (!sw)
2091                                            break;
2092    
2093                                    if (sw->id != g_seamless_focused)
2094                                    {
2095                                            seamless_send_focus(sw->id, 0);
2096                                            g_seamless_focused = sw->id;
2097                                    }
2098                                  break;                                  break;
2099    
2100                          case FocusOut:                          case FocusOut:
# Line 1241  xwin_process_events(void) Line 2127  xwin_process_events(void)
2127                                  break;                                  break;
2128    
2129                          case Expose:                          case Expose:
2130                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2131                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2132                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2133                                            xevent.xexpose.height,                                                    g_gc,
2134                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2135                                                      xevent.xexpose.width, xevent.xexpose.height,
2136                                                      xevent.xexpose.x, xevent.xexpose.y);
2137                                    }
2138                                    else
2139                                    {
2140                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2141                                            if (!sw)
2142                                                    break;
2143                                            XCopyArea(g_display, g_backstore,
2144                                                      xevent.xexpose.window, g_gc,
2145                                                      xevent.xexpose.x + sw->xoffset,
2146                                                      xevent.xexpose.y + sw->yoffset,
2147                                                      xevent.xexpose.width,
2148                                                      xevent.xexpose.height, xevent.xexpose.x,
2149                                                      xevent.xexpose.y);
2150                                    }
2151    
2152                                  break;                                  break;
2153    
2154                          case MappingNotify:                          case MappingNotify:
# Line 1274  xwin_process_events(void) Line 2177  xwin_process_events(void)
2177                                  break;                                  break;
2178                          case PropertyNotify:                          case PropertyNotify:
2179                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2180                                    if (xevent.xproperty.window == g_wnd)
2181                                            break;
2182                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2183                                            break;
2184    
2185                                    /* seamless */
2186                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2187                                    if (!sw)
2188                                            break;
2189    
2190                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2191                                        && (xevent.xproperty.state == PropertyNewValue))
2192                                    {
2193                                            sw->state = ewmh_get_window_state(sw->wnd);
2194                                            seamless_send_state(sw->id, sw->state, 0);
2195                                    }
2196    
2197                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2198                                        && (xevent.xproperty.state == PropertyNewValue))
2199                                    {
2200                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2201                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2202                                    }
2203    
2204                                    break;
2205                            case MapNotify:
2206                                    if (!g_seamless_active)
2207                                            rdp_send_client_window_status(1);
2208                                    break;
2209                            case UnmapNotify:
2210                                    if (!g_seamless_active)
2211                                            rdp_send_client_window_status(0);
2212                                    break;
2213                            case ConfigureNotify:
2214                                    if (!g_seamless_active)
2215                                            break;
2216    
2217                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2218                                    if (!sw)
2219                                            break;
2220    
2221                                    gettimeofday(sw->position_timer, NULL);
2222                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2223                                        1000000)
2224                                    {
2225                                            sw->position_timer->tv_usec +=
2226                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2227                                            sw->position_timer->tv_sec += 1;
2228                                    }
2229                                    else
2230                                    {
2231                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2232                                    }
2233    
2234                                    sw_handle_restack(sw);
2235                                  break;                                  break;
2236                  }                  }
2237          }          }
# Line 1288  ui_select(int rdp_socket) Line 2246  ui_select(int rdp_socket)
2246          int n;          int n;
2247          fd_set rfds, wfds;          fd_set rfds, wfds;
2248          struct timeval tv;          struct timeval tv;
2249          BOOL s_timeout = False;          RD_BOOL s_timeout = False;
2250    
2251          while (True)          while (True)
2252          {          {
# Line 1298  ui_select(int rdp_socket) Line 2256  ui_select(int rdp_socket)
2256                          /* User quit */                          /* User quit */
2257                          return 0;                          return 0;
2258    
2259                    if (g_seamless_active)
2260                            sw_check_timers();
2261    
2262                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2263                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2264                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2265                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2266    
 #ifdef WITH_RDPSND  
                 /* FIXME: there should be an API for registering fds */  
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd > n) ? g_dsp_fd : n;  
                 }  
 #endif  
2267                  /* default timeout */                  /* default timeout */
2268                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2269                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2270    
2271    #ifdef WITH_RDPSND
2272                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2273    #endif
2274    
2275                  /* add redirection handles */                  /* add redirection handles */
2276                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2277                    seamless_select_timeout(&tv);
2278    
2279                  n++;                  n++;
2280    
# Line 1326  ui_select(int rdp_socket) Line 2284  ui_select(int rdp_socket)
2284                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2285    
2286                          case 0:                          case 0:
2287                                  /* TODO: if tv.tv_sec just times out  #ifdef WITH_RDPSND
2288                                   * we will segfault.                                  rdpsnd_check_fds(&rfds, &wfds);
2289                                   * FIXME:  #endif
2290                                   */  
2291                                  //s_timeout = True;                                  /* Abort serial read calls */
2292                                  //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                  if (s_timeout)
2293                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2294                                  continue;                                  continue;
2295                  }                  }
2296    
2297                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);  #ifdef WITH_RDPSND
2298                    rdpsnd_check_fds(&rfds, &wfds);
2299    #endif
2300    
2301                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2302    
2303                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2304                          return 1;                          return 1;
2305    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2306          }          }
2307  }  }
2308    
# Line 1353  ui_move_pointer(int x, int y) Line 2312  ui_move_pointer(int x, int y)
2312          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2313  }  }
2314    
2315  HBITMAP  RD_HBITMAP
2316  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2317  {  {
2318          XImage *image;          XImage *image;
# Line 1361  ui_create_bitmap(int width, int height, Line 2320  ui_create_bitmap(int width, int height,
2320          uint8 *tdata;          uint8 *tdata;
2321          int bitmap_pad;          int bitmap_pad;
2322    
2323          if (g_server_bpp == 8)          if (g_server_depth == 8)
2324          {          {
2325                  bitmap_pad = 8;                  bitmap_pad = 8;
2326          }          }
# Line 1378  ui_create_bitmap(int width, int height, Line 2337  ui_create_bitmap(int width, int height,
2337          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2338                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2339    
2340          XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2341    
2342          XFree(image);          XFree(image);
2343          if (!g_owncolmap)          if (tdata != data)
2344                  xfree(tdata);                  xfree(tdata);
2345          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2346  }  }
2347    
2348  void  void
# Line 1393  ui_paint_bitmap(int x, int y, int cx, in Line 2352  ui_paint_bitmap(int x, int y, int cx, in
2352          uint8 *tdata;          uint8 *tdata;
2353          int bitmap_pad;          int bitmap_pad;
2354    
2355          if (g_server_bpp == 8)          if (g_server_depth == 8)
2356          {          {
2357                  bitmap_pad = 8;                  bitmap_pad = 8;
2358          }          }
# Line 1413  ui_paint_bitmap(int x, int y, int cx, in Line 2372  ui_paint_bitmap(int x, int y, int cx, in
2372          {          {
2373                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2374                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2375                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2376                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2377                                             x - sw->xoffset, y - sw->yoffset));
2378          }          }
2379          else          else
2380          {          {
2381                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2382                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2383                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2384                                             x - sw->xoffset, y - sw->yoffset));
2385          }          }
2386    
2387          XFree(image);          XFree(image);
2388          if (!g_owncolmap)          if (tdata != data)
2389                  xfree(tdata);                  xfree(tdata);
2390  }  }
2391    
2392  void  void
2393  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2394  {  {
2395          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2396  }  }
2397    
2398  HGLYPH  RD_HGLYPH
2399  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2400  {  {
2401          XImage *image;          XImage *image;
2402          Pixmap bitmap;          Pixmap bitmap;
2403          int scanline;          int scanline;
         GC gc;  
2404    
2405          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2406    
2407          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2408          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2409                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2410    
2411          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2412                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1449  ui_create_glyph(int width, int height, u Line 2414  ui_create_glyph(int width, int height, u
2414          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2415          XInitImage(image);          XInitImage(image);
2416    
2417          XPutImage(g_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);
2418    
2419          XFree(image);          XFree(image);
2420          XFreeGC(g_display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH) bitmap;  
2421  }  }
2422    
2423  void  void
2424  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2425  {  {
2426          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2427  }  }
2428    
2429  HCURSOR  RD_HCURSOR
2430  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2431                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2432  {  {
2433          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2434          XColor bg, fg;          XColor bg, fg;
2435          Cursor xcursor;          Cursor xcursor;
2436          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1530  ui_create_cursor(unsigned int x, unsigne Line 2494  ui_create_cursor(unsigned int x, unsigne
2494          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2495          xfree(mask);          xfree(mask);
2496          xfree(cursor);          xfree(cursor);
2497          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2498  }  }
2499    
2500  void  void
2501  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2502  {  {
2503          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2504          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2505            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2506  }  }
2507    
2508  void  void
2509  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2510  {  {
2511          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2512  }  }
# Line 1559  ui_set_null_cursor(void) Line 2524  ui_set_null_cursor(void)
2524                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2525    
2526    
2527  HCOLOURMAP  RD_HCOLOURMAP
2528  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2529  {  {
2530          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1655  ui_create_colourmap(COLOURMAP * colours) Line 2620  ui_create_colourmap(COLOURMAP * colours)
2620                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2621    
2622                  xfree(xcolours);                  xfree(xcolours);
2623                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2624          }          }
2625  }  }
2626    
2627  void  void
2628  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2629  {  {
2630          if (!g_owncolmap)          if (!g_owncolmap)
2631                  xfree(map);                  xfree(map);
# Line 1669  ui_destroy_colourmap(HCOLOURMAP map) Line 2634  ui_destroy_colourmap(HCOLOURMAP map)
2634  }  }
2635    
2636  void  void
2637  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2638  {  {
2639          if (!g_owncolmap)          if (!g_owncolmap)
2640          {          {
# Line 1679  ui_set_colourmap(HCOLOURMAP map) Line 2644  ui_set_colourmap(HCOLOURMAP map)
2644                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2645          }          }
2646          else          else
2647            {
2648                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2649                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2650            }
2651  }  }
2652    
2653  void  void
2654  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2655  {  {
2656          XRectangle rect;          g_clip_rectangle.x = x;
2657            g_clip_rectangle.y = y;
2658          rect.x = x;          g_clip_rectangle.width = cx;
2659          rect.y = y;          g_clip_rectangle.height = cy;
2660          rect.width = cx;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = cy;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
2661  }  }
2662    
2663  void  void
2664  ui_reset_clip(void)  ui_reset_clip(void)
2665  {  {
2666          XRectangle rect;          g_clip_rectangle.x = 0;
2667            g_clip_rectangle.y = 0;
2668          rect.x = 0;          g_clip_rectangle.width = g_width;
2669          rect.y = 0;          g_clip_rectangle.height = g_height;
2670          rect.width = g_width;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = g_height;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
2671  }  }
2672    
2673  void  void
# Line 1744  ui_patblt(uint8 opcode, Line 2708  ui_patblt(uint8 opcode,
2708          {          {
2709                  case 0: /* Solid */                  case 0: /* Solid */
2710                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2711                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2712                          break;                          break;
2713    
2714                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1755  ui_patblt(uint8 opcode, Line 2719  ui_patblt(uint8 opcode,
2719                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2720                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2721                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2722                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2723                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2724                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2725                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2726                          break;                          break;
2727    
2728                  case 3: /* Pattern */                  case 3: /* Pattern */
2729                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2730                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2731                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2732                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2733                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2734                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2735                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2736                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2737                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
2738                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2739                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2740                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2741                          break;                          break;
2742    
2743                  default:                  default:
# Line 1784  ui_patblt(uint8 opcode, Line 2745  ui_patblt(uint8 opcode,
2745          }          }
2746    
2747          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2748    
2749            if (g_ownbackstore)
2750                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2751            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2752                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2753                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2754  }  }
2755    
2756  void  void
# Line 1794  ui_screenblt(uint8 opcode, Line 2761  ui_screenblt(uint8 opcode,
2761          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2762          if (g_ownbackstore)          if (g_ownbackstore)
2763          {          {
2764                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2765                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2766                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2767          }          }
2768          else          else
2769          {          {
2770                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2771          }          }
2772    
2773            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2774                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2775                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2776    
2777          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2778  }  }
2779    
2780  void  void
2781  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
2782            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2783            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
2784  {  {
2785          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2786          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2787            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2788                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2789                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2790          if (g_ownbackstore)          if (g_ownbackstore)
2791                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2792          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1819  ui_memblt(uint8 opcode, Line 2795  ui_memblt(uint8 opcode,
2795  void  void
2796  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2797            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2798            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
2799            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2800  {  {
2801          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1857  ui_line(uint8 opcode, Line 2833  ui_line(uint8 opcode,
2833          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2834          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2835          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2836            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2837                                                startx - sw->xoffset, starty - sw->yoffset,
2838                                                endx - sw->xoffset, endy - sw->yoffset));
2839          if (g_ownbackstore)          if (g_ownbackstore)
2840                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2841          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1871  ui_rect( Line 2850  ui_rect(
2850          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2851  }  }
2852    
2853    void
2854    ui_polygon(uint8 opcode,
2855               /* mode */ uint8 fillmode,
2856               /* dest */ RD_POINT * point, int npoints,
2857               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2858    {
2859            uint8 style, i, ipattern[8];
2860            Pixmap fill;
2861    
2862            SET_FUNCTION(opcode);
2863    
2864            switch (fillmode)
2865            {
2866                    case ALTERNATE:
2867                            XSetFillRule(g_display, g_gc, EvenOddRule);
2868                            break;
2869                    case WINDING:
2870                            XSetFillRule(g_display, g_gc, WindingRule);
2871                            break;
2872                    default:
2873                            unimpl("fill mode %d\n", fillmode);
2874            }
2875    
2876            if (brush)
2877                    style = brush->style;
2878            else
2879                    style = 0;
2880    
2881            switch (style)
2882            {
2883                    case 0: /* Solid */
2884                            SET_FOREGROUND(fgcolour);
2885                            FILL_POLYGON((XPoint *) point, npoints);
2886                            break;
2887    
2888                    case 2: /* Hatch */
2889                            fill = (Pixmap) ui_create_glyph(8, 8,
2890                                                            hatch_patterns + brush->pattern[0] * 8);
2891                            SET_FOREGROUND(fgcolour);
2892                            SET_BACKGROUND(bgcolour);
2893                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2894                            XSetStipple(g_display, g_gc, fill);
2895                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2896                            FILL_POLYGON((XPoint *) point, npoints);
2897                            XSetFillStyle(g_display, g_gc, FillSolid);
2898                            XSetTSOrigin(g_display, g_gc, 0, 0);
2899                            ui_destroy_glyph((RD_HGLYPH) fill);
2900                            break;
2901    
2902                    case 3: /* Pattern */
2903                            for (i = 0; i != 8; i++)
2904                                    ipattern[7 - i] = brush->pattern[i];
2905                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2906                            SET_FOREGROUND(bgcolour);
2907                            SET_BACKGROUND(fgcolour);
2908                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2909                            XSetStipple(g_display, g_gc, fill);
2910                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2911                            FILL_POLYGON((XPoint *) point, npoints);
2912                            XSetFillStyle(g_display, g_gc, FillSolid);
2913                            XSetTSOrigin(g_display, g_gc, 0, 0);
2914                            ui_destroy_glyph((RD_HGLYPH) fill);
2915                            break;
2916    
2917                    default:
2918                            unimpl("brush %d\n", brush->style);
2919            }
2920    
2921            RESET_FUNCTION(opcode);
2922    }
2923    
2924    void
2925    ui_polyline(uint8 opcode,
2926                /* dest */ RD_POINT * points, int npoints,
2927                /* pen */ PEN * pen)
2928    {
2929            /* TODO: set join style */
2930            SET_FUNCTION(opcode);
2931            SET_FOREGROUND(pen->colour);
2932            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2933            if (g_ownbackstore)
2934                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2935                               CoordModePrevious);
2936    
2937            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2938                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2939    
2940            RESET_FUNCTION(opcode);
2941    }
2942    
2943    void
2944    ui_ellipse(uint8 opcode,
2945               /* mode */ uint8 fillmode,
2946               /* dest */ int x, int y, int cx, int cy,
2947               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2948    {
2949            uint8 style, i, ipattern[8];
2950            Pixmap fill;
2951    
2952            SET_FUNCTION(opcode);
2953    
2954            if (brush)
2955                    style = brush->style;
2956            else
2957                    style = 0;
2958    
2959            switch (style)
2960            {
2961                    case 0: /* Solid */
2962                            SET_FOREGROUND(fgcolour);
2963                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2964                            break;
2965    
2966                    case 2: /* Hatch */
2967                            fill = (Pixmap) ui_create_glyph(8, 8,
2968                                                            hatch_patterns + brush->pattern[0] * 8);
2969                            SET_FOREGROUND(fgcolour);
2970                            SET_BACKGROUND(bgcolour);
2971                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2972                            XSetStipple(g_display, g_gc, fill);
2973                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2974                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2975                            XSetFillStyle(g_display, g_gc, FillSolid);
2976                            XSetTSOrigin(g_display, g_gc, 0, 0);
2977                            ui_destroy_glyph((RD_HGLYPH) fill);
2978                            break;
2979    
2980                    case 3: /* Pattern */
2981                            for (i = 0; i != 8; i++)
2982                                    ipattern[7 - i] = brush->pattern[i];
2983                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2984                            SET_FOREGROUND(bgcolour);
2985                            SET_BACKGROUND(fgcolour);
2986                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2987                            XSetStipple(g_display, g_gc, fill);
2988                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2989                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2990                            XSetFillStyle(g_display, g_gc, FillSolid);
2991                            XSetTSOrigin(g_display, g_gc, 0, 0);
2992                            ui_destroy_glyph((RD_HGLYPH) fill);
2993                            break;
2994    
2995                    default:
2996                            unimpl("brush %d\n", brush->style);
2997            }
2998    
2999            RESET_FUNCTION(opcode);
3000    }
3001    
3002  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3003  void  void
3004  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3005                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3006                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3007                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3008  {  {
3009          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1926  ui_draw_glyph(int mixmode, Line 3054  ui_draw_glyph(int mixmode,
3054  }  }
3055    
3056  void  void
3057  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,
3058               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3059               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3060               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3061  {  {
3062            /* TODO: use brush appropriately */
3063    
3064          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3065          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
3066          DATABLOB *entry;          DATABLOB *entry;
# Line 1962  ui_draw_text(uint8 font, uint8 flags, in Line 3092  ui_draw_text(uint8 font, uint8 flags, in
3092                  switch (text[i])                  switch (text[i])
3093                  {                  {
3094                          case 0xff:                          case 0xff:
3095                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3096                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3097                                  {                                  {
3098                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3099                                          exit(1);                                          for (j = 0; j < length; j++)
3100                                                    fprintf(stderr, "%02x ", text[j]);
3101                                            fprintf(stderr, "\n");
3102                                            i = length = 0;
3103                                            break;
3104                                  }                                  }
3105                                    cache_put_text(text[i + 1], text, text[i + 2]);
3106                                    i += 3;
3107                                    length -= i;
3108                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3109                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3110                                  i = 0;                                  i = 0;
3111                                  break;                                  break;
3112    
3113                          case 0xfe:                          case 0xfe:
3114                                    /* At least one byte needs to follow */
3115                                    if (i + 2 > length)
3116                                    {
3117                                            warning("Skipping short 0xfe command:");
3118                                            for (j = 0; j < length; j++)
3119                                                    fprintf(stderr, "%02x ", text[j]);
3120                                            fprintf(stderr, "\n");
3121                                            i = length = 0;
3122                                            break;
3123                                    }
3124                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3125                                  if (entry != NULL)                                  if (entry->data != NULL)
3126                                  {                                  {
3127                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3128                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3129                                          {                                          {
3130                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3131                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2012  ui_draw_text(uint8 font, uint8 flags, in Line 3157  ui_draw_text(uint8 font, uint8 flags, in
3157          if (g_ownbackstore)          if (g_ownbackstore)
3158          {          {
3159                  if (boxcx > 1)                  if (boxcx > 1)
3160                    {
3161                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3162                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3163                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3164                                                    (g_display, g_backstore, sw->wnd, g_gc,
3165                                                     boxx, boxy,
3166                                                     boxcx, boxcy,
3167                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3168                    }
3169                  else                  else
3170                    {
3171                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3172                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3173                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3174                                                    (g_display, g_backstore, sw->wnd, g_gc,
3175                                                     clipx, clipy,
3176                                                     clipcx, clipcy, clipx - sw->xoffset,
3177                                                     clipy - sw->yoffset));
3178                    }
3179          }          }
3180  }  }
3181    
# Line 2029  ui_desktop_save(uint32 offset, int x, in Line 3188  ui_desktop_save(uint32 offset, int x, in
3188          if (g_ownbackstore)          if (g_ownbackstore)
3189          {          {
3190                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3191                    exit_if_null(image);
3192          }          }
3193          else          else
3194          {          {
3195                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3196                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3197                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3198                    exit_if_null(image);
3199                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3200          }          }
3201    
# Line 2062  ui_desktop_restore(uint32 offset, int x, Line 3223  ui_desktop_restore(uint32 offset, int x,
3223          {          {
3224                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3225                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3226                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3227                                            (g_display, g_backstore, sw->wnd, g_gc,
3228                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3229          }          }
3230          else          else
3231          {          {
3232                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3233                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3234                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3235                                             x - sw->xoffset, y - sw->yoffset));
3236          }          }
3237    
3238          XFree(image);          XFree(image);
3239  }  }
3240    
3241    /* these do nothing here but are used in uiports */
3242    void
3243    ui_begin_update(void)
3244    {
3245    }
3246    
3247    void
3248    ui_end_update(void)
3249    {
3250    }
3251    
3252    
3253    void
3254    ui_seamless_begin(RD_BOOL hidden)
3255    {
3256            if (!g_seamless_rdp)
3257                    return;
3258    
3259            if (g_seamless_started)
3260                    return;
3261    
3262            g_seamless_started = True;
3263            g_seamless_hidden = hidden;
3264    
3265            if (!hidden)
3266                    ui_seamless_toggle();
3267    }
3268    
3269    
3270    void
3271    ui_seamless_hide_desktop()
3272    {
3273            if (!g_seamless_rdp)
3274                    return;
3275    
3276            if (!g_seamless_started)
3277                    return;
3278    
3279            if (g_seamless_active)
3280                    ui_seamless_toggle();
3281    
3282            g_seamless_hidden = True;
3283    }
3284    
3285    
3286    void
3287    ui_seamless_unhide_desktop()
3288    {
3289            if (!g_seamless_rdp)
3290                    return;
3291    
3292            if (!g_seamless_started)
3293                    return;
3294    
3295            g_seamless_hidden = False;
3296    
3297            ui_seamless_toggle();
3298    }
3299    
3300    
3301    void
3302    ui_seamless_toggle()
3303    {
3304            if (!g_seamless_rdp)
3305                    return;
3306    
3307            if (!g_seamless_started)
3308                    return;
3309    
3310            if (g_seamless_hidden)
3311                    return;
3312    
3313            if (g_seamless_active)
3314            {
3315                    /* Deactivate */
3316                    while (g_seamless_windows)
3317                    {
3318                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3319                            sw_remove_window(g_seamless_windows);
3320                    }
3321                    XMapWindow(g_display, g_wnd);
3322            }
3323            else
3324            {
3325                    /* Activate */
3326                    XUnmapWindow(g_display, g_wnd);
3327                    seamless_send_sync();
3328            }
3329    
3330            g_seamless_active = !g_seamless_active;
3331    }
3332    
3333    
3334    void
3335    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3336                              unsigned long flags)
3337    {
3338            Window wnd;
3339            XSetWindowAttributes attribs;
3340            XClassHint *classhints;
3341            XSizeHints *sizehints;
3342            XWMHints *wmhints;
3343            long input_mask;
3344            seamless_window *sw, *sw_parent;
3345    
3346            if (!g_seamless_active)
3347                    return;
3348    
3349            /* Ignore CREATEs for existing windows */
3350            sw = sw_get_window_by_id(id);
3351            if (sw)
3352                    return;
3353    
3354            get_window_attribs(&attribs);
3355            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3356                                InputOutput, g_visual,
3357                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3358    
3359            XStoreName(g_display, wnd, "SeamlessRDP");
3360            ewmh_set_wm_name(wnd, "SeamlessRDP");
3361    
3362            mwm_hide_decorations(wnd);
3363    
3364            classhints = XAllocClassHint();
3365            if (classhints != NULL)
3366            {
3367                    classhints->res_name = "rdesktop";
3368                    classhints->res_class = "SeamlessRDP";
3369                    XSetClassHint(g_display, wnd, classhints);
3370                    XFree(classhints);
3371            }
3372    
3373            /* WM_NORMAL_HINTS */
3374            sizehints = XAllocSizeHints();
3375            if (sizehints != NULL)
3376            {
3377                    sizehints->flags = USPosition;
3378                    XSetWMNormalHints(g_display, wnd, sizehints);
3379                    XFree(sizehints);
3380            }
3381    
3382            /* Parent-less transient windows */
3383            if (parent == 0xFFFFFFFF)
3384            {
3385                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3386                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3387                       using some other hints. */
3388                    ewmh_set_window_popup(wnd);
3389            }
3390            /* Normal transient windows */
3391            else if (parent != 0x00000000)
3392            {
3393                    sw_parent = sw_get_window_by_id(parent);
3394                    if (sw_parent)
3395                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3396                    else
3397                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3398            }
3399    
3400            if (flags & SEAMLESSRDP_CREATE_MODAL)
3401            {
3402                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3403                       somewhat at least */
3404                    if (parent == 0x00000000)
3405                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3406                    ewmh_set_window_modal(wnd);
3407            }
3408    
3409            /* FIXME: Support for Input Context:s */
3410    
3411            get_input_mask(&input_mask);
3412            input_mask |= PropertyChangeMask;
3413    
3414            XSelectInput(g_display, wnd, input_mask);
3415    
3416            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3417               seamless window, we could try to close the window on the
3418               serverside, instead of terminating rdesktop */
3419            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3420    
3421            sw = xmalloc(sizeof(seamless_window));
3422            sw->wnd = wnd;
3423            sw->id = id;
3424            sw->behind = 0;
3425            sw->group = sw_find_group(group, False);
3426            sw->group->refcnt++;
3427            sw->xoffset = 0;
3428            sw->yoffset = 0;
3429            sw->width = 0;
3430            sw->height = 0;
3431            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3432            sw->desktop = 0;
3433            sw->position_timer = xmalloc(sizeof(struct timeval));
3434            timerclear(sw->position_timer);
3435    
3436            sw->outstanding_position = False;
3437            sw->outpos_serial = 0;
3438            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3439            sw->outpos_width = sw->outpos_height = 0;
3440    
3441            sw->next = g_seamless_windows;
3442            g_seamless_windows = sw;
3443    
3444            /* WM_HINTS */
3445            wmhints = XAllocWMHints();
3446            if (wmhints)
3447            {
3448                    wmhints->flags = WindowGroupHint;
3449                    wmhints->window_group = sw->group->wnd;
3450                    XSetWMHints(g_display, sw->wnd, wmhints);
3451                    XFree(wmhints);
3452            }
3453    }
3454    
3455    
3456    void
3457    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3458    {
3459            seamless_window *sw;
3460    
3461            if (!g_seamless_active)
3462                    return;
3463    
3464            sw = sw_get_window_by_id(id);
3465            if (!sw)
3466            {
3467                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3468                    return;
3469            }
3470    
3471            XDestroyWindow(g_display, sw->wnd);
3472            sw_remove_window(sw);
3473    }
3474    
3475    
3476    void
3477    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3478    {
3479            seamless_window *sw, *sw_next;
3480    
3481            if (!g_seamless_active)
3482                    return;
3483    
3484            for (sw = g_seamless_windows; sw; sw = sw_next)
3485            {
3486                    sw_next = sw->next;
3487    
3488                    if (sw->group->id == id)
3489                    {
3490                            XDestroyWindow(g_display, sw->wnd);
3491                            sw_remove_window(sw);
3492                    }
3493            }
3494    }
3495    
3496    
3497    void
3498    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3499    {
3500            seamless_window *sw;
3501    
3502            if (!g_seamless_active)
3503                    return;
3504    
3505            sw = sw_get_window_by_id(id);
3506            if (!sw)
3507            {
3508                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3509                    return;
3510            }
3511    
3512            /* We ignore server updates until it has handled our request. */
3513            if (sw->outstanding_position)
3514                    return;
3515    
3516            if (!width || !height)
3517                    /* X11 windows must be at least 1x1 */
3518                    return;
3519    
3520            sw->xoffset = x;
3521            sw->yoffset = y;
3522            sw->width = width;
3523            sw->height = height;
3524    
3525            /* If we move the window in a maximized state, then KDE won't
3526               accept restoration */
3527            switch (sw->state)
3528            {
3529                    case SEAMLESSRDP_MINIMIZED:
3530                    case SEAMLESSRDP_MAXIMIZED:
3531                            return;
3532            }
3533    
3534            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3535            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3536    }
3537    
3538    
3539    void
3540    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3541    {
3542            seamless_window *sw;
3543    
3544            if (!g_seamless_active)
3545                    return;
3546    
3547            sw = sw_get_window_by_id(id);
3548            if (!sw)
3549            {
3550                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3551                    return;
3552            }
3553    
3554            if (behind)
3555            {
3556                    seamless_window *sw_behind;
3557                    Window wnds[2];
3558    
3559                    sw_behind = sw_get_window_by_id(behind);
3560                    if (!sw_behind)
3561                    {
3562                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3563                                    behind);
3564                            return;
3565                    }
3566    
3567                    wnds[1] = sw_behind->wnd;
3568                    wnds[0] = sw->wnd;
3569    
3570                    XRestackWindows(g_display, wnds, 2);
3571            }
3572            else
3573            {
3574                    XRaiseWindow(g_display, sw->wnd);
3575            }
3576    
3577            sw_restack_window(sw, behind);
3578    }
3579    
3580    
3581    void
3582    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3583    {
3584            seamless_window *sw;
3585    
3586            if (!g_seamless_active)
3587                    return;
3588    
3589            sw = sw_get_window_by_id(id);
3590            if (!sw)
3591            {
3592                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3593                    return;
3594            }
3595    
3596            /* FIXME: Might want to convert the name for non-EWMH WMs */
3597            XStoreName(g_display, sw->wnd, title);
3598            ewmh_set_wm_name(sw->wnd, title);
3599    }
3600    
3601    
3602    void
3603    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3604    {
3605            seamless_window *sw;
3606    
3607            if (!g_seamless_active)
3608                    return;
3609    
3610            sw = sw_get_window_by_id(id);
3611            if (!sw)
3612            {
3613                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3614                    return;
3615            }
3616    
3617            switch (state)
3618            {
3619                    case SEAMLESSRDP_NORMAL:
3620                    case SEAMLESSRDP_MAXIMIZED:
3621                            ewmh_change_state(sw->wnd, state);
3622                            XMapWindow(g_display, sw->wnd);
3623                            break;
3624                    case SEAMLESSRDP_MINIMIZED:
3625                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3626                               the Window Manager should probably just ignore the request, since
3627                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3628                               such as minimization, rather than an independent state." Besides,
3629                               XIconifyWindow is easier. */
3630                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3631                            {
3632                                    XWMHints *hints;
3633                                    hints = XGetWMHints(g_display, sw->wnd);
3634                                    if (hints)
3635                                    {
3636                                            hints->flags |= StateHint;
3637                                            hints->initial_state = IconicState;
3638                                            XSetWMHints(g_display, sw->wnd, hints);
3639                                            XFree(hints);
3640                                    }
3641                                    XMapWindow(g_display, sw->wnd);
3642                            }
3643                            else
3644                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3645                            break;
3646                    default:
3647                            warning("SeamlessRDP: Invalid state %d\n", state);
3648                            break;
3649            }
3650    
3651            sw->state = state;
3652    }
3653    
3654    
3655    void
3656    ui_seamless_syncbegin(unsigned long flags)
3657    {
3658            if (!g_seamless_active)
3659                    return;
3660    
3661            /* Destroy all seamless windows */
3662            while (g_seamless_windows)
3663            {
3664                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3665                    sw_remove_window(g_seamless_windows);
3666            }
3667    }
3668    
3669    
3670    void
3671    ui_seamless_ack(unsigned int serial)
3672    {
3673            seamless_window *sw;
3674            for (sw = g_seamless_windows; sw; sw = sw->next)
3675            {
3676                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3677                    {
3678                            sw->xoffset = sw->outpos_xoffset;
3679                            sw->yoffset = sw->outpos_yoffset;
3680                            sw->width = sw->outpos_width;
3681                            sw->height = sw->outpos_height;
3682                            sw->outstanding_position = False;
3683    
3684                            /* Do a complete redraw of the window as part of the
3685                               completion of the move. This is to remove any
3686                               artifacts caused by our lack of synchronization. */
3687                            XCopyArea(g_display, g_backstore,
3688                                      sw->wnd, g_gc,
3689                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3690    
3691                            break;
3692                    }
3693            }
3694    }

Legend:
Removed from v.643  
changed lines
  Added in v.1372

  ViewVC Help
Powered by ViewVC 1.1.26