/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

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

sourceforge.net/trunk/rdesktop/xwin.c revision 644 by jsorg71, Thu Mar 25 22:58:45 2004 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1182 by ossman_, Tue Mar 21 15:31:48 2006 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-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 28  Line 28 
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31    /* We can't include Xproto.h because of conflicting defines for BOOL */
32    #define X_ConfigureWindow              12
33    
34  extern int g_width;  extern int g_width;
35  extern int g_height;  extern int g_height;
36    extern int g_xpos;
37    extern int g_ypos;
38    extern int g_pos;
39  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
40  extern BOOL g_fullscreen;  extern BOOL g_fullscreen;
41  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
42  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
43  extern char g_title[];  extern char g_title[];
44  extern int g_server_bpp;  /* Color depth of the RDP session.
45       As of RDP 5.1, it may be 8, 15, 16 or 24. */
46    extern int g_server_depth;
47  extern int g_win_button_size;  extern int g_win_button_size;
48    
49  Display *g_display;  Display *g_display;
# Line 43  Time g_last_gesturetime; Line 51  Time g_last_gesturetime;
51  static int g_x_socket;  static int g_x_socket;
52  static Screen *g_screen;  static Screen *g_screen;
53  Window g_wnd;  Window g_wnd;
54  uint32 g_embed_wnd;  
55    /* SeamlessRDP support */
56    typedef struct _seamless_group
57    {
58            Window wnd;
59            unsigned long id;
60            unsigned int refcnt;
61    } seamless_group;
62    typedef struct _seamless_window
63    {
64            Window wnd;
65            unsigned long id;
66            unsigned long behind;
67            seamless_group *group;
68            int xoffset, yoffset;
69            int width, height;
70            int state;              /* normal/minimized/maximized. */
71            unsigned int desktop;
72            struct timeval *position_timer;
73    
74            BOOL outstanding_position;
75            unsigned int outpos_serial;
76            int outpos_xoffset, outpos_yoffset;
77            int outpos_width, outpos_height;
78    
79            struct _seamless_window *next;
80    } seamless_window;
81    static seamless_window *g_seamless_windows = NULL;
82    static unsigned long g_seamless_focused = 0;
83    static BOOL g_seamless_started = False; /* Server end is up and running */
84    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
85    extern BOOL g_seamless_rdp;
86    
87    extern uint32 g_embed_wnd;
88  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
89    BOOL g_Unobscured;              /* used for screenblt */
90  static GC g_gc = NULL;  static GC g_gc = NULL;
91    static GC g_create_bitmap_gc = NULL;
92    static GC g_create_glyph_gc = NULL;
93    static XRectangle g_clip_rectangle;
94  static Visual *g_visual;  static Visual *g_visual;
95    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
96       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
97       as far as we're concerned. */
98  static int g_depth;  static int g_depth;
99    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
100       This may be larger than g_depth, in which case some of the bits would
101       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
102  static int g_bpp;  static int g_bpp;
103  static XIM g_IM;  static XIM g_IM;
104  static XIC g_IC;  static XIC g_IC;
# Line 55  static XModifierKeymap *g_mod_map; Line 106  static XModifierKeymap *g_mod_map;
106  static Cursor g_current_cursor;  static Cursor g_current_cursor;
107  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
108  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
109    extern Atom g_net_wm_state_atom;
110    extern Atom g_net_wm_desktop_atom;
111  static BOOL g_focused;  static BOOL g_focused;
112  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
113  static BOOL g_arch_match = False; /* set to True if RGB XServer and little endian */  /* Indicates that:
114       1) visual has 15, 16 or 24 depth and the same color channel masks
115          as its RDP equivalent (implies X server is LE),
116       2) host is LE
117       This will trigger an optimization whose real value is questionable.
118    */
119    static BOOL g_compatible_arch;
120    /* Indicates whether RDP's bitmaps and our XImages have the same
121       binary format. If so, we can avoid an expensive translation.
122       Note that this can be true when g_compatible_arch is false,
123       e.g.:
124      
125         RDP(LE) <-> host(BE) <-> X-Server(LE)
126        
127       ('host' is the machine running rdesktop; the host simply memcpy's
128        so its endianess doesn't matter)
129     */
130    static BOOL g_no_translate_image = False;
131    
132  /* endianness */  /* endianness */
133  static BOOL g_host_be;  static BOOL g_host_be;
# Line 66  static int g_red_shift_r, g_blue_shift_r Line 136  static int g_red_shift_r, g_blue_shift_r
136  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;
137    
138  /* software backing store */  /* software backing store */
139  BOOL g_ownbackstore = True;     /* We can't rely on external BackingStore */  extern BOOL g_ownbackstore;
140  static Pixmap g_backstore = 0;  static Pixmap g_backstore = 0;
141    
142  /* Moving in single app mode */  /* Moving in single app mode */
143  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
144  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
145  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
146    static BOOL g_using_full_workarea = False;
147    
148  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
149  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 85  extern BOOL g_rdpsnd; Line 156  extern BOOL g_rdpsnd;
156  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
157  typedef struct  typedef struct
158  {  {
159          uint32 flags;          unsigned long flags;
160          uint32 functions;          unsigned long functions;
161          uint32 decorations;          unsigned long decorations;
162          sint32 inputMode;          long inputMode;
163          uint32 status;          unsigned long status;
164  }  }
165  PropMotifWmHints;  PropMotifWmHints;
166    
# Line 101  typedef struct Line 172  typedef struct
172  }  }
173  PixelColour;  PixelColour;
174    
175    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
176            do { \
177                    seamless_window *sw; \
178                    XRectangle rect; \
179                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
180                        rect.x = g_clip_rectangle.x - sw->xoffset; \
181                        rect.y = g_clip_rectangle.y - sw->yoffset; \
182                        rect.width = g_clip_rectangle.width; \
183                        rect.height = g_clip_rectangle.height; \
184                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
185                        func args; \
186                    } \
187                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
188            } while (0)
189    
190    static void
191    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
192    {
193            points[0].x -= xoffset;
194            points[0].y -= yoffset;
195            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
196            points[0].x += xoffset;
197            points[0].y += yoffset;
198    }
199    
200    static void
201    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
202    {
203            points[0].x -= xoffset;
204            points[0].y -= yoffset;
205            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
206            points[0].x += xoffset;
207            points[0].y += yoffset;
208    }
209    
210  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
211  { \  { \
212          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
213            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
214          if (g_ownbackstore) \          if (g_ownbackstore) \
215                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
216  }  }
# Line 114  PixelColour; Line 220  PixelColour;
220          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); \
221  }  }
222    
223    #define FILL_POLYGON(p,np)\
224    { \
225            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
226            if (g_ownbackstore) \
227                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
228            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
229    }
230    
231    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
232    { \
233            switch (m) \
234            { \
235                    case 0: /* Outline */ \
236                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
237                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
238                            if (g_ownbackstore) \
239                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
240                            break; \
241                    case 1: /* Filled */ \
242                            XFillArc(g_display, g_wnd, g_gc, x, y, \
243                                     cx, cy, 0, 360*64); \
244                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
245                            if (g_ownbackstore) \
246                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
247                            break; \
248            } \
249    }
250    
251  /* colour maps */  /* colour maps */
252  BOOL g_owncolmap = False;  extern BOOL g_owncolmap;
253  static Colormap g_xcolmap;  static Colormap g_xcolmap;
254  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
255    
256  #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] )
257  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
258  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
259    
# Line 145  static int rop2_map[] = { Line 279  static int rop2_map[] = {
279  #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]); }
280  #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); }
281    
282    static seamless_window *
283    sw_get_window_by_id(unsigned long id)
284    {
285            seamless_window *sw;
286            for (sw = g_seamless_windows; sw; sw = sw->next)
287            {
288                    if (sw->id == id)
289                            return sw;
290            }
291            return NULL;
292    }
293    
294    
295    static seamless_window *
296    sw_get_window_by_wnd(Window wnd)
297    {
298            seamless_window *sw;
299            for (sw = g_seamless_windows; sw; sw = sw->next)
300            {
301                    if (sw->wnd == wnd)
302                            return sw;
303            }
304            return NULL;
305    }
306    
307    
308    static void
309    sw_remove_window(seamless_window * win)
310    {
311            seamless_window *sw, **prevnext = &g_seamless_windows;
312            for (sw = g_seamless_windows; sw; sw = sw->next)
313            {
314                    if (sw == win)
315                    {
316                            *prevnext = sw->next;
317                            sw->group->refcnt--;
318                            if (sw->group->refcnt == 0)
319                            {
320                                    XDestroyWindow(g_display, sw->group->wnd);
321                                    xfree(sw->group);
322                            }
323                            xfree(sw);
324                            return;
325                    }
326                    prevnext = &sw->next;
327            }
328            return;
329    }
330    
331    
332    /* Move all windows except wnd to new desktop */
333    static void
334    sw_all_to_desktop(Window wnd, unsigned int desktop)
335    {
336            seamless_window *sw;
337            for (sw = g_seamless_windows; sw; sw = sw->next)
338            {
339                    if (sw->wnd == wnd)
340                            continue;
341                    if (sw->desktop != desktop)
342                    {
343                            ewmh_move_to_desktop(sw->wnd, desktop);
344                            sw->desktop = desktop;
345                    }
346            }
347    }
348    
349    
350    /* Send our position */
351    static void
352    sw_update_position(seamless_window * sw)
353    {
354            XWindowAttributes wa;
355            int x, y;
356            Window child_return;
357            unsigned int serial;
358    
359            XGetWindowAttributes(g_display, sw->wnd, &wa);
360            XTranslateCoordinates(g_display, sw->wnd, wa.root,
361                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
362    
363            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
364    
365            sw->outstanding_position = True;
366            sw->outpos_serial = serial;
367    
368            sw->outpos_xoffset = x;
369            sw->outpos_yoffset = y;
370            sw->outpos_width = wa.width;
371            sw->outpos_height = wa.height;
372    }
373    
374    
375    /* Check if it's time to send our position */
376    static void
377    sw_check_timers()
378    {
379            seamless_window *sw;
380            struct timeval now;
381    
382            gettimeofday(&now, NULL);
383            for (sw = g_seamless_windows; sw; sw = sw->next)
384            {
385                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
386                    {
387                            timerclear(sw->position_timer);
388                            sw_update_position(sw);
389                    }
390            }
391    }
392    
393    
394    static void
395    sw_restack_window(seamless_window * sw, unsigned long behind)
396    {
397            seamless_window *sw_above;
398    
399            /* Remove window from stack */
400            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
401            {
402                    if (sw_above->behind == sw->id)
403                            break;
404            }
405    
406            if (sw_above)
407                    sw_above->behind = sw->behind;
408    
409            /* And then add it at the new position */
410    
411            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
412            {
413                    if (sw_above->behind == behind)
414                            break;
415            }
416    
417            if (sw_above)
418                    sw_above->behind = sw->id;
419    
420            sw->behind = behind;
421    }
422    
423    
424    static void
425    sw_handle_restack(seamless_window * sw)
426    {
427            Status status;
428            Window root, parent, *children;
429            unsigned int nchildren, i;
430            seamless_window *sw_below;
431    
432            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
433                                &root, &parent, &children, &nchildren);
434            if (!status || !nchildren)
435                    return;
436    
437            sw_below = NULL;
438    
439            i = 0;
440            while (children[i] != sw->wnd)
441            {
442                    i++;
443                    if (i >= nchildren)
444                            return;
445            }
446    
447            for (i++; i < nchildren; i++)
448            {
449                    sw_below = sw_get_window_by_wnd(children[i]);
450                    if (sw_below)
451                            break;
452            }
453    
454            if (!sw_below && !sw->behind)
455                    return;
456            if (sw_below && (sw_below->id == sw->behind))
457                    return;
458    
459            if (sw_below)
460            {
461                    seamless_send_zchange(sw->id, sw_below->id, 0);
462                    sw_restack_window(sw, sw_below->id);
463            }
464            else
465            {
466                    seamless_send_zchange(sw->id, 0, 0);
467                    sw_restack_window(sw, 0);
468            }
469    }
470    
471    
472    static seamless_group *
473    sw_find_group(unsigned long id, 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  static void
502  mwm_hide_decorations(void)  mwm_hide_decorations(Window wnd)
503  {  {
504          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
505          Atom hintsatom;          Atom hintsatom;
# Line 163  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 255  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 282  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 310  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 602  translate_image(int width, int height, u Line 1175  translate_image(int width, int height, u
1175          uint8 *out;          uint8 *out;
1176          uint8 *end;          uint8 *end;
1177    
1178          /* if server and xserver bpp match, */          /*
1179          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1180          /* just return data */             and arch(endian) matches, no need to translate:
1181          if (g_depth > 8)             just return data.
1182                  if (g_arch_match)             Note: select_visual should've already ensured g_no_translate
1183                          if (g_depth == g_server_bpp)             is only set for compatible depths, but the RDP depth might've
1184                                  return data;             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);          size = width * height * (g_bpp / 8);
1195          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1196          end = out + size;          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 712  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 BOOL
1312    select_visual()
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            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1324            if (pfm == NULL)
1325          {          {
1326                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1327                    XCloseDisplay(g_display);
1328                  return False;                  return False;
1329          }          }
1330    
1331          screen_num = DefaultScreen(g_display);          /* Search for best TrueColor visual */
         g_x_socket = ConnectionNumber(g_display);  
         g_screen = ScreenOfDisplay(g_display, screen_num);  
         g_depth = DefaultDepthOfScreen(g_screen);  
   
         /* Search for best TrueColor depth */  
1332          template.class = TrueColor;          template.class = TrueColor;
1333          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1334            g_visual = NULL;
1335            g_no_translate_image = False;
1336            g_compatible_arch = False;
1337            if (vmatches != NULL)
1338            {
1339                    for (i = 0; i < visuals_count; ++i)
1340                    {
1341                            XVisualInfo *visual_info = &vmatches[i];
1342    
1343                            /* Try to find a no-translation visual that'll
1344                               allow us to use RDP bitmaps directly as ZPixmaps. */
1345                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1346                                                   /* R5G5B5 */
1347                                                   (visual_info->red_mask == 0x7c00) &&
1348                                                   (visual_info->green_mask == 0x3e0) &&
1349                                                   (visual_info->blue_mask == 0x1f)) ||
1350                                                  ((visual_info->depth == 16) &&
1351                                                   /* R5G6B5 */
1352                                                   (visual_info->red_mask == 0xf800) &&
1353                                                   (visual_info->green_mask == 0x7e0) &&
1354                                                   (visual_info->blue_mask == 0x1f)) ||
1355                                                  ((visual_info->depth == 24) &&
1356                                                   /* R8G8B8 */
1357                                                   (visual_info->red_mask == 0xff0000) &&
1358                                                   (visual_info->green_mask == 0xff00) &&
1359                                                   (visual_info->blue_mask == 0xff))))
1360                            {
1361                                    g_visual = visual_info->visual;
1362                                    g_depth = visual_info->depth;
1363                                    g_compatible_arch = !g_host_be;
1364                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1365                                    if (g_no_translate_image)
1366                                            /* We found the best visual */
1367                                            break;
1368                            }
1369                            else
1370                            {
1371                                    g_compatible_arch = False;
1372                            }
1373    
1374          nvisuals--;                          if (visual_info->depth > 24)
1375          while (nvisuals >= 0)                          {
1376          {                                  /* Avoid 32-bit visuals and likes like the plague.
1377                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1378                  {                                     (e.g. nvidia's Composite 32-bit visual).
1379                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1380                                    continue;
1381                            }
1382    
1383                            /* Only care for visuals, for whose BPPs (not depths!)
1384                               we have a translateXtoY function. */
1385                            BOOL can_translate_to_bpp = False;
1386                            int j;
1387                            for (j = 0; j < pixmap_formats_count; ++j)
1388                            {
1389                                    if (pfm[j].depth == visual_info->depth)
1390                                    {
1391                                            if ((pfm[j].bits_per_pixel == 16) ||
1392                                                (pfm[j].bits_per_pixel == 24) ||
1393                                                (pfm[j].bits_per_pixel == 32))
1394                                            {
1395                                                    can_translate_to_bpp = True;
1396                                            }
1397                                            break;
1398                                    }
1399                            }
1400    
1401                            /* Prefer formats which have the most colour depth.
1402                               We're being truly aristocratic here, minding each
1403                               weight on its own. */
1404                            if (can_translate_to_bpp)
1405                            {
1406                                    unsigned vis_red_weight =
1407                                            calculate_mask_weight(visual_info->red_mask);
1408                                    unsigned vis_green_weight =
1409                                            calculate_mask_weight(visual_info->green_mask);
1410                                    unsigned vis_blue_weight =
1411                                            calculate_mask_weight(visual_info->blue_mask);
1412                                    if ((vis_red_weight >= red_weight)
1413                                        && (vis_green_weight >= green_weight)
1414                                        && (vis_blue_weight >= blue_weight))
1415                                    {
1416                                            red_weight = vis_red_weight;
1417                                            green_weight = vis_green_weight;
1418                                            blue_weight = vis_blue_weight;
1419                                            g_visual = visual_info->visual;
1420                                            g_depth = visual_info->depth;
1421                                    }
1422                            }
1423                  }                  }
1424                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1425          }          }
1426    
1427          test = 1;          if (g_visual != NULL)
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
         if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))  
1428          {          {
1429                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1430                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1431                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1432                    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;  
                 }  
1433          }          }
1434          else          else
1435          {          {
1436                  /* need a truecolour visual */                  template.class = PseudoColor;
1437                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1438                  {                  template.colormap_size = 256;
1439                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1440                            XGetVisualInfo(g_display,
1441                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1442                                           &template, &visuals_count);
1443                    if (vmatches == NULL)
1444                    {
1445                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1446                            XCloseDisplay(g_display);
1447                            XFree(pfm);
1448                          return False;                          return False;
1449                  }                  }
1450    
1451                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1452                  g_owncolmap = False;                  g_owncolmap = True;
1453                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1454                  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);  
   
                 /* if RGB video and averything is little endian */  
                 if (vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask)  
                         if (!g_xserver_be && !g_host_be)  
                                 g_arch_match = True;  
1455          }          }
1456    
1457          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1458          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1459          {          {
1460                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1461                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1462                  {                  {
1463                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1464    
1465                            if (g_no_translate_image)
1466                          {                          {
1467                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1468                                    {
1469                                            case 15:
1470                                            case 16:
1471                                                    if (g_bpp != 16)
1472                                                            g_no_translate_image = False;
1473                                                    break;
1474                                            case 24:
1475                                                    /* Yes, this will force image translation
1476                                                       on most modern servers which use 32 bits
1477                                                       for R8G8B8. */
1478                                                    if (g_bpp != 24)
1479                                                            g_no_translate_image = False;
1480                                                    break;
1481                                            default:
1482                                                    g_no_translate_image = False;
1483                                                    break;
1484                                    }
1485                          }                          }
1486    
1487                            /* Pixmap formats list is a depth-to-bpp mapping --
1488                               there's just a single entry for every depth,
1489                               so we can safely break here */
1490                            break;
1491                  }                  }
                 XFree(pfm);  
1492          }          }
1493            XFree(pfm);
1494            pfm = NULL;
1495            return True;
1496    }
1497    
1498    static XErrorHandler g_old_error_handler;
1499    
1500          if (g_bpp < 8)  static int
1501    error_handler(Display * dpy, XErrorEvent * eev)
1502    {
1503            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1504          {          {
1505                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1506                  XCloseDisplay(g_display);                  fprintf(stderr,
1507                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1508                    return 0;
1509            }
1510    
1511            return g_old_error_handler(dpy, eev);
1512    }
1513    
1514    BOOL
1515    ui_init(void)
1516    {
1517            int screen_num;
1518    
1519            g_display = XOpenDisplay(NULL);
1520            if (g_display == NULL)
1521            {
1522                    error("Failed to open display: %s\n", XDisplayName(NULL));
1523                    return False;
1524            }
1525    
1526            {
1527                    uint16 endianess_test = 1;
1528                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1529            }
1530    
1531            g_old_error_handler = XSetErrorHandler(error_handler);
1532    
1533            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1534            screen_num = DefaultScreen(g_display);
1535            g_x_socket = ConnectionNumber(g_display);
1536            g_screen = ScreenOfDisplay(g_display, screen_num);
1537            g_depth = DefaultDepthOfScreen(g_screen);
1538    
1539            if (!select_visual())
1540                  return False;                  return False;
1541    
1542            if (g_no_translate_image)
1543            {
1544                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1545            }
1546    
1547            if (g_server_depth > g_bpp)
1548            {
1549                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1550                            g_server_depth, g_bpp);
1551          }          }
1552    
1553            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1554                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1555    
1556          if (!g_owncolmap)          if (!g_owncolmap)
1557          {          {
1558                  g_xcolmap =                  g_xcolmap =
1559                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1560                                          AllocNone);                                          AllocNone);
1561                  if (g_depth <= 8)                  if (g_depth <= 8)
1562                          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);
1563          }          }
1564    
1565          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1566          {          {
1567                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1568                  g_ownbackstore = True;                  g_ownbackstore = True;
1569          }          }
1570    
# Line 831  ui_init(void) Line 1575  ui_init(void)
1575          {          {
1576                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1577                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1578                    g_using_full_workarea = True;
1579          }          }
1580          else if (g_width < 0)          else if (g_width < 0)
1581          {          {
1582                  /* Percent of screen */                  /* Percent of screen */
1583                    if (-g_width >= 100)
1584                            g_using_full_workarea = True;
1585                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1586                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1587          }          }
# Line 842  ui_init(void) Line 1589  ui_init(void)
1589          {          {
1590                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1591                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1592                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1593                  {                  {
1594                          g_width = cx;                          g_width = cx;
1595                          g_height = cy;                          g_height = cy;
1596                            g_using_full_workarea = True;
1597                  }                  }
1598                  else                  else
1599                  {                  {
1600                          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");
1601                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1602                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1603                  }                  }
1604          }          }
1605    
# Line 867  ui_init(void) Line 1614  ui_init(void)
1614                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1615    
1616          xclip_init();          xclip_init();
1617            ewmh_init();
1618            if (g_seamless_rdp)
1619                    seamless_init();
1620    
1621          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));
1622    
1623          return True;          return True;
1624  }  }
# Line 892  ui_deinit(void) Line 1642  ui_deinit(void)
1642          g_display = NULL;          g_display = NULL;
1643  }  }
1644    
1645    
1646    static void
1647    get_window_attribs(XSetWindowAttributes * attribs)
1648    {
1649            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1650            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1651            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1652            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1653            attribs->override_redirect = g_fullscreen;
1654            attribs->colormap = g_xcolmap;
1655    }
1656    
1657    static void
1658    get_input_mask(long *input_mask)
1659    {
1660            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1661                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1662    
1663            if (g_sendmotion)
1664                    *input_mask |= PointerMotionMask;
1665            if (g_ownbackstore)
1666                    *input_mask |= ExposureMask;
1667            if (g_fullscreen || g_grab_keyboard)
1668                    *input_mask |= EnterWindowMask;
1669            if (g_grab_keyboard)
1670                    *input_mask |= LeaveWindowMask;
1671    }
1672    
1673  BOOL  BOOL
1674  ui_create_window(void)  ui_create_window(void)
1675  {  {
1676          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1677          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1678    
1679          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1680          XClassHint *classhints;          XClassHint *classhints;
1681          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 907  ui_create_window(void) Line 1686  ui_create_window(void)
1686          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1687          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1688    
1689          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1690          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1691          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1692          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1693          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1694    
1695          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,          get_window_attribs(&attribs);
1696                                0, g_depth, InputOutput, g_visual,  
1697                                CWBackPixel | CWBackingStore | CWOverrideRedirect |          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1698                                CWColormap | CWBorderPixel, &attribs);                                wndheight, 0, g_depth, InputOutput, g_visual,
1699                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1700                                  CWBorderPixel, &attribs);
1701    
1702          if (g_gc == NULL)          if (g_gc == NULL)
1703            {
1704                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1705                    ui_reset_clip();
1706            }
1707    
1708            if (g_create_bitmap_gc == NULL)
1709                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1710    
1711          if ((g_ownbackstore) && (g_backstore == 0))          if ((g_ownbackstore) && (g_backstore == 0))
1712          {          {
# Line 933  ui_create_window(void) Line 1720  ui_create_window(void)
1720          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1721    
1722          if (g_hide_decorations)          if (g_hide_decorations)
1723                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1724    
1725          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1726          if (classhints != NULL)          if (classhints != NULL)
# Line 947  ui_create_window(void) Line 1734  ui_create_window(void)
1734          if (sizehints)          if (sizehints)
1735          {          {
1736                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1737                    if (g_pos)
1738                            sizehints->flags |= PPosition;
1739                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1740                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1741                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1742                  XFree(sizehints);                  XFree(sizehints);
1743          }          }
1744    
1745          if ( g_embed_wnd )          if (g_embed_wnd)
1746          {          {
1747                  XReparentWindow(g_display, g_wnd, (Window)g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1748          }          }
   
         input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |  
                 VisibilityChangeMask | FocusChangeMask;  
1749    
1750          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;  
1751    
1752          if (g_IM != NULL)          if (g_IM != NULL)
1753          {          {
# Line 981  ui_create_window(void) Line 1760  ui_create_window(void)
1760          }          }
1761    
1762          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1763    
1764            XMapWindow(g_display, g_wnd);
1765          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1766          do          do
1767          {          {
1768                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1769          }          }
1770          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1771            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1772    
1773          g_focused = False;          g_focused = False;
1774          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 1006  ui_create_window(void) Line 1786  ui_create_window(void)
1786  }  }
1787    
1788  void  void
1789    ui_resize_window()
1790    {
1791            XSizeHints *sizehints;
1792            Pixmap bs;
1793    
1794            sizehints = XAllocSizeHints();
1795            if (sizehints)
1796            {
1797                    sizehints->flags = PMinSize | PMaxSize;
1798                    sizehints->min_width = sizehints->max_width = g_width;
1799                    sizehints->min_height = sizehints->max_height = g_height;
1800                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1801                    XFree(sizehints);
1802            }
1803    
1804            if (!(g_fullscreen || g_embed_wnd))
1805            {
1806                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1807            }
1808    
1809            /* create new backstore pixmap */
1810            if (g_backstore != 0)
1811            {
1812                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1813                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1814                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1815                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1816                    XFreePixmap(g_display, g_backstore);
1817                    g_backstore = bs;
1818            }
1819    }
1820    
1821    void
1822  ui_destroy_window(void)  ui_destroy_window(void)
1823  {  {
1824          if (g_IC != NULL)          if (g_IC != NULL)
# Line 1019  xwin_toggle_fullscreen(void) Line 1832  xwin_toggle_fullscreen(void)
1832  {  {
1833          Pixmap contents = 0;          Pixmap contents = 0;
1834    
1835            if (g_seamless_active)
1836                    /* Turn off SeamlessRDP mode */
1837                    ui_seamless_toggle();
1838    
1839          if (!g_ownbackstore)          if (!g_ownbackstore)
1840          {          {
1841                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1039  xwin_toggle_fullscreen(void) Line 1856  xwin_toggle_fullscreen(void)
1856          }          }
1857  }  }
1858    
1859  /* Process all events in Xlib queue  static void
1860    handle_button_event(XEvent xevent, BOOL down)
1861    {
1862            uint16 button, flags = 0;
1863            g_last_gesturetime = xevent.xbutton.time;
1864            button = xkeymap_translate_button(xevent.xbutton.button);
1865            if (button == 0)
1866                    return;
1867    
1868            if (down)
1869                    flags = MOUSE_FLAG_DOWN;
1870    
1871            /* Stop moving window when button is released, regardless of cursor position */
1872            if (g_moving_wnd && (xevent.type == ButtonRelease))
1873                    g_moving_wnd = False;
1874    
1875            /* If win_button_size is nonzero, enable single app mode */
1876            if (xevent.xbutton.y < g_win_button_size)
1877            {
1878                    /*  Check from right to left: */
1879                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1880                    {
1881                            /* The close button, continue */
1882                            ;
1883                    }
1884                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1885                    {
1886                            /* The maximize/restore button. Do not send to
1887                               server.  It might be a good idea to change the
1888                               cursor or give some other visible indication
1889                               that rdesktop inhibited this click */
1890                            if (xevent.type == ButtonPress)
1891                                    return;
1892                    }
1893                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1894                    {
1895                            /* The minimize button. Iconify window. */
1896                            if (xevent.type == ButtonRelease)
1897                            {
1898                                    /* Release the mouse button outside the minimize button, to prevent the
1899                                       actual minimazation to happen */
1900                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1901                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1902                                    return;
1903                            }
1904                    }
1905                    else if (xevent.xbutton.x <= g_win_button_size)
1906                    {
1907                            /* The system menu. Ignore. */
1908                            if (xevent.type == ButtonPress)
1909                                    return;
1910                    }
1911                    else
1912                    {
1913                            /* The title bar. */
1914                            if (xevent.type == ButtonPress)
1915                            {
1916                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1917                                    {
1918                                            g_moving_wnd = True;
1919                                            g_move_x_offset = xevent.xbutton.x;
1920                                            g_move_y_offset = xevent.xbutton.y;
1921                                    }
1922                                    return;
1923                            }
1924                    }
1925            }
1926    
1927            if (xevent.xmotion.window == g_wnd)
1928            {
1929                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1930                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1931            }
1932            else
1933            {
1934                    /* SeamlessRDP */
1935                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1936                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1937            }
1938    }
1939    
1940    
1941    /* Process events in Xlib queue
1942     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1943  static int  static int
1944  xwin_process_events(void)  xwin_process_events(void)
1945  {  {
1946          XEvent xevent;          XEvent xevent;
1947          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1948          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1949          char str[256];          char str[256];
1950          Status status;          Status status;
1951            int events = 0;
1952            seamless_window *sw;
1953    
1954          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1955          {          {
1956                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1957    
# Line 1062  xwin_process_events(void) Line 1961  xwin_process_events(void)
1961                          continue;                          continue;
1962                  }                  }
1963    
                 flags = 0;  
   
1964                  switch (xevent.type)                  switch (xevent.type)
1965                  {                  {
1966                            case VisibilityNotify:
1967                                    if (xevent.xvisibility.window == g_wnd)
1968                                            g_Unobscured =
1969                                                    xevent.xvisibility.state == VisibilityUnobscured;
1970    
1971                                    break;
1972                          case ClientMessage:                          case ClientMessage:
1973                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
1974                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 1097  xwin_process_events(void) Line 2000  xwin_process_events(void)
2000                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2001                                  }                                  }
2002    
2003                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2004                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2005    
2006                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2007                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2008                                          break;                                          break;
2009    
2010                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2011                                                             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);  
   
2012                                  break;                                  break;
2013    
2014                          case KeyRelease:                          case KeyRelease:
# Line 1122  xwin_process_events(void) Line 2016  xwin_process_events(void)
2016                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2017                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2018    
2019                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2020                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2021    
2022                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2023                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2024                                          break;                                          break;
2025    
2026                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2027                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2028                                  break;                                  break;
2029    
2030                          case ButtonPress:                          case ButtonPress:
2031                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2032                                  /* fall through */                                  break;
2033    
2034                          case ButtonRelease:                          case ButtonRelease:
2035                                  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);  
2036                                  break;                                  break;
2037    
2038                          case MotionNotify:                          case MotionNotify:
# Line 1215  xwin_process_events(void) Line 2047  xwin_process_events(void)
2047                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2048                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2049                                                         CurrentTime);                                                         CurrentTime);
2050                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2051                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2052                                    {
2053                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2054                                                           xevent.xmotion.x, xevent.xmotion.y);
2055                                    }
2056                                    else
2057                                    {
2058                                            /* SeamlessRDP */
2059                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2060                                                           xevent.xmotion.x_root,
2061                                                           xevent.xmotion.y_root);
2062                                    }
2063                                  break;                                  break;
2064    
2065                          case FocusIn:                          case FocusIn:
# Line 1227  xwin_process_events(void) Line 2070  xwin_process_events(void)
2070                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2071                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2072                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2073    
2074                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2075                                    if (!sw)
2076                                            break;
2077    
2078                                    if (sw->id != g_seamless_focused)
2079                                    {
2080                                            seamless_send_focus(sw->id, 0);
2081                                            g_seamless_focused = sw->id;
2082                                    }
2083                                  break;                                  break;
2084    
2085                          case FocusOut:                          case FocusOut:
# Line 1259  xwin_process_events(void) Line 2112  xwin_process_events(void)
2112                                  break;                                  break;
2113    
2114                          case Expose:                          case Expose:
2115                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2116                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2117                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2118                                            xevent.xexpose.height,                                                    g_gc,
2119                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2120                                                      xevent.xexpose.width, xevent.xexpose.height,
2121                                                      xevent.xexpose.x, xevent.xexpose.y);
2122                                    }
2123                                    else
2124                                    {
2125                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2126                                            if (sw)
2127                                                    XCopyArea(g_display, g_backstore,
2128                                                              xevent.xexpose.window, g_gc,
2129                                                              xevent.xexpose.x + sw->xoffset,
2130                                                              xevent.xexpose.y + sw->yoffset,
2131                                                              xevent.xexpose.width,
2132                                                              xevent.xexpose.height, xevent.xexpose.x,
2133                                                              xevent.xexpose.y);
2134                                            else
2135                                            {
2136                                                    error("Expose for unknown window 0x%lx\n",
2137                                                          xevent.xexpose.window);
2138                                            }
2139                                    }
2140    
2141                                  break;                                  break;
2142    
2143                          case MappingNotify:                          case MappingNotify:
# Line 1292  xwin_process_events(void) Line 2166  xwin_process_events(void)
2166                                  break;                                  break;
2167                          case PropertyNotify:                          case PropertyNotify:
2168                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2169                                    if (xevent.xproperty.window == g_wnd)
2170                                            break;
2171                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2172                                            break;
2173    
2174                                    /* seamless */
2175                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2176                                    if (!sw)
2177                                            break;
2178    
2179                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2180                                        && (xevent.xproperty.state == PropertyNewValue))
2181                                    {
2182                                            sw->state = ewmh_get_window_state(sw->wnd);
2183                                            seamless_send_state(sw->id, sw->state, 0);
2184                                    }
2185    
2186                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2187                                        && (xevent.xproperty.state == PropertyNewValue))
2188                                    {
2189                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2190                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2191                                    }
2192    
2193                                    break;
2194                            case MapNotify:
2195                                    if (!g_seamless_active)
2196                                            rdp_send_client_window_status(1);
2197                                    break;
2198                            case UnmapNotify:
2199                                    if (!g_seamless_active)
2200                                            rdp_send_client_window_status(0);
2201                                    break;
2202                            case ConfigureNotify:
2203                                    if (!g_seamless_active)
2204                                            break;
2205    
2206                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2207                                    if (!sw)
2208                                    {
2209                                            error("ConfigureNotify for unknown window 0x%lx\n",
2210                                                  xevent.xconfigure.window);
2211                                    }
2212    
2213                                    gettimeofday(sw->position_timer, NULL);
2214                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2215                                        1000000)
2216                                    {
2217                                            sw->position_timer->tv_usec +=
2218                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2219                                            sw->position_timer->tv_sec += 1;
2220                                    }
2221                                    else
2222                                    {
2223                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2224                                    }
2225    
2226                                    sw_handle_restack(sw);
2227                                  break;                                  break;
2228                  }                  }
2229          }          }
# Line 1316  ui_select(int rdp_socket) Line 2248  ui_select(int rdp_socket)
2248                          /* User quit */                          /* User quit */
2249                          return 0;                          return 0;
2250    
2251                    if (g_seamless_active)
2252                            sw_check_timers();
2253    
2254                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2255                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2256                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1335  ui_select(int rdp_socket) Line 2270  ui_select(int rdp_socket)
2270    
2271                  /* add redirection handles */                  /* add redirection handles */
2272                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2273                    seamless_select_timeout(&tv);
2274    
2275                  n++;                  n++;
2276    
# Line 1344  ui_select(int rdp_socket) Line 2280  ui_select(int rdp_socket)
2280                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2281    
2282                          case 0:                          case 0:
2283                                  /* TODO: if tv.tv_sec just times out                                  /* Abort serial read calls */
2284                                   * we will segfault.                                  if (s_timeout)
2285                                   * FIXME:                                          rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
                                  */  
                                 //s_timeout = True;  
                                 //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);  
2286                                  continue;                                  continue;
2287                  }                  }
2288    
# Line 1379  ui_create_bitmap(int width, int height, Line 2312  ui_create_bitmap(int width, int height,
2312          uint8 *tdata;          uint8 *tdata;
2313          int bitmap_pad;          int bitmap_pad;
2314    
2315          if (g_server_bpp == 8)          if (g_server_depth == 8)
2316          {          {
2317                  bitmap_pad = 8;                  bitmap_pad = 8;
2318          }          }
# Line 1396  ui_create_bitmap(int width, int height, Line 2329  ui_create_bitmap(int width, int height,
2329          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2330                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2331    
2332          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);
2333    
2334          XFree(image);          XFree(image);
2335          if (tdata != data)          if (tdata != data)
# Line 1411  ui_paint_bitmap(int x, int y, int cx, in Line 2344  ui_paint_bitmap(int x, int y, int cx, in
2344          uint8 *tdata;          uint8 *tdata;
2345          int bitmap_pad;          int bitmap_pad;
2346    
2347          if (g_server_bpp == 8)          if (g_server_depth == 8)
2348          {          {
2349                  bitmap_pad = 8;                  bitmap_pad = 8;
2350          }          }
# Line 1431  ui_paint_bitmap(int x, int y, int cx, in Line 2364  ui_paint_bitmap(int x, int y, int cx, in
2364          {          {
2365                  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);
2366                  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);
2367                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2368                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2369                                             x - sw->xoffset, y - sw->yoffset));
2370          }          }
2371          else          else
2372          {          {
2373                  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);
2374                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2375                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2376                                             x - sw->xoffset, y - sw->yoffset));
2377          }          }
2378    
2379          XFree(image);          XFree(image);
# Line 1454  ui_create_glyph(int width, int height, u Line 2393  ui_create_glyph(int width, int height, u
2393          XImage *image;          XImage *image;
2394          Pixmap bitmap;          Pixmap bitmap;
2395          int scanline;          int scanline;
         GC gc;  
2396    
2397          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2398    
2399          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2400          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2401                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2402    
2403          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2404                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1467  ui_create_glyph(int width, int height, u Line 2406  ui_create_glyph(int width, int height, u
2406          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2407          XInitImage(image);          XInitImage(image);
2408    
2409          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);
2410    
2411          XFree(image);          XFree(image);
         XFreeGC(g_display, gc);  
2412          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2413  }  }
2414    
# Line 1556  ui_set_cursor(HCURSOR cursor) Line 2494  ui_set_cursor(HCURSOR cursor)
2494  {  {
2495          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2496          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2497            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2498  }  }
2499    
2500  void  void
# Line 1697  ui_set_colourmap(HCOLOURMAP map) Line 2636  ui_set_colourmap(HCOLOURMAP map)
2636                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2637          }          }
2638          else          else
2639            {
2640                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2641                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2642            }
2643  }  }
2644    
2645  void  void
2646  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2647  {  {
2648          XRectangle rect;          g_clip_rectangle.x = x;
2649            g_clip_rectangle.y = y;
2650          rect.x = x;          g_clip_rectangle.width = cx;
2651          rect.y = y;          g_clip_rectangle.height = cy;
2652          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);  
2653  }  }
2654    
2655  void  void
2656  ui_reset_clip(void)  ui_reset_clip(void)
2657  {  {
2658          XRectangle rect;          g_clip_rectangle.x = 0;
2659            g_clip_rectangle.y = 0;
2660          rect.x = 0;          g_clip_rectangle.width = g_width;
2661          rect.y = 0;          g_clip_rectangle.height = g_height;
2662          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);  
2663  }  }
2664    
2665  void  void
# Line 1762  ui_patblt(uint8 opcode, Line 2700  ui_patblt(uint8 opcode,
2700          {          {
2701                  case 0: /* Solid */                  case 0: /* Solid */
2702                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2703                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2704                          break;                          break;
2705    
2706                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1773  ui_patblt(uint8 opcode, Line 2711  ui_patblt(uint8 opcode,
2711                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2712                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2713                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2714                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2715                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2716                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2717                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1783  ui_patblt(uint8 opcode, Line 2721  ui_patblt(uint8 opcode,
2721                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2722                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2723                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2724                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2725                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2726                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2727                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2728                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2729                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
2730                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2731                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2732                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1802  ui_patblt(uint8 opcode, Line 2737  ui_patblt(uint8 opcode,
2737          }          }
2738    
2739          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2740    
2741            if (g_ownbackstore)
2742                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2743            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2744                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2745                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2746  }  }
2747    
2748  void  void
# Line 1812  ui_screenblt(uint8 opcode, Line 2753  ui_screenblt(uint8 opcode,
2753          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2754          if (g_ownbackstore)          if (g_ownbackstore)
2755          {          {
2756                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2757                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2758                  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);
2759          }          }
2760          else          else
2761          {          {
2762                  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);
2763          }          }
2764    
2765            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2766                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2767                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2768    
2769          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2770  }  }
2771    
# Line 1829  ui_memblt(uint8 opcode, Line 2776  ui_memblt(uint8 opcode,
2776  {  {
2777          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2778          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);
2779            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2780                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2781                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2782          if (g_ownbackstore)          if (g_ownbackstore)
2783                  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);
2784          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1875  ui_line(uint8 opcode, Line 2825  ui_line(uint8 opcode,
2825          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2826          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2827          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2828            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2829                                                startx - sw->xoffset, starty - sw->yoffset,
2830                                                endx - sw->xoffset, endy - sw->yoffset));
2831          if (g_ownbackstore)          if (g_ownbackstore)
2832                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2833          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1889  ui_rect( Line 2842  ui_rect(
2842          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2843  }  }
2844    
2845    void
2846    ui_polygon(uint8 opcode,
2847               /* mode */ uint8 fillmode,
2848               /* dest */ POINT * point, int npoints,
2849               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2850    {
2851            uint8 style, i, ipattern[8];
2852            Pixmap fill;
2853    
2854            SET_FUNCTION(opcode);
2855    
2856            switch (fillmode)
2857            {
2858                    case ALTERNATE:
2859                            XSetFillRule(g_display, g_gc, EvenOddRule);
2860                            break;
2861                    case WINDING:
2862                            XSetFillRule(g_display, g_gc, WindingRule);
2863                            break;
2864                    default:
2865                            unimpl("fill mode %d\n", fillmode);
2866            }
2867    
2868            if (brush)
2869                    style = brush->style;
2870            else
2871                    style = 0;
2872    
2873            switch (style)
2874            {
2875                    case 0: /* Solid */
2876                            SET_FOREGROUND(fgcolour);
2877                            FILL_POLYGON((XPoint *) point, npoints);
2878                            break;
2879    
2880                    case 2: /* Hatch */
2881                            fill = (Pixmap) ui_create_glyph(8, 8,
2882                                                            hatch_patterns + brush->pattern[0] * 8);
2883                            SET_FOREGROUND(fgcolour);
2884                            SET_BACKGROUND(bgcolour);
2885                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2886                            XSetStipple(g_display, g_gc, fill);
2887                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2888                            FILL_POLYGON((XPoint *) point, npoints);
2889                            XSetFillStyle(g_display, g_gc, FillSolid);
2890                            XSetTSOrigin(g_display, g_gc, 0, 0);
2891                            ui_destroy_glyph((HGLYPH) fill);
2892                            break;
2893    
2894                    case 3: /* Pattern */
2895                            for (i = 0; i != 8; i++)
2896                                    ipattern[7 - i] = brush->pattern[i];
2897                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2898                            SET_FOREGROUND(bgcolour);
2899                            SET_BACKGROUND(fgcolour);
2900                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2901                            XSetStipple(g_display, g_gc, fill);
2902                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2903                            FILL_POLYGON((XPoint *) point, npoints);
2904                            XSetFillStyle(g_display, g_gc, FillSolid);
2905                            XSetTSOrigin(g_display, g_gc, 0, 0);
2906                            ui_destroy_glyph((HGLYPH) fill);
2907                            break;
2908    
2909                    default:
2910                            unimpl("brush %d\n", brush->style);
2911            }
2912    
2913            RESET_FUNCTION(opcode);
2914    }
2915    
2916    void
2917    ui_polyline(uint8 opcode,
2918                /* dest */ POINT * points, int npoints,
2919                /* pen */ PEN * pen)
2920    {
2921            /* TODO: set join style */
2922            SET_FUNCTION(opcode);
2923            SET_FOREGROUND(pen->colour);
2924            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2925            if (g_ownbackstore)
2926                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2927                               CoordModePrevious);
2928    
2929            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2930                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2931    
2932            RESET_FUNCTION(opcode);
2933    }
2934    
2935    void
2936    ui_ellipse(uint8 opcode,
2937               /* mode */ uint8 fillmode,
2938               /* dest */ int x, int y, int cx, int cy,
2939               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2940    {
2941            uint8 style, i, ipattern[8];
2942            Pixmap fill;
2943    
2944            SET_FUNCTION(opcode);
2945    
2946            if (brush)
2947                    style = brush->style;
2948            else
2949                    style = 0;
2950    
2951            switch (style)
2952            {
2953                    case 0: /* Solid */
2954                            SET_FOREGROUND(fgcolour);
2955                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2956                            break;
2957    
2958                    case 2: /* Hatch */
2959                            fill = (Pixmap) ui_create_glyph(8, 8,
2960                                                            hatch_patterns + brush->pattern[0] * 8);
2961                            SET_FOREGROUND(fgcolour);
2962                            SET_BACKGROUND(bgcolour);
2963                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2964                            XSetStipple(g_display, g_gc, fill);
2965                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2966                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2967                            XSetFillStyle(g_display, g_gc, FillSolid);
2968                            XSetTSOrigin(g_display, g_gc, 0, 0);
2969                            ui_destroy_glyph((HGLYPH) fill);
2970                            break;
2971    
2972                    case 3: /* Pattern */
2973                            for (i = 0; i != 8; i++)
2974                                    ipattern[7 - i] = brush->pattern[i];
2975                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2976                            SET_FOREGROUND(bgcolour);
2977                            SET_BACKGROUND(fgcolour);
2978                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2979                            XSetStipple(g_display, g_gc, fill);
2980                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2981                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2982                            XSetFillStyle(g_display, g_gc, FillSolid);
2983                            XSetTSOrigin(g_display, g_gc, 0, 0);
2984                            ui_destroy_glyph((HGLYPH) fill);
2985                            break;
2986    
2987                    default:
2988                            unimpl("brush %d\n", brush->style);
2989            }
2990    
2991            RESET_FUNCTION(opcode);
2992    }
2993    
2994  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
2995  void  void
2996  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 1944  ui_draw_glyph(int mixmode, Line 3046  ui_draw_glyph(int mixmode,
3046  }  }
3047    
3048  void  void
3049  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,
3050               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3051               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3052               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3053  {  {
3054            /* TODO: use brush appropriately */
3055    
3056          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3057          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
3058          DATABLOB *entry;          DATABLOB *entry;
# Line 1980  ui_draw_text(uint8 font, uint8 flags, in Line 3084  ui_draw_text(uint8 font, uint8 flags, in
3084                  switch (text[i])                  switch (text[i])
3085                  {                  {
3086                          case 0xff:                          case 0xff:
3087                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3088                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3089                                  {                                  {
3090                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3091                                          exit(1);                                          for (j = 0; j < length; j++)
3092                                                    fprintf(stderr, "%02x ", text[j]);
3093                                            fprintf(stderr, "\n");
3094                                            i = length = 0;
3095                                            break;
3096                                  }                                  }
3097                                    cache_put_text(text[i + 1], text, text[i + 2]);
3098                                    i += 3;
3099                                    length -= i;
3100                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3101                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3102                                  i = 0;                                  i = 0;
3103                                  break;                                  break;
3104    
3105                          case 0xfe:                          case 0xfe:
3106                                    /* At least one byte needs to follow */
3107                                    if (i + 2 > length)
3108                                    {
3109                                            warning("Skipping short 0xfe command:");
3110                                            for (j = 0; j < length; j++)
3111                                                    fprintf(stderr, "%02x ", text[j]);
3112                                            fprintf(stderr, "\n");
3113                                            i = length = 0;
3114                                            break;
3115                                    }
3116                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3117                                  if (entry != NULL)                                  if (entry->data != NULL)
3118                                  {                                  {
3119                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3120                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3121                                          {                                          {
3122                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3123                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2030  ui_draw_text(uint8 font, uint8 flags, in Line 3149  ui_draw_text(uint8 font, uint8 flags, in
3149          if (g_ownbackstore)          if (g_ownbackstore)
3150          {          {
3151                  if (boxcx > 1)                  if (boxcx > 1)
3152                    {
3153                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3154                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3155                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3156                                                    (g_display, g_backstore, sw->wnd, g_gc,
3157                                                     boxx, boxy,
3158                                                     boxcx, boxcy,
3159                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3160                    }
3161                  else                  else
3162                    {
3163                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3164                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3165                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3166                                                    (g_display, g_backstore, sw->wnd, g_gc,
3167                                                     clipx, clipy,
3168                                                     clipcx, clipcy, clipx - sw->xoffset,
3169                                                     clipy - sw->yoffset));
3170                    }
3171          }          }
3172  }  }
3173    
# Line 2080  ui_desktop_restore(uint32 offset, int x, Line 3213  ui_desktop_restore(uint32 offset, int x,
3213          {          {
3214                  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);
3215                  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);
3216                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3217                                            (g_display, g_backstore, sw->wnd, g_gc,
3218                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3219          }          }
3220          else          else
3221          {          {
3222                  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);
3223                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3224                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3225                                             x - sw->xoffset, y - sw->yoffset));
3226          }          }
3227    
3228          XFree(image);          XFree(image);
3229  }  }
3230    
3231    /* these do nothing here but are used in uiports */
3232    void
3233    ui_begin_update(void)
3234    {
3235    }
3236    
3237    void
3238    ui_end_update(void)
3239    {
3240    }
3241    
3242    
3243    void
3244    ui_seamless_begin()
3245    {
3246            if (!g_seamless_rdp)
3247                    return;
3248    
3249            if (g_seamless_started)
3250                    return;
3251    
3252            g_seamless_started = True;
3253            ui_seamless_toggle();
3254    }
3255    
3256    
3257    void
3258    ui_seamless_toggle()
3259    {
3260            if (!g_seamless_rdp)
3261                    return;
3262    
3263            if (!g_seamless_started)
3264                    return;
3265    
3266            if (g_seamless_active)
3267            {
3268                    /* Deactivate */
3269                    while (g_seamless_windows)
3270                    {
3271                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3272                            sw_remove_window(g_seamless_windows);
3273                    }
3274                    XMapWindow(g_display, g_wnd);
3275            }
3276            else
3277            {
3278                    /* Activate */
3279                    XUnmapWindow(g_display, g_wnd);
3280                    seamless_send_sync();
3281            }
3282    
3283            g_seamless_active = !g_seamless_active;
3284    }
3285    
3286    
3287    void
3288    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3289                              unsigned long flags)
3290    {
3291            Window wnd;
3292            XSetWindowAttributes attribs;
3293            XClassHint *classhints;
3294            XSizeHints *sizehints;
3295            XWMHints *wmhints;
3296            long input_mask;
3297            seamless_window *sw, *sw_parent;
3298    
3299            if (!g_seamless_active)
3300                    return;
3301    
3302            /* Ignore CREATEs for existing windows */
3303            sw = sw_get_window_by_id(id);
3304            if (sw)
3305                    return;
3306    
3307            get_window_attribs(&attribs);
3308            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3309                                InputOutput, g_visual,
3310                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3311    
3312            XStoreName(g_display, wnd, "SeamlessRDP");
3313            ewmh_set_wm_name(wnd, "SeamlessRDP");
3314    
3315            mwm_hide_decorations(wnd);
3316    
3317            classhints = XAllocClassHint();
3318            if (classhints != NULL)
3319            {
3320                    classhints->res_name = "rdesktop";
3321                    classhints->res_class = "SeamlessRDP";
3322                    XSetClassHint(g_display, wnd, classhints);
3323                    XFree(classhints);
3324            }
3325    
3326            /* WM_NORMAL_HINTS */
3327            sizehints = XAllocSizeHints();
3328            if (sizehints != NULL)
3329            {
3330                    sizehints->flags = USPosition;
3331                    XSetWMNormalHints(g_display, wnd, sizehints);
3332                    XFree(sizehints);
3333            }
3334    
3335            /* Parent-less transient windows */
3336            if (parent == 0xFFFFFFFF)
3337            {
3338                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3339                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3340                       using some other hints. */
3341                    ewmh_set_window_popup(wnd);
3342            }
3343            /* Normal transient windows */
3344            else if (parent != 0x00000000)
3345            {
3346                    sw_parent = sw_get_window_by_id(parent);
3347                    if (sw_parent)
3348                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3349                    else
3350                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3351            }
3352    
3353            if (flags & SEAMLESSRDP_CREATE_MODAL)
3354            {
3355                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3356                       somewhat at least */
3357                    if (parent == 0x00000000)
3358                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3359                    ewmh_set_window_modal(wnd);
3360            }
3361    
3362            /* FIXME: Support for Input Context:s */
3363    
3364            get_input_mask(&input_mask);
3365            input_mask |= PropertyChangeMask;
3366    
3367            XSelectInput(g_display, wnd, input_mask);
3368    
3369            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3370               seamless window, we could try to close the window on the
3371               serverside, instead of terminating rdesktop */
3372            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3373    
3374            sw = xmalloc(sizeof(seamless_window));
3375            sw->wnd = wnd;
3376            sw->id = id;
3377            sw->behind = 0;
3378            sw->group = sw_find_group(group, False);
3379            sw->group->refcnt++;
3380            sw->xoffset = 0;
3381            sw->yoffset = 0;
3382            sw->width = 0;
3383            sw->height = 0;
3384            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3385            sw->desktop = 0;
3386            sw->position_timer = xmalloc(sizeof(struct timeval));
3387            timerclear(sw->position_timer);
3388    
3389            sw->outstanding_position = False;
3390            sw->outpos_serial = 0;
3391            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3392            sw->outpos_width = sw->outpos_height = 0;
3393    
3394            sw->next = g_seamless_windows;
3395            g_seamless_windows = sw;
3396    
3397            /* WM_HINTS */
3398            wmhints = XAllocWMHints();
3399            if (wmhints)
3400            {
3401                    wmhints->flags = WindowGroupHint;
3402                    wmhints->window_group = sw->group->wnd;
3403                    XSetWMHints(g_display, sw->wnd, wmhints);
3404                    XFree(wmhints);
3405            }
3406    }
3407    
3408    
3409    void
3410    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3411    {
3412            seamless_window *sw;
3413    
3414            if (!g_seamless_active)
3415                    return;
3416    
3417            sw = sw_get_window_by_id(id);
3418            if (!sw)
3419            {
3420                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3421                    return;
3422            }
3423    
3424            XDestroyWindow(g_display, sw->wnd);
3425            sw_remove_window(sw);
3426    }
3427    
3428    
3429    void
3430    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3431    {
3432            seamless_window *sw;
3433    
3434            if (!g_seamless_active)
3435                    return;
3436    
3437            sw = sw_get_window_by_id(id);
3438            if (!sw)
3439            {
3440                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3441                    return;
3442            }
3443    
3444            /* We ignore server updates until it has handled our request. */
3445            if (sw->outstanding_position)
3446                    return;
3447    
3448            if (!width || !height)
3449                    /* X11 windows must be at least 1x1 */
3450                    return;
3451    
3452            sw->xoffset = x;
3453            sw->yoffset = y;
3454            sw->width = width;
3455            sw->height = height;
3456    
3457            /* If we move the window in a maximized state, then KDE won't
3458               accept restoration */
3459            switch (sw->state)
3460            {
3461                    case SEAMLESSRDP_MINIMIZED:
3462                    case SEAMLESSRDP_MAXIMIZED:
3463                            return;
3464            }
3465    
3466            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3467            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3468    }
3469    
3470    
3471    void
3472    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3473    {
3474            seamless_window *sw;
3475    
3476            if (!g_seamless_active)
3477                    return;
3478    
3479            sw = sw_get_window_by_id(id);
3480            if (!sw)
3481            {
3482                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3483                    return;
3484            }
3485    
3486            if (behind)
3487            {
3488                    seamless_window *sw_behind;
3489                    Window wnds[2];
3490    
3491                    sw_behind = sw_get_window_by_id(behind);
3492                    if (!sw_behind)
3493                    {
3494                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3495                                    behind);
3496                            return;
3497                    }
3498    
3499                    wnds[1] = sw_behind->wnd;
3500                    wnds[0] = sw->wnd;
3501    
3502                    XRestackWindows(g_display, wnds, 2);
3503            }
3504            else
3505            {
3506                    XRaiseWindow(g_display, sw->wnd);
3507            }
3508    
3509            sw_restack_window(sw, behind);
3510    }
3511    
3512    
3513    void
3514    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3515    {
3516            seamless_window *sw;
3517    
3518            if (!g_seamless_active)
3519                    return;
3520    
3521            sw = sw_get_window_by_id(id);
3522            if (!sw)
3523            {
3524                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3525                    return;
3526            }
3527    
3528            /* FIXME: Might want to convert the name for non-EWMH WMs */
3529            XStoreName(g_display, sw->wnd, title);
3530            ewmh_set_wm_name(sw->wnd, title);
3531    }
3532    
3533    
3534    void
3535    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3536    {
3537            seamless_window *sw;
3538    
3539            if (!g_seamless_active)
3540                    return;
3541    
3542            sw = sw_get_window_by_id(id);
3543            if (!sw)
3544            {
3545                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3546                    return;
3547            }
3548    
3549            switch (state)
3550            {
3551                    case SEAMLESSRDP_NORMAL:
3552                    case SEAMLESSRDP_MAXIMIZED:
3553                            ewmh_change_state(sw->wnd, state);
3554                            XMapWindow(g_display, sw->wnd);
3555                            break;
3556                    case SEAMLESSRDP_MINIMIZED:
3557                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3558                               the Window Manager should probably just ignore the request, since
3559                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3560                               such as minimization, rather than an independent state." Besides,
3561                               XIconifyWindow is easier. */
3562                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3563                            {
3564                                    XWMHints *hints;
3565                                    hints = XGetWMHints(g_display, sw->wnd);
3566                                    if (hints)
3567                                    {
3568                                            hints->flags |= StateHint;
3569                                            hints->initial_state = IconicState;
3570                                            XSetWMHints(g_display, sw->wnd, hints);
3571                                            XFree(hints);
3572                                    }
3573                                    XMapWindow(g_display, sw->wnd);
3574                            }
3575                            else
3576                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3577                            break;
3578                    default:
3579                            warning("SeamlessRDP: Invalid state %d\n", state);
3580                            break;
3581            }
3582    
3583            sw->state = state;
3584    }
3585    
3586    
3587    void
3588    ui_seamless_syncbegin(unsigned long flags)
3589    {
3590            if (!g_seamless_active)
3591                    return;
3592    
3593            /* Destroy all seamless windows */
3594            while (g_seamless_windows)
3595            {
3596                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3597                    sw_remove_window(g_seamless_windows);
3598            }
3599    }
3600    
3601    
3602    void
3603    ui_seamless_ack(unsigned int serial)
3604    {
3605            seamless_window *sw;
3606            for (sw = g_seamless_windows; sw; sw = sw->next)
3607            {
3608                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3609                    {
3610                            sw->xoffset = sw->outpos_xoffset;
3611                            sw->yoffset = sw->outpos_yoffset;
3612                            sw->width = sw->outpos_width;
3613                            sw->height = sw->outpos_height;
3614                            sw->outstanding_position = False;
3615    
3616                            /* Do a complete redraw of the window as part of the
3617                               completion of the move. This is to remove any
3618                               artifacts caused by our lack of synchronization. */
3619                            XCopyArea(g_display, g_backstore,
3620                                      sw->wnd, g_gc,
3621                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3622    
3623                            break;
3624                    }
3625            }
3626    }

Legend:
Removed from v.644  
changed lines
  Added in v.1182

  ViewVC Help
Powered by ViewVC 1.1.26