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

Diff of /sourceforge.net/trunk/rdesktop/xwin.c

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

revision 542 by astrand, Mon Nov 3 13:22:09 2003 UTC revision 1407 by astrand, Mon May 14 12:11:15 2007 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2007
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <X11/Xproto.h>
24  #include <unistd.h>  #include <unistd.h>
25    #include <sys/time.h>
26  #include <time.h>  #include <time.h>
27  #include <errno.h>  #include <errno.h>
28    #include <strings.h>
29  #include "rdesktop.h"  #include "rdesktop.h"
30  #include "xproto.h"  #include "xproto.h"
31    
32  extern int g_width;  extern int g_width;
33  extern int g_height;  extern int g_height;
34  extern BOOL g_sendmotion;  extern int g_xpos;
35  extern BOOL g_fullscreen;  extern int g_ypos;
36  extern BOOL g_grab_keyboard;  extern int g_pos;
37  extern BOOL g_hide_decorations;  extern RD_BOOL g_sendmotion;
38    extern RD_BOOL g_fullscreen;
39    extern RD_BOOL g_grab_keyboard;
40    extern RD_BOOL g_hide_decorations;
41  extern char g_title[];  extern char g_title[];
42  extern int g_server_bpp;  /* Color depth of the RDP session.
43       As of RDP 5.1, it may be 8, 15, 16 or 24. */
44    extern int g_server_depth;
45  extern int g_win_button_size;  extern int g_win_button_size;
46    
47  Display *g_display;  Display *g_display;
# Line 41  Time g_last_gesturetime; Line 49  Time g_last_gesturetime;
49  static int g_x_socket;  static int g_x_socket;
50  static Screen *g_screen;  static Screen *g_screen;
51  Window g_wnd;  Window g_wnd;
52  BOOL g_enable_compose = False;  
53  static GC g_gc;  /* SeamlessRDP support */
54    typedef struct _seamless_group
55    {
56            Window wnd;
57            unsigned long id;
58            unsigned int refcnt;
59    } seamless_group;
60    typedef struct _seamless_window
61    {
62            Window wnd;
63            unsigned long id;
64            unsigned long behind;
65            seamless_group *group;
66            int xoffset, yoffset;
67            int width, height;
68            int state;              /* normal/minimized/maximized. */
69            unsigned int desktop;
70            struct timeval *position_timer;
71    
72            RD_BOOL outstanding_position;
73            unsigned int outpos_serial;
74            int outpos_xoffset, outpos_yoffset;
75            int outpos_width, outpos_height;
76    
77            struct _seamless_window *next;
78    } seamless_window;
79    static seamless_window *g_seamless_windows = NULL;
80    static unsigned long g_seamless_focused = 0;
81    static RD_BOOL g_seamless_started = False;      /* Server end is up and running */
82    static RD_BOOL g_seamless_active = False;       /* We are currently in seamless mode */
83    static RD_BOOL g_seamless_hidden = False;       /* Desktop is hidden on server */
84    extern RD_BOOL g_seamless_rdp;
85    
86    extern uint32 g_embed_wnd;
87    RD_BOOL g_enable_compose = False;
88    RD_BOOL g_Unobscured;           /* used for screenblt */
89    static GC g_gc = NULL;
90    static GC g_create_bitmap_gc = NULL;
91    static GC g_create_glyph_gc = NULL;
92    static XRectangle g_clip_rectangle;
93  static Visual *g_visual;  static Visual *g_visual;
94    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
95       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
96       as far as we're concerned. */
97  static int g_depth;  static int g_depth;
98    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
99       This may be larger than g_depth, in which case some of the bits would
100       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
101  static int g_bpp;  static int g_bpp;
102  static XIM g_IM;  static XIM g_IM;
103  static XIC g_IC;  static XIC g_IC;
104  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
105    /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
106       to physical (1-based) indices. */
107    static unsigned char g_pointer_log_to_phys_map[16];
108  static Cursor g_current_cursor;  static Cursor g_current_cursor;
109  static HCURSOR g_null_cursor;  static RD_HCURSOR g_null_cursor = NULL;
110  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
111  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
112  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
113    static RD_BOOL g_focused;
114    static RD_BOOL g_mouse_in_wnd;
115    /* Indicates that:
116       1) visual has 15, 16 or 24 depth and the same color channel masks
117          as its RDP equivalent (implies X server is LE),
118       2) host is LE
119       This will trigger an optimization whose real value is questionable.
120    */
121    static RD_BOOL g_compatible_arch;
122    /* Indicates whether RDP's bitmaps and our XImages have the same
123       binary format. If so, we can avoid an expensive translation.
124       Note that this can be true when g_compatible_arch is false,
125       e.g.:
126      
127         RDP(LE) <-> host(BE) <-> X-Server(LE)
128        
129       ('host' is the machine running rdesktop; the host simply memcpy's
130        so its endianess doesn't matter)
131     */
132    static RD_BOOL g_no_translate_image = False;
133    
134  /* endianness */  /* endianness */
135  static BOOL g_host_be;  static RD_BOOL g_host_be;
136  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
137  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
138  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;
139    
140  /* software backing store */  /* software backing store */
141  static BOOL g_ownbackstore;  extern RD_BOOL g_ownbackstore;
142  static Pixmap g_backstore;  static Pixmap g_backstore = 0;
143    
144  /* Moving in single app mode */  /* Moving in single app mode */
145  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
146  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
147  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
148    static RD_BOOL g_using_full_workarea = False;
149    
150  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
151  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
152  #endif  #endif
153    
154  /* MWM decorations */  /* MWM decorations */
# Line 81  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 97  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                    if (!g_seamless_windows) break; \
180                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
181                        rect.x = g_clip_rectangle.x - sw->xoffset; \
182                        rect.y = g_clip_rectangle.y - sw->yoffset; \
183                        rect.width = g_clip_rectangle.width; \
184                        rect.height = g_clip_rectangle.height; \
185                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
186                        func args; \
187                    } \
188                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
189            } while (0)
190    
191    static void
192    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
193    {
194            points[0].x -= xoffset;
195            points[0].y -= yoffset;
196            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
197            points[0].x += xoffset;
198            points[0].y += yoffset;
199    }
200    
201    static void
202    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
203    {
204            points[0].x -= xoffset;
205            points[0].y -= yoffset;
206            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
207            points[0].x += xoffset;
208            points[0].y += yoffset;
209    }
210    
211  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
212  { \  { \
213          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
214            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
215          if (g_ownbackstore) \          if (g_ownbackstore) \
216                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
217  }  }
# Line 110  PixelColour; Line 221  PixelColour;
221          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); \
222  }  }
223    
224    #define FILL_POLYGON(p,np)\
225    { \
226            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
227            if (g_ownbackstore) \
228                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
229            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
230    }
231    
232    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
233    { \
234            switch (m) \
235            { \
236                    case 0: /* Outline */ \
237                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
238                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
239                            if (g_ownbackstore) \
240                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
241                            break; \
242                    case 1: /* Filled */ \
243                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
244                            ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
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 RD_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 141  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->position_timer);
324                            xfree(sw);
325                            return;
326                    }
327                    prevnext = &sw->next;
328            }
329            return;
330    }
331    
332    
333    /* Move all windows except wnd to new desktop */
334    static void
335    sw_all_to_desktop(Window wnd, unsigned int desktop)
336    {
337            seamless_window *sw;
338            for (sw = g_seamless_windows; sw; sw = sw->next)
339            {
340                    if (sw->wnd == wnd)
341                            continue;
342                    if (sw->desktop != desktop)
343                    {
344                            ewmh_move_to_desktop(sw->wnd, desktop);
345                            sw->desktop = desktop;
346                    }
347            }
348    }
349    
350    
351    /* Send our position */
352    static void
353    sw_update_position(seamless_window * sw)
354    {
355            XWindowAttributes wa;
356            int x, y;
357            Window child_return;
358            unsigned int serial;
359    
360            XGetWindowAttributes(g_display, sw->wnd, &wa);
361            XTranslateCoordinates(g_display, sw->wnd, wa.root,
362                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
363    
364            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
365    
366            sw->outstanding_position = True;
367            sw->outpos_serial = serial;
368    
369            sw->outpos_xoffset = x;
370            sw->outpos_yoffset = y;
371            sw->outpos_width = wa.width;
372            sw->outpos_height = wa.height;
373    }
374    
375    
376    /* Check if it's time to send our position */
377  static void  static void
378  mwm_hide_decorations(void)  sw_check_timers()
379    {
380            seamless_window *sw;
381            struct timeval now;
382    
383            gettimeofday(&now, NULL);
384            for (sw = g_seamless_windows; sw; sw = sw->next)
385            {
386                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
387                    {
388                            timerclear(sw->position_timer);
389                            sw_update_position(sw);
390                    }
391            }
392    }
393    
394    
395    static void
396    sw_restack_window(seamless_window * sw, unsigned long behind)
397    {
398            seamless_window *sw_above;
399    
400            /* Remove window from stack */
401            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
402            {
403                    if (sw_above->behind == sw->id)
404                            break;
405            }
406    
407            if (sw_above)
408                    sw_above->behind = sw->behind;
409    
410            /* And then add it at the new position */
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                            goto end;
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                    goto end;
456            if (sw_below && (sw_below->id == sw->behind))
457                    goto end;
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          end:
471            XFree(children);
472    }
473    
474    
475    static seamless_group *
476    sw_find_group(unsigned long id, RD_BOOL dont_create)
477    {
478            seamless_window *sw;
479            seamless_group *sg;
480            XSetWindowAttributes attribs;
481    
482            for (sw = g_seamless_windows; sw; sw = sw->next)
483            {
484                    if (sw->group->id == id)
485                            return sw->group;
486            }
487    
488            if (dont_create)
489                    return NULL;
490    
491            sg = xmalloc(sizeof(seamless_group));
492    
493            sg->wnd =
494                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
495                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
496    
497            sg->id = id;
498            sg->refcnt = 0;
499    
500            return sg;
501    }
502    
503    
504    static void
505    mwm_hide_decorations(Window wnd)
506  {  {
507          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
508          Atom hintsatom;          Atom hintsatom;
# Line 159  mwm_hide_decorations(void) Line 519  mwm_hide_decorations(void)
519                  return;                  return;
520          }          }
521    
522          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
523                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
524    
525  }  }
526    
527  static PixelColour  #define SPLITCOLOUR15(colour, rv) \
528  split_colour15(uint32 colour)  { \
529  {          rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
530          PixelColour rv;          rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
531          rv.red = (colour & 0x7c00) >> 10;          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
         rv.red = (rv.red * 0xff) / 0x1f;  
         rv.green = (colour & 0x03e0) >> 5;  
         rv.green = (rv.green * 0xff) / 0x1f;  
         rv.blue = (colour & 0x1f);  
         rv.blue = (rv.blue * 0xff) / 0x1f;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour16(uint32 colour)  
 {  
         PixelColour rv;  
         rv.red = (colour & 0xf800) >> 11;  
         rv.red = (rv.red * 0xff) / 0x1f;  
         rv.green = (colour & 0x07e0) >> 5;  
         rv.green = (rv.green * 0xff) / 0x3f;  
         rv.blue = (colour & 0x001f);  
         rv.blue = (rv.blue * 0xff) / 0x1f;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour24(uint32 colour)  
 {  
         PixelColour rv;  
         rv.blue = (colour & 0xff0000) >> 16;  
         rv.green = (colour & 0xff00) >> 8;  
         rv.red = (colour & 0xff);  
         return rv;  
532  }  }
533    
534  static uint32  #define SPLITCOLOUR16(colour, rv) \
535  make_colour(PixelColour pc)  { \
536  {          rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
537          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
538                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
539                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));  } \
540    
541    #define SPLITCOLOUR24(colour, rv) \
542    { \
543            rv.blue = (colour & 0xff0000) >> 16; \
544            rv.green = (colour & 0x00ff00) >> 8; \
545            rv.red = (colour & 0x0000ff); \
546  }  }
547    
548    #define MAKECOLOUR(pc) \
549            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
550                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
551                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
552    
553  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
554  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
555  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
556                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
557    
558    /* The following macros output the same octet sequences
559       on both BE and LE hosts: */
560    
561    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
562    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
563    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
564    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
565    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
566    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
567    
568  static uint32  static uint32
569  translate_colour(uint32 colour)  translate_colour(uint32 colour)
570  {  {
571          PixelColour pc;          PixelColour pc;
572          switch (g_server_bpp)          switch (g_server_depth)
573          {          {
574                  case 15:                  case 15:
575                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
576                          break;                          break;
577                  case 16:                  case 16:
578                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
579                          break;                          break;
580                  case 24:                  case 24:
581                          pc = split_colour24(colour);                          SPLITCOLOUR24(colour, pc);
582                            break;
583                    default:
584                            /* Avoid warning */
585                            pc.red = 0;
586                            pc.green = 0;
587                            pc.blue = 0;
588                          break;                          break;
589          }          }
590          return make_colour(pc);          return MAKECOLOUR(pc);
591    }
592    
593    /* indent is confused by UNROLL8 */
594    /* *INDENT-OFF* */
595    
596    /* repeat and unroll, similar to bitmap.c */
597    /* potentialy any of the following translate */
598    /* functions can use repeat but just doing */
599    /* the most common ones */
600    
601    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
602    /* 2 byte output repeat */
603    #define REPEAT2(stm) \
604    { \
605            while (out <= end - 8 * 2) \
606                    UNROLL8(stm) \
607            while (out < end) \
608                    { stm } \
609    }
610    /* 3 byte output repeat */
611    #define REPEAT3(stm) \
612    { \
613            while (out <= end - 8 * 3) \
614                    UNROLL8(stm) \
615            while (out < end) \
616                    { stm } \
617    }
618    /* 4 byte output repeat */
619    #define REPEAT4(stm) \
620    { \
621            while (out <= end - 8 * 4) \
622                    UNROLL8(stm) \
623            while (out < end) \
624                    { stm } \
625  }  }
626    /* *INDENT-ON* */
627    
628  static void  static void
629  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
630  {  {
631          while (out < end)          while (out < end)
632                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
633  }  }
634    
635  static void  static void
636  translate8to16(uint8 * data, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
637  {  {
638          uint16 value;          uint16 value;
639    
640          while (out < end)          if (g_compatible_arch)
641          {          {
642                  value = (uint16) g_colmap[*(data++)];                  /* *INDENT-OFF* */
643                    REPEAT2
644                  if (g_xserver_be)                  (
645                            *((uint16 *) out) = g_colmap[*(data++)];
646                            out += 2;
647                    )
648                    /* *INDENT-ON* */
649            }
650            else if (g_xserver_be)
651            {
652                    while (out < end)
653                  {                  {
654                          *(out++) = value >> 8;                          value = (uint16) g_colmap[*(data++)];
655                          *(out++) = value;                          BOUT16(out, value);
656                  }                  }
657                  else          }
658            else
659            {
660                    while (out < end)
661                  {                  {
662                          *(out++) = value;                          value = (uint16) g_colmap[*(data++)];
663                          *(out++) = value >> 8;                          LOUT16(out, value);
664                  }                  }
665          }          }
666  }  }
667    
668  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
669  static void  static void
670  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
671  {  {
672          uint32 value;          uint32 value;
673    
674          while (out < end)          if (g_compatible_arch)
675          {          {
676                  value = g_colmap[*(data++)];                  while (out < end)
   
                 if (g_xserver_be)  
677                  {                  {
678                          *(out++) = value >> 16;                          value = g_colmap[*(data++)];
679                          *(out++) = value >> 8;                          BOUT24(out, value);
                         *(out++) = value;  
680                  }                  }
681                  else          }
682            else
683            {
684                    while (out < end)
685                  {                  {
686                          *(out++) = value;                          value = g_colmap[*(data++)];
687                          *(out++) = value >> 8;                          LOUT24(out, value);
                         *(out++) = value >> 16;  
688                  }                  }
689          }          }
690  }  }
691    
692  static void  static void
693  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
694  {  {
695          uint32 value;          uint32 value;
696    
697          while (out < end)          if (g_compatible_arch)
698          {          {
699                  value = g_colmap[*(data++)];                  /* *INDENT-OFF* */
700                    REPEAT4
701                  if (g_xserver_be)                  (
702                            *((uint32 *) out) = g_colmap[*(data++)];
703                            out += 4;
704                    )
705                    /* *INDENT-ON* */
706            }
707            else if (g_xserver_be)
708            {
709                    while (out < end)
710                  {                  {
711                          *(out++) = value >> 24;                          value = g_colmap[*(data++)];
712                          *(out++) = value >> 16;                          BOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
713                  }                  }
714                  else          }
715            else
716            {
717                    while (out < end)
718                  {                  {
719                          *(out++) = value;                          value = g_colmap[*(data++)];
720                          *(out++) = value >> 8;                          LOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
721                  }                  }
722          }          }
723  }  }
724    
 /* todo the remaining translate function might need some big endian check ?? */  
   
725  static void  static void
726  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
727  {  {
728          uint16 pixel;          uint16 pixel;
729          uint16 value;          uint16 value;
730            PixelColour pc;
731    
732          while (out < end)          if (g_xserver_be)
733          {          {
734                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
735                  {                  {
736                          BSWAP16(pixel);                          pixel = *(data++);
737                  }                          if (g_host_be)
738                            {
739                  value = make_colour(split_colour15(pixel));                                  BSWAP16(pixel);
740                            }
741                  if (g_xserver_be)                          SPLITCOLOUR15(pixel, pc);
742                  {                          value = MAKECOLOUR(pc);
743                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
744                  }                  }
745                  else          }
746            else
747            {
748                    while (out < end)
749                  {                  {
750                          *(out++) = value;                          pixel = *(data++);
751                          *(out++) = value >> 8;                          if (g_host_be)
752                            {
753                                    BSWAP16(pixel);
754                            }
755                            SPLITCOLOUR15(pixel, pc);
756                            value = MAKECOLOUR(pc);
757                            LOUT16(out, value);
758                  }                  }
759          }          }
760  }  }
761    
762  static void  static void
763  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
764  {  {
765          uint32 value;          uint32 value;
766          uint16 pixel;          uint16 pixel;
767            PixelColour pc;
768    
769          while (out < end)          if (g_compatible_arch)
770          {          {
771                  pixel = *(data++);                  /* *INDENT-OFF* */
772                    REPEAT3
773                  if (g_host_be)                  (
774                  {                          pixel = *(data++);
775                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
776                  }                          *(out++) = pc.blue;
777                            *(out++) = pc.green;
778                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
779                  if (g_xserver_be)                  )
780                    /* *INDENT-ON* */
781            }
782            else if (g_xserver_be)
783            {
784                    while (out < end)
785                  {                  {
786                          *(out++) = value >> 16;                          pixel = *(data++);
787                          *(out++) = value >> 8;                          if (g_host_be)
788                          *(out++) = value;                          {
789                                    BSWAP16(pixel);
790                            }
791                            SPLITCOLOUR15(pixel, pc);
792                            value = MAKECOLOUR(pc);
793                            BOUT24(out, value);
794                  }                  }
795                  else          }
796            else
797            {
798                    while (out < end)
799                  {                  {
800                          *(out++) = value;                          pixel = *(data++);
801                          *(out++) = value >> 8;                          if (g_host_be)
802                          *(out++) = value >> 16;                          {
803                                    BSWAP16(pixel);
804                            }
805                            SPLITCOLOUR15(pixel, pc);
806                            value = MAKECOLOUR(pc);
807                            LOUT24(out, value);
808                  }                  }
809          }          }
810  }  }
811    
812  static void  static void
813  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
814  {  {
815          uint16 pixel;          uint16 pixel;
816          uint32 value;          uint32 value;
817            PixelColour pc;
818    
819          while (out < end)          if (g_compatible_arch)
820          {          {
821                  pixel = *(data++);                  /* *INDENT-OFF* */
822                    REPEAT4
823                  if (g_host_be)                  (
824                  {                          pixel = *(data++);
825                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
826                  }                          *(out++) = pc.blue;
827                            *(out++) = pc.green;
828                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
829                            *(out++) = 0;
830                  if (g_xserver_be)                  )
831                    /* *INDENT-ON* */
832            }
833            else if (g_xserver_be)
834            {
835                    while (out < end)
836                  {                  {
837                          *(out++) = value >> 24;                          pixel = *(data++);
838                          *(out++) = value >> 16;                          if (g_host_be)
839                          *(out++) = value >> 8;                          {
840                          *(out++) = value;                                  BSWAP16(pixel);
841                            }
842                            SPLITCOLOUR15(pixel, pc);
843                            value = MAKECOLOUR(pc);
844                            BOUT32(out, value);
845                  }                  }
846                  else          }
847            else
848            {
849                    while (out < end)
850                  {                  {
851                          *(out++) = value;                          pixel = *(data++);
852                          *(out++) = value >> 8;                          if (g_host_be)
853                          *(out++) = value >> 16;                          {
854                          *(out++) = value >> 24;                                  BSWAP16(pixel);
855                            }
856                            SPLITCOLOUR15(pixel, pc);
857                            value = MAKECOLOUR(pc);
858                            LOUT32(out, value);
859                  }                  }
860          }          }
861  }  }
862    
863  static void  static void
864  translate16to16(uint16 * data, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
865  {  {
866          uint16 pixel;          uint16 pixel;
867          uint16 value;          uint16 value;
868            PixelColour pc;
869    
870          while (out < end)          if (g_xserver_be)
871          {          {
                 pixel = *(data++);  
   
872                  if (g_host_be)                  if (g_host_be)
873                  {                  {
874                          BSWAP16(pixel);                          while (out < end)
875                            {
876                                    pixel = *(data++);
877                                    BSWAP16(pixel);
878                                    SPLITCOLOUR16(pixel, pc);
879                                    value = MAKECOLOUR(pc);
880                                    BOUT16(out, value);
881                            }
882                  }                  }
883                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
884                  {                  {
885                          *(out++) = value >> 8;                          while (out < end)
886                          *(out++) = value;                          {
887                                    pixel = *(data++);
888                                    SPLITCOLOUR16(pixel, pc);
889                                    value = MAKECOLOUR(pc);
890                                    BOUT16(out, value);
891                            }
892                    }
893            }
894            else
895            {
896                    if (g_host_be)
897                    {
898                            while (out < end)
899                            {
900                                    pixel = *(data++);
901                                    BSWAP16(pixel);
902                                    SPLITCOLOUR16(pixel, pc);
903                                    value = MAKECOLOUR(pc);
904                                    LOUT16(out, value);
905                            }
906                  }                  }
907                  else                  else
908                  {                  {
909                          *(out++) = value;                          while (out < end)
910                          *(out++) = value >> 8;                          {
911                                    pixel = *(data++);
912                                    SPLITCOLOUR16(pixel, pc);
913                                    value = MAKECOLOUR(pc);
914                                    LOUT16(out, value);
915                            }
916                  }                  }
917          }          }
918  }  }
919    
920  static void  static void
921  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
922  {  {
923          uint32 value;          uint32 value;
924          uint16 pixel;          uint16 pixel;
925            PixelColour pc;
926    
927          while (out < end)          if (g_compatible_arch)
928            {
929                    /* *INDENT-OFF* */
930                    REPEAT3
931                    (
932                            pixel = *(data++);
933                            SPLITCOLOUR16(pixel, pc);
934                            *(out++) = pc.blue;
935                            *(out++) = pc.green;
936                            *(out++) = pc.red;
937                    )
938                    /* *INDENT-ON* */
939            }
940            else if (g_xserver_be)
941          {          {
                 pixel = *(data++);  
   
942                  if (g_host_be)                  if (g_host_be)
943                  {                  {
944                          BSWAP16(pixel);                          while (out < end)
945                            {
946                                    pixel = *(data++);
947                                    BSWAP16(pixel);
948                                    SPLITCOLOUR16(pixel, pc);
949                                    value = MAKECOLOUR(pc);
950                                    BOUT24(out, value);
951                            }
952                  }                  }
953                    else
954                  value = make_colour(split_colour16(pixel));                  {
955                            while (out < end)
956                  if (g_xserver_be)                          {
957                                    pixel = *(data++);
958                                    SPLITCOLOUR16(pixel, pc);
959                                    value = MAKECOLOUR(pc);
960                                    BOUT24(out, value);
961                            }
962                    }
963            }
964            else
965            {
966                    if (g_host_be)
967                  {                  {
968                          *(out++) = value >> 16;                          while (out < end)
969                          *(out++) = value >> 8;                          {
970                          *(out++) = value;                                  pixel = *(data++);
971                                    BSWAP16(pixel);
972                                    SPLITCOLOUR16(pixel, pc);
973                                    value = MAKECOLOUR(pc);
974                                    LOUT24(out, value);
975                            }
976                  }                  }
977                  else                  else
978                  {                  {
979                          *(out++) = value;                          while (out < end)
980                          *(out++) = value >> 8;                          {
981                          *(out++) = value >> 16;                                  pixel = *(data++);
982                                    SPLITCOLOUR16(pixel, pc);
983                                    value = MAKECOLOUR(pc);
984                                    LOUT24(out, value);
985                            }
986                  }                  }
987          }          }
988  }  }
989    
990  static void  static void
991  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
992  {  {
993          uint16 pixel;          uint16 pixel;
994          uint32 value;          uint32 value;
995            PixelColour pc;
996    
997          while (out < end)          if (g_compatible_arch)
998            {
999                    /* *INDENT-OFF* */
1000                    REPEAT4
1001                    (
1002                            pixel = *(data++);
1003                            SPLITCOLOUR16(pixel, pc);
1004                            *(out++) = pc.blue;
1005                            *(out++) = pc.green;
1006                            *(out++) = pc.red;
1007                            *(out++) = 0;
1008                    )
1009                    /* *INDENT-ON* */
1010            }
1011            else if (g_xserver_be)
1012          {          {
                 pixel = *(data++);  
   
1013                  if (g_host_be)                  if (g_host_be)
1014                  {                  {
1015                          BSWAP16(pixel);                          while (out < end)
1016                            {
1017                                    pixel = *(data++);
1018                                    BSWAP16(pixel);
1019                                    SPLITCOLOUR16(pixel, pc);
1020                                    value = MAKECOLOUR(pc);
1021                                    BOUT32(out, value);
1022                            }
1023                  }                  }
1024                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
1025                  {                  {
1026                          *(out++) = value >> 24;                          while (out < end)
1027                          *(out++) = value >> 16;                          {
1028                          *(out++) = value >> 8;                                  pixel = *(data++);
1029                          *(out++) = value;                                  SPLITCOLOUR16(pixel, pc);
1030                                    value = MAKECOLOUR(pc);
1031                                    BOUT32(out, value);
1032                            }
1033                    }
1034            }
1035            else
1036            {
1037                    if (g_host_be)
1038                    {
1039                            while (out < end)
1040                            {
1041                                    pixel = *(data++);
1042                                    BSWAP16(pixel);
1043                                    SPLITCOLOUR16(pixel, pc);
1044                                    value = MAKECOLOUR(pc);
1045                                    LOUT32(out, value);
1046                            }
1047                  }                  }
1048                  else                  else
1049                  {                  {
1050                          *(out++) = value;                          while (out < end)
1051                          *(out++) = value >> 8;                          {
1052                          *(out++) = value >> 16;                                  pixel = *(data++);
1053                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
1054                                    value = MAKECOLOUR(pc);
1055                                    LOUT32(out, value);
1056                            }
1057                  }                  }
1058          }          }
1059  }  }
1060    
1061  static void  static void
1062  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1063  {  {
1064          uint32 pixel = 0;          uint32 pixel = 0;
1065          uint16 value;          uint16 value;
1066            PixelColour pc;
1067    
1068          while (out < end)          while (out < end)
1069          {          {
1070                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1071                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1072                  pixel |= *(data++);                  pixel |= *(data++);
1073                    SPLITCOLOUR24(pixel, pc);
1074                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1075                  if (g_xserver_be)                  if (g_xserver_be)
1076                  {                  {
1077                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1078                  }                  }
1079                  else                  else
1080                  {                  {
1081                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1082                  }                  }
1083          }          }
1084  }  }
1085    
1086  static void  static void
1087  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1088  {  {
1089          uint32 pixel;          uint32 pixel;
1090          uint32 value;          uint32 value;
1091            PixelColour pc;
1092    
1093          while (out < end)          if (g_xserver_be)
1094          {          {
1095                  pixel = *(data++) << 16;                  while (out < end)
                 pixel |= *(data++) << 8;  
                 pixel |= *(data++);  
   
                 value = make_colour(split_colour24(pixel));  
   
                 if (g_xserver_be)  
1096                  {                  {
1097                          *(out++) = value >> 16;                          pixel = *(data++) << 16;
1098                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1099                          *(out++) = value;                          pixel |= *(data++);
1100                            SPLITCOLOUR24(pixel, pc);
1101                            value = MAKECOLOUR(pc);
1102                            BOUT24(out, value);
1103                  }                  }
1104                  else          }
1105            else
1106            {
1107                    while (out < end)
1108                  {                  {
1109                          *(out++) = value;                          pixel = *(data++) << 16;
1110                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1111                          *(out++) = value >> 16;                          pixel |= *(data++);
1112                            SPLITCOLOUR24(pixel, pc);
1113                            value = MAKECOLOUR(pc);
1114                            LOUT24(out, value);
1115                  }                  }
1116          }          }
1117  }  }
1118    
1119  static void  static void
1120  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1121  {  {
1122          uint32 pixel;          uint32 pixel;
1123          uint32 value;          uint32 value;
1124            PixelColour pc;
1125    
1126          while (out < end)          if (g_compatible_arch)
1127          {          {
1128                  pixel = *(data++) << 16;                  /* *INDENT-OFF* */
1129                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
1130                  pixel |= *(data++);                  REPEAT4
1131                    (
1132                  value = make_colour(split_colour24(pixel));                          *(out++) = *(data++);
1133                            *(out++) = *(data++);
1134                  if (g_xserver_be)                          *(out++) = *(data++);
1135                            *(out++) = 0;
1136                    )
1137    #else
1138                    REPEAT4
1139                    (
1140                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1141                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1142                     out += 4;
1143                     data += 3;
1144                    )
1145    #endif
1146                    /* *INDENT-ON* */
1147            }
1148            else if (g_xserver_be)
1149            {
1150                    while (out < end)
1151                  {                  {
1152                          *(out++) = value >> 24;                          pixel = *(data++) << 16;
1153                          *(out++) = value >> 16;                          pixel |= *(data++) << 8;
1154                          *(out++) = value >> 8;                          pixel |= *(data++);
1155                          *(out++) = value;                          SPLITCOLOUR24(pixel, pc);
1156                            value = MAKECOLOUR(pc);
1157                            BOUT32(out, value);
1158                  }                  }
1159                  else          }
1160            else
1161            {
1162                    while (out < end)
1163                  {                  {
1164                          *(out++) = value;                          pixel = *(data++) << 16;
1165                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1166                          *(out++) = value >> 16;                          pixel |= *(data++);
1167                          *(out++) = value >> 24;                          SPLITCOLOUR24(pixel, pc);
1168                            value = MAKECOLOUR(pc);
1169                            LOUT32(out, value);
1170                  }                  }
1171          }          }
1172  }  }
# Line 593  translate24to32(uint8 * data, uint8 * ou Line 1174  translate24to32(uint8 * data, uint8 * ou
1174  static uint8 *  static uint8 *
1175  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1176  {  {
1177          int size = width * height * g_bpp / 8;          int size;
1178          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1179          uint8 *end = out + size;          uint8 *end;
1180    
1181            /*
1182               If RDP depth and X Visual depths match,
1183               and arch(endian) matches, no need to translate:
1184               just return data.
1185               Note: select_visual should've already ensured g_no_translate
1186               is only set for compatible depths, but the RDP depth might've
1187               changed during connection negotiations.
1188             */
1189            if (g_no_translate_image)
1190            {
1191                    if ((g_depth == 15 && g_server_depth == 15) ||
1192                        (g_depth == 16 && g_server_depth == 16) ||
1193                        (g_depth == 24 && g_server_depth == 24))
1194                            return data;
1195            }
1196    
1197            size = width * height * (g_bpp / 8);
1198            out = (uint8 *) xmalloc(size);
1199            end = out + size;
1200    
1201          switch (g_server_bpp)          switch (g_server_depth)
1202          {          {
1203                  case 24:                  case 24:
1204                          switch (g_bpp)                          switch (g_bpp)
# Line 662  translate_image(int width, int height, u Line 1263  translate_image(int width, int height, u
1263          return out;          return out;
1264  }  }
1265    
1266  BOOL  static void
1267    xwin_refresh_pointer_map(void)
1268    {
1269            unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
1270            int i, pointer_buttons;
1271    
1272            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1273            for (i = 0; i < pointer_buttons; ++i)
1274            {
1275                    /* This might produce multiple logical buttons mapping
1276                       to a single physical one, but hey, that's
1277                       life... */
1278                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1279            }
1280    }
1281    
1282    RD_BOOL
1283  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1284  {  {
1285          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 695  calculate_shifts(uint32 mask, int *shift Line 1312  calculate_shifts(uint32 mask, int *shift
1312          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1313  }  }
1314    
1315  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1316  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1317     */
1318    static unsigned
1319    calculate_mask_weight(uint32 mask)
1320    {
1321            unsigned weight = 0;
1322            do
1323            {
1324                    weight += (mask & 1);
1325            }
1326            while (mask >>= 1);
1327            return weight;
1328    }
1329    
1330    static RD_BOOL
1331    select_visual(int screen_num)
1332  {  {
         XVisualInfo vi;  
1333          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1334          uint16 test;          int pixmap_formats_count, visuals_count;
1335          int i, screen_num;          XVisualInfo *vmatches = NULL;
1336            XVisualInfo template;
1337            int i;
1338            unsigned red_weight, blue_weight, green_weight;
1339    
1340          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1341          if (g_display == NULL)  
1342            if (g_server_depth == -1)
1343          {          {
1344                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1345            }
1346    
1347            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1348            if (pfm == NULL)
1349            {
1350                    error("Unable to get list of pixmap formats from display.\n");
1351                    XCloseDisplay(g_display);
1352                  return False;                  return False;
1353          }          }
1354    
1355          screen_num = DefaultScreen(g_display);          /* Search for best TrueColor visual */
1356          g_x_socket = ConnectionNumber(g_display);          template.class = TrueColor;
1357          g_screen = ScreenOfDisplay(g_display, screen_num);          template.screen = screen_num;
1358          g_depth = DefaultDepthOfScreen(g_screen);          vmatches =
1359                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1360                                   &visuals_count);
1361            g_visual = NULL;
1362            g_no_translate_image = False;
1363            g_compatible_arch = False;
1364            if (vmatches != NULL)
1365            {
1366                    for (i = 0; i < visuals_count; ++i)
1367                    {
1368                            XVisualInfo *visual_info = &vmatches[i];
1369                            RD_BOOL can_translate_to_bpp = False;
1370                            int j;
1371    
1372                            /* Try to find a no-translation visual that'll
1373                               allow us to use RDP bitmaps directly as ZPixmaps. */
1374                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1375                                                   /* R5G5B5 */
1376                                                   (visual_info->red_mask == 0x7c00) &&
1377                                                   (visual_info->green_mask == 0x3e0) &&
1378                                                   (visual_info->blue_mask == 0x1f)) ||
1379                                                  ((visual_info->depth == 16) &&
1380                                                   /* R5G6B5 */
1381                                                   (visual_info->red_mask == 0xf800) &&
1382                                                   (visual_info->green_mask == 0x7e0) &&
1383                                                   (visual_info->blue_mask == 0x1f)) ||
1384                                                  ((visual_info->depth == 24) &&
1385                                                   /* R8G8B8 */
1386                                                   (visual_info->red_mask == 0xff0000) &&
1387                                                   (visual_info->green_mask == 0xff00) &&
1388                                                   (visual_info->blue_mask == 0xff))))
1389                            {
1390                                    g_visual = visual_info->visual;
1391                                    g_depth = visual_info->depth;
1392                                    g_compatible_arch = !g_host_be;
1393                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1394                                    if (g_no_translate_image)
1395                                            /* We found the best visual */
1396                                            break;
1397                            }
1398                            else
1399                            {
1400                                    g_compatible_arch = False;
1401                            }
1402    
1403                            if (visual_info->depth > 24)
1404                            {
1405                                    /* Avoid 32-bit visuals and likes like the plague.
1406                                       They're either untested or proven to work bad
1407                                       (e.g. nvidia's Composite 32-bit visual).
1408                                       Most implementation offer a 24-bit visual anyway. */
1409                                    continue;
1410                            }
1411    
1412          if (g_server_bpp == 8)                          /* Only care for visuals, for whose BPPs (not depths!)
1413                               we have a translateXtoY function. */
1414                            for (j = 0; j < pixmap_formats_count; ++j)
1415                            {
1416                                    if (pfm[j].depth == visual_info->depth)
1417                                    {
1418                                            if ((pfm[j].bits_per_pixel == 16) ||
1419                                                (pfm[j].bits_per_pixel == 24) ||
1420                                                (pfm[j].bits_per_pixel == 32))
1421                                            {
1422                                                    can_translate_to_bpp = True;
1423                                            }
1424                                            break;
1425                                    }
1426                            }
1427    
1428                            /* Prefer formats which have the most colour depth.
1429                               We're being truly aristocratic here, minding each
1430                               weight on its own. */
1431                            if (can_translate_to_bpp)
1432                            {
1433                                    unsigned vis_red_weight =
1434                                            calculate_mask_weight(visual_info->red_mask);
1435                                    unsigned vis_green_weight =
1436                                            calculate_mask_weight(visual_info->green_mask);
1437                                    unsigned vis_blue_weight =
1438                                            calculate_mask_weight(visual_info->blue_mask);
1439                                    if ((vis_red_weight >= red_weight)
1440                                        && (vis_green_weight >= green_weight)
1441                                        && (vis_blue_weight >= blue_weight))
1442                                    {
1443                                            red_weight = vis_red_weight;
1444                                            green_weight = vis_green_weight;
1445                                            blue_weight = vis_blue_weight;
1446                                            g_visual = visual_info->visual;
1447                                            g_depth = visual_info->depth;
1448                                    }
1449                            }
1450                    }
1451                    XFree(vmatches);
1452            }
1453    
1454            if (g_visual != NULL)
1455          {          {
1456                  /* we use a colourmap, so any visual should do */                  g_owncolmap = False;
1457                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1458                    calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1459                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1460          }          }
1461          else          else
1462          {          {
1463                  /* need a truecolour visual */                  template.class = PseudoColor;
1464                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1465                  {                  template.colormap_size = 256;
1466                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1467                            XGetVisualInfo(g_display,
1468                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1469                                           &template, &visuals_count);
1470                    if (vmatches == NULL)
1471                    {
1472                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1473                            XCloseDisplay(g_display);
1474                            XFree(pfm);
1475                          return False;                          return False;
1476                  }                  }
1477    
1478                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1479                  g_owncolmap = False;                  g_owncolmap = True;
1480                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1481                  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);  
1482          }          }
1483    
1484          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1485          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1486          {          {
1487                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1488                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1489                  {                  {
1490                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1491    
1492                            if (g_no_translate_image)
1493                          {                          {
1494                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1495                                    {
1496                                            case 15:
1497                                            case 16:
1498                                                    if (g_bpp != 16)
1499                                                            g_no_translate_image = False;
1500                                                    break;
1501                                            case 24:
1502                                                    /* Yes, this will force image translation
1503                                                       on most modern servers which use 32 bits
1504                                                       for R8G8B8. */
1505                                                    if (g_bpp != 24)
1506                                                            g_no_translate_image = False;
1507                                                    break;
1508                                            default:
1509                                                    g_no_translate_image = False;
1510                                                    break;
1511                                    }
1512                          }                          }
1513    
1514                            /* Pixmap formats list is a depth-to-bpp mapping --
1515                               there's just a single entry for every depth,
1516                               so we can safely break here */
1517                            break;
1518                  }                  }
                 XFree(pfm);  
1519          }          }
1520            XFree(pfm);
1521            pfm = NULL;
1522            return True;
1523    }
1524    
1525          if (g_bpp < 8)  static XErrorHandler g_old_error_handler;
1526    
1527    static int
1528    error_handler(Display * dpy, XErrorEvent * eev)
1529    {
1530            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1531          {          {
1532                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1533                  XCloseDisplay(g_display);                  fprintf(stderr,
1534                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1535                    return 0;
1536            }
1537    
1538            return g_old_error_handler(dpy, eev);
1539    }
1540    
1541    RD_BOOL
1542    ui_init(void)
1543    {
1544            int screen_num;
1545    
1546            g_display = XOpenDisplay(NULL);
1547            if (g_display == NULL)
1548            {
1549                    error("Failed to open display: %s\n", XDisplayName(NULL));
1550                  return False;                  return False;
1551          }          }
1552    
1553            {
1554                    uint16 endianess_test = 1;
1555                    g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1556            }
1557    
1558            g_old_error_handler = XSetErrorHandler(error_handler);
1559            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1560            screen_num = DefaultScreen(g_display);
1561            g_x_socket = ConnectionNumber(g_display);
1562            g_screen = ScreenOfDisplay(g_display, screen_num);
1563            g_depth = DefaultDepthOfScreen(g_screen);
1564    
1565            if (!select_visual(screen_num))
1566                    return False;
1567    
1568            if (g_no_translate_image)
1569            {
1570                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1571            }
1572    
1573            if (g_server_depth > g_bpp)
1574            {
1575                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1576                            g_server_depth, g_bpp);
1577            }
1578    
1579            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1580                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1581    
1582          if (!g_owncolmap)          if (!g_owncolmap)
1583          {          {
1584                  g_xcolmap = DefaultColormapOfScreen(g_screen);                  g_xcolmap =
1585                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1586                                            AllocNone);
1587                  if (g_depth <= 8)                  if (g_depth <= 8)
1588                          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);
1589          }          }
1590    
1591          g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1592            {
1593          if (DoesBackingStore(g_screen) != Always)                  warning("External BackingStore not available. Using internal.\n");
1594                  g_ownbackstore = True;                  g_ownbackstore = True;
1595            }
         test = 1;  
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
1596    
1597          /*          /*
1598           * Determine desktop size           * Determine desktop size
1599           */           */
1600          if (g_width < 0)          if (g_fullscreen)
1601            {
1602                    g_width = WidthOfScreen(g_screen);
1603                    g_height = HeightOfScreen(g_screen);
1604                    g_using_full_workarea = True;
1605            }
1606            else if (g_width < 0)
1607          {          {
1608                  /* Percent of screen */                  /* Percent of screen */
1609                    if (-g_width >= 100)
1610                            g_using_full_workarea = True;
1611                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1612                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1613          }          }
# Line 787  ui_init(void) Line 1615  ui_init(void)
1615          {          {
1616                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1617                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1618                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1619                  {                  {
1620                          g_width = cx;                          g_width = cx;
1621                          g_height = cy;                          g_height = cy;
1622                            g_using_full_workarea = True;
1623                  }                  }
1624                  else                  else
1625                  {                  {
1626                          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");
1627                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1628                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1629                  }                  }
1630          }          }
         else if (g_fullscreen)  
         {  
                 g_width = WidthOfScreen(g_screen);  
                 g_height = HeightOfScreen(g_screen);  
         }  
1631    
1632          /* make sure width is a multiple of 4 */          /* make sure width is a multiple of 4 */
1633          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1634    
         if (g_ownbackstore)  
         {  
                 g_backstore =  
                         XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,  
                                       g_depth);  
   
                 /* clear to prevent rubbish being exposed at startup */  
                 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));  
                 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);  
         }  
   
1635          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1636            xwin_refresh_pointer_map();
1637    
1638          xkeymap_init();          xkeymap_init();
1639    
# Line 828  ui_init(void) Line 1641  ui_init(void)
1641                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1642    
1643          xclip_init();          xclip_init();
1644            ewmh_init();
1645            if (g_seamless_rdp)
1646                    seamless_init();
1647    
1648          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));
1649    
1650          return True;          return True;
1651  }  }
# Line 837  ui_init(void) Line 1653  ui_init(void)
1653  void  void
1654  ui_deinit(void)  ui_deinit(void)
1655  {  {
1656            while (g_seamless_windows)
1657            {
1658                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1659                    sw_remove_window(g_seamless_windows);
1660            }
1661    
1662            xclip_deinit();
1663    
1664          if (g_IM != NULL)          if (g_IM != NULL)
1665                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1666    
1667            if (g_null_cursor != NULL)
1668                    ui_destroy_cursor(g_null_cursor);
1669    
1670          XFreeModifiermap(g_mod_map);          XFreeModifiermap(g_mod_map);
1671    
1672          if (g_ownbackstore)          if (g_ownbackstore)
# Line 850  ui_deinit(void) Line 1677  ui_deinit(void)
1677          g_display = NULL;          g_display = NULL;
1678  }  }
1679    
1680  BOOL  
1681    static void
1682    get_window_attribs(XSetWindowAttributes * attribs)
1683    {
1684            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1685            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1686            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1687            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1688            attribs->override_redirect = g_fullscreen;
1689            attribs->colormap = g_xcolmap;
1690    }
1691    
1692    static void
1693    get_input_mask(long *input_mask)
1694    {
1695            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1696                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1697    
1698            if (g_sendmotion)
1699                    *input_mask |= PointerMotionMask;
1700            if (g_ownbackstore)
1701                    *input_mask |= ExposureMask;
1702            if (g_fullscreen || g_grab_keyboard)
1703                    *input_mask |= EnterWindowMask;
1704            if (g_grab_keyboard)
1705                    *input_mask |= LeaveWindowMask;
1706    }
1707    
1708    RD_BOOL
1709  ui_create_window(void)  ui_create_window(void)
1710  {  {
1711          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1712          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1713    
1714          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1715          XClassHint *classhints;          XClassHint *classhints;
1716          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 865  ui_create_window(void) Line 1721  ui_create_window(void)
1721          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1722          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1723    
1724          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1725          attribs.backing_store = g_ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1726          attribs.override_redirect = g_fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1727            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1728          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1729                                0, CopyFromParent, InputOutput, CopyFromParent,  
1730                                CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          get_window_attribs(&attribs);
1731    
1732            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1733                                  wndheight, 0, g_depth, InputOutput, g_visual,
1734                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1735                                  CWBorderPixel, &attribs);
1736    
1737            if (g_gc == NULL)
1738            {
1739                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1740                    ui_reset_clip();
1741            }
1742    
1743            if (g_create_bitmap_gc == NULL)
1744                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1745    
1746            if ((g_ownbackstore) && (g_backstore == 0))
1747            {
1748                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1749    
1750                    /* clear to prevent rubbish being exposed at startup */
1751                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1752                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1753            }
1754    
1755          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1756            ewmh_set_wm_name(g_wnd, g_title);
1757    
1758          if (g_hide_decorations)          if (g_hide_decorations)
1759                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1760    
1761          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1762          if (classhints != NULL)          if (classhints != NULL)
# Line 890  ui_create_window(void) Line 1770  ui_create_window(void)
1770          if (sizehints)          if (sizehints)
1771          {          {
1772                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1773                    if (g_pos)
1774                            sizehints->flags |= PPosition;
1775                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1776                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1777                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1778                  XFree(sizehints);                  XFree(sizehints);
1779          }          }
1780    
1781          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          if (g_embed_wnd)
1782                  VisibilityChangeMask | FocusChangeMask;          {
1783                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1784            }
1785    
1786          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;  
1787    
1788          if (g_IM != NULL)          if (g_IM != NULL)
1789          {          {
# Line 927  ui_create_window(void) Line 1804  ui_create_window(void)
1804                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1805          }          }
1806          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1807            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1808    
1809          g_focused = False;          g_focused = False;
1810          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 937  ui_create_window(void) Line 1815  ui_create_window(void)
1815          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1816    
1817          /* create invisible 1x1 cursor to be used as null cursor */          /* create invisible 1x1 cursor to be used as null cursor */
1818          g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);          if (g_null_cursor == NULL)
1819                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1820    
1821          return True;          return True;
1822  }  }
1823    
1824  void  void
1825    ui_resize_window()
1826    {
1827            XSizeHints *sizehints;
1828            Pixmap bs;
1829    
1830            sizehints = XAllocSizeHints();
1831            if (sizehints)
1832            {
1833                    sizehints->flags = PMinSize | PMaxSize;
1834                    sizehints->min_width = sizehints->max_width = g_width;
1835                    sizehints->min_height = sizehints->max_height = g_height;
1836                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1837                    XFree(sizehints);
1838            }
1839    
1840            if (!(g_fullscreen || g_embed_wnd))
1841            {
1842                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1843            }
1844    
1845            /* create new backstore pixmap */
1846            if (g_backstore != 0)
1847            {
1848                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1849                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1850                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1851                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1852                    XFreePixmap(g_display, g_backstore);
1853                    g_backstore = bs;
1854            }
1855    }
1856    
1857    void
1858  ui_destroy_window(void)  ui_destroy_window(void)
1859  {  {
1860          if (g_IC != NULL)          if (g_IC != NULL)
# Line 956  xwin_toggle_fullscreen(void) Line 1868  xwin_toggle_fullscreen(void)
1868  {  {
1869          Pixmap contents = 0;          Pixmap contents = 0;
1870    
1871            if (g_seamless_active)
1872                    /* Turn off SeamlessRDP mode */
1873                    ui_seamless_toggle();
1874    
1875          if (!g_ownbackstore)          if (!g_ownbackstore)
1876          {          {
1877                  /* need to save contents of window */                  /* need to save contents of window */
# Line 976  xwin_toggle_fullscreen(void) Line 1892  xwin_toggle_fullscreen(void)
1892          }          }
1893  }  }
1894    
1895  /* Process all events in Xlib queue  static void
1896    handle_button_event(XEvent xevent, RD_BOOL down)
1897    {
1898            uint16 button, flags = 0;
1899            g_last_gesturetime = xevent.xbutton.time;
1900            /* Reverse the pointer button mapping, e.g. in the case of
1901               "left-handed mouse mode"; the RDP session expects to
1902               receive physical buttons (true in mstsc as well) and
1903               logical button behavior depends on the remote desktop's own
1904               mouse settings */
1905            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
1906            button = xkeymap_translate_button(xevent.xbutton.button);
1907            if (button == 0)
1908                    return;
1909    
1910            if (down)
1911                    flags = MOUSE_FLAG_DOWN;
1912    
1913            /* Stop moving window when button is released, regardless of cursor position */
1914            if (g_moving_wnd && (xevent.type == ButtonRelease))
1915                    g_moving_wnd = False;
1916    
1917            /* If win_button_size is nonzero, enable single app mode */
1918            if (xevent.xbutton.y < g_win_button_size)
1919            {
1920                    /*  Check from right to left: */
1921                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1922                    {
1923                            /* The close button, continue */
1924                            ;
1925                    }
1926                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1927                    {
1928                            /* The maximize/restore button. Do not send to
1929                               server.  It might be a good idea to change the
1930                               cursor or give some other visible indication
1931                               that rdesktop inhibited this click */
1932                            if (xevent.type == ButtonPress)
1933                                    return;
1934                    }
1935                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1936                    {
1937                            /* The minimize button. Iconify window. */
1938                            if (xevent.type == ButtonRelease)
1939                            {
1940                                    /* Release the mouse button outside the minimize button, to prevent the
1941                                       actual minimazation to happen */
1942                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1943                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1944                                    return;
1945                            }
1946                    }
1947                    else if (xevent.xbutton.x <= g_win_button_size)
1948                    {
1949                            /* The system menu. Ignore. */
1950                            if (xevent.type == ButtonPress)
1951                                    return;
1952                    }
1953                    else
1954                    {
1955                            /* The title bar. */
1956                            if (xevent.type == ButtonPress)
1957                            {
1958                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1959                                    {
1960                                            g_moving_wnd = True;
1961                                            g_move_x_offset = xevent.xbutton.x;
1962                                            g_move_y_offset = xevent.xbutton.y;
1963                                    }
1964                                    return;
1965                            }
1966                    }
1967            }
1968    
1969            if (xevent.xmotion.window == g_wnd)
1970            {
1971                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1972                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1973            }
1974            else
1975            {
1976                    /* SeamlessRDP */
1977                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1978                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1979            }
1980    }
1981    
1982    
1983    /* Process events in Xlib queue
1984     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1985  static int  static int
1986  xwin_process_events(void)  xwin_process_events(void)
1987  {  {
1988          XEvent xevent;          XEvent xevent;
1989          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1990          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1991          char str[256];          char str[256];
1992          Status status;          Status status;
1993          unsigned int state;          int events = 0;
1994          Window wdummy;          seamless_window *sw;
         int dummy;  
1995    
1996          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1997          {          {
1998                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1999    
# Line 1002  xwin_process_events(void) Line 2003  xwin_process_events(void)
2003                          continue;                          continue;
2004                  }                  }
2005    
                 flags = 0;  
   
2006                  switch (xevent.type)                  switch (xevent.type)
2007                  {                  {
2008                            case VisibilityNotify:
2009                                    if (xevent.xvisibility.window == g_wnd)
2010                                            g_Unobscured =
2011                                                    xevent.xvisibility.state == VisibilityUnobscured;
2012    
2013                                    break;
2014                          case ClientMessage:                          case ClientMessage:
2015                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
2016                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 1037  xwin_process_events(void) Line 2042  xwin_process_events(void)
2042                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2043                                  }                                  }
2044    
2045                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2046                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2047    
2048                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2049                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2050                                          break;                                          break;
2051    
2052                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2053                                                             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);  
   
2054                                  break;                                  break;
2055    
2056                          case KeyRelease:                          case KeyRelease:
# Line 1062  xwin_process_events(void) Line 2058  xwin_process_events(void)
2058                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2059                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2060    
2061                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2062                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2063    
2064                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2065                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2066                                          break;                                          break;
2067    
2068                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2069                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2070                                  break;                                  break;
2071    
2072                          case ButtonPress:                          case ButtonPress:
2073                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2074                                  /* fall through */                                  break;
2075    
2076                          case ButtonRelease:                          case ButtonRelease:
2077                                  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);  
2078                                  break;                                  break;
2079    
2080                          case MotionNotify:                          case MotionNotify:
# Line 1155  xwin_process_events(void) Line 2089  xwin_process_events(void)
2089                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2090                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2091                                                         CurrentTime);                                                         CurrentTime);
2092                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2093                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2094                                    {
2095                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2096                                                           xevent.xmotion.x, xevent.xmotion.y);
2097                                    }
2098                                    else
2099                                    {
2100                                            /* SeamlessRDP */
2101                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2102                                                           xevent.xmotion.x_root,
2103                                                           xevent.xmotion.y_root);
2104                                    }
2105                                  break;                                  break;
2106    
2107                          case FocusIn:                          case FocusIn:
2108                                  if (xevent.xfocus.mode == NotifyGrab)                                  if (xevent.xfocus.mode == NotifyGrab)
2109                                          break;                                          break;
2110                                  g_focused = True;                                  g_focused = True;
2111                                  XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,                                  reset_modifier_keys();
                                               &dummy, &dummy, &state);  
                                 reset_modifier_keys(state);  
2112                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2113                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2114                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2115    
2116                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2117                                    if (!sw)
2118                                            break;
2119    
2120                                    if (sw->id != g_seamless_focused)
2121                                    {
2122                                            seamless_send_focus(sw->id, 0);
2123                                            g_seamless_focused = sw->id;
2124                                    }
2125                                  break;                                  break;
2126    
2127                          case FocusOut:                          case FocusOut:
# Line 1201  xwin_process_events(void) Line 2154  xwin_process_events(void)
2154                                  break;                                  break;
2155    
2156                          case Expose:                          case Expose:
2157                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2158                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2159                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2160                                            xevent.xexpose.height,                                                    g_gc,
2161                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2162                                                      xevent.xexpose.width, xevent.xexpose.height,
2163                                                      xevent.xexpose.x, xevent.xexpose.y);
2164                                    }
2165                                    else
2166                                    {
2167                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2168                                            if (!sw)
2169                                                    break;
2170                                            XCopyArea(g_display, g_backstore,
2171                                                      xevent.xexpose.window, g_gc,
2172                                                      xevent.xexpose.x + sw->xoffset,
2173                                                      xevent.xexpose.y + sw->yoffset,
2174                                                      xevent.xexpose.width,
2175                                                      xevent.xexpose.height, xevent.xexpose.x,
2176                                                      xevent.xexpose.y);
2177                                    }
2178    
2179                                  break;                                  break;
2180    
2181                          case MappingNotify:                          case MappingNotify:
# Line 1220  xwin_process_events(void) Line 2190  xwin_process_events(void)
2190                                          XFreeModifiermap(g_mod_map);                                          XFreeModifiermap(g_mod_map);
2191                                          g_mod_map = XGetModifierMapping(g_display);                                          g_mod_map = XGetModifierMapping(g_display);
2192                                  }                                  }
2193    
2194                                    if (xevent.xmapping.request == MappingPointer)
2195                                    {
2196                                            xwin_refresh_pointer_map();
2197                                    }
2198    
2199                                  break;                                  break;
2200    
2201                                  /* clipboard stuff */                                  /* clipboard stuff */
# Line 1234  xwin_process_events(void) Line 2210  xwin_process_events(void)
2210                                  break;                                  break;
2211                          case PropertyNotify:                          case PropertyNotify:
2212                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2213                                    if (xevent.xproperty.window == g_wnd)
2214                                            break;
2215                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2216                                            break;
2217    
2218                                    /* seamless */
2219                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2220                                    if (!sw)
2221                                            break;
2222    
2223                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2224                                        && (xevent.xproperty.state == PropertyNewValue))
2225                                    {
2226                                            sw->state = ewmh_get_window_state(sw->wnd);
2227                                            seamless_send_state(sw->id, sw->state, 0);
2228                                    }
2229    
2230                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2231                                        && (xevent.xproperty.state == PropertyNewValue))
2232                                    {
2233                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2234                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2235                                    }
2236    
2237                                    break;
2238                            case MapNotify:
2239                                    if (!g_seamless_active)
2240                                            rdp_send_client_window_status(1);
2241                                    break;
2242                            case UnmapNotify:
2243                                    if (!g_seamless_active)
2244                                            rdp_send_client_window_status(0);
2245                                    break;
2246                            case ConfigureNotify:
2247                                    if (!g_seamless_active)
2248                                            break;
2249    
2250                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2251                                    if (!sw)
2252                                            break;
2253    
2254                                    gettimeofday(sw->position_timer, NULL);
2255                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2256                                        1000000)
2257                                    {
2258                                            sw->position_timer->tv_usec +=
2259                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2260                                            sw->position_timer->tv_sec += 1;
2261                                    }
2262                                    else
2263                                    {
2264                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2265                                    }
2266    
2267                                    sw_handle_restack(sw);
2268                                  break;                                  break;
2269                  }                  }
2270          }          }
# Line 1245  xwin_process_events(void) Line 2276  xwin_process_events(void)
2276  int  int
2277  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2278  {  {
2279          int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;          int n;
2280          fd_set rfds, wfds;          fd_set rfds, wfds;
2281            struct timeval tv;
2282            RD_BOOL s_timeout = False;
2283    
2284          while (True)          while (True)
2285          {          {
2286                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2287                  /* Process any events already waiting */                  /* Process any events already waiting */
2288                  if (!xwin_process_events())                  if (!xwin_process_events())
2289                          /* User quit */                          /* User quit */
2290                          return 0;                          return 0;
2291    
2292                    if (g_seamless_active)
2293                            sw_check_timers();
2294    
2295                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2296                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2297                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2298                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2299    
2300                    /* default timeout */
2301                    tv.tv_sec = 60;
2302                    tv.tv_usec = 0;
2303    
2304  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
2305                  /* FIXME: there should be an API for registering fds */                  rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;  
                 }  
2306  #endif  #endif
2307    
2308                  switch (select(n, &rfds, &wfds, NULL, NULL))                  /* add redirection handles */
2309                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2310                    seamless_select_timeout(&tv);
2311    
2312                    n++;
2313    
2314                    switch (select(n, &rfds, &wfds, NULL, &tv))
2315                  {                  {
2316                          case -1:                          case -1:
2317                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2318    
2319                          case 0:                          case 0:
2320    #ifdef WITH_RDPSND
2321                                    rdpsnd_check_fds(&rfds, &wfds);
2322    #endif
2323    
2324                                    /* Abort serial read calls */
2325                                    if (s_timeout)
2326                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2327                                  continue;                                  continue;
2328                  }                  }
2329    
2330    #ifdef WITH_RDPSND
2331                    rdpsnd_check_fds(&rfds, &wfds);
2332    #endif
2333    
2334                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2335    
2336                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2337                          return 1;                          return 1;
2338    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2339          }          }
2340  }  }
2341    
# Line 1294  ui_move_pointer(int x, int y) Line 2345  ui_move_pointer(int x, int y)
2345          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2346  }  }
2347    
2348  HBITMAP  RD_HBITMAP
2349  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2350  {  {
2351          XImage *image;          XImage *image;
# Line 1302  ui_create_bitmap(int width, int height, Line 2353  ui_create_bitmap(int width, int height,
2353          uint8 *tdata;          uint8 *tdata;
2354          int bitmap_pad;          int bitmap_pad;
2355    
2356          if (g_server_bpp == 8)          if (g_server_depth == 8)
2357          {          {
2358                  bitmap_pad = 8;                  bitmap_pad = 8;
2359          }          }
# Line 1319  ui_create_bitmap(int width, int height, Line 2370  ui_create_bitmap(int width, int height,
2370          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2371                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2372    
2373          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);
2374    
2375          XFree(image);          XFree(image);
2376          if (!g_owncolmap)          if (tdata != data)
2377                  xfree(tdata);                  xfree(tdata);
2378          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2379  }  }
2380    
2381  void  void
# Line 1334  ui_paint_bitmap(int x, int y, int cx, in Line 2385  ui_paint_bitmap(int x, int y, int cx, in
2385          uint8 *tdata;          uint8 *tdata;
2386          int bitmap_pad;          int bitmap_pad;
2387    
2388          if (g_server_bpp == 8)          if (g_server_depth == 8)
2389          {          {
2390                  bitmap_pad = 8;                  bitmap_pad = 8;
2391          }          }
# Line 1354  ui_paint_bitmap(int x, int y, int cx, in Line 2405  ui_paint_bitmap(int x, int y, int cx, in
2405          {          {
2406                  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);
2407                  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);
2408                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2409                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2410                                             x - sw->xoffset, y - sw->yoffset));
2411          }          }
2412          else          else
2413          {          {
2414                  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);
2415                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2416                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2417                                             x - sw->xoffset, y - sw->yoffset));
2418          }          }
2419    
2420          XFree(image);          XFree(image);
2421          if (!g_owncolmap)          if (tdata != data)
2422                  xfree(tdata);                  xfree(tdata);
2423  }  }
2424    
2425  void  void
2426  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2427  {  {
2428          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2429  }  }
2430    
2431  HGLYPH  RD_HGLYPH
2432  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2433  {  {
2434          XImage *image;          XImage *image;
2435          Pixmap bitmap;          Pixmap bitmap;
2436          int scanline;          int scanline;
         GC gc;  
2437    
2438          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2439    
2440          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2441          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2442                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2443    
2444          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2445                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1390  ui_create_glyph(int width, int height, u Line 2447  ui_create_glyph(int width, int height, u
2447          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2448          XInitImage(image);          XInitImage(image);
2449    
2450          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);
2451    
2452          XFree(image);          XFree(image);
2453          XFreeGC(g_display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH) bitmap;  
2454  }  }
2455    
2456  void  void
2457  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2458  {  {
2459          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2460  }  }
2461    
2462  HCURSOR  RD_HCURSOR
2463  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2464                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2465  {  {
2466          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2467          XColor bg, fg;          XColor bg, fg;
2468          Cursor xcursor;          Cursor xcursor;
2469          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1471  ui_create_cursor(unsigned int x, unsigne Line 2527  ui_create_cursor(unsigned int x, unsigne
2527          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2528          xfree(mask);          xfree(mask);
2529          xfree(cursor);          xfree(cursor);
2530          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2531  }  }
2532    
2533  void  void
2534  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2535  {  {
2536          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2537          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2538            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2539  }  }
2540    
2541  void  void
2542  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2543  {  {
2544          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2545  }  }
# Line 1500  ui_set_null_cursor(void) Line 2557  ui_set_null_cursor(void)
2557                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2558    
2559    
2560  HCOLOURMAP  RD_HCOLOURMAP
2561  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2562  {  {
2563          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1596  ui_create_colourmap(COLOURMAP * colours) Line 2653  ui_create_colourmap(COLOURMAP * colours)
2653                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2654    
2655                  xfree(xcolours);                  xfree(xcolours);
2656                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2657          }          }
2658  }  }
2659    
2660  void  void
2661  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2662  {  {
2663          if (!g_owncolmap)          if (!g_owncolmap)
2664                  xfree(map);                  xfree(map);
# Line 1610  ui_destroy_colourmap(HCOLOURMAP map) Line 2667  ui_destroy_colourmap(HCOLOURMAP map)
2667  }  }
2668    
2669  void  void
2670  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2671  {  {
2672          if (!g_owncolmap)          if (!g_owncolmap)
2673          {          {
# Line 1620  ui_set_colourmap(HCOLOURMAP map) Line 2677  ui_set_colourmap(HCOLOURMAP map)
2677                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2678          }          }
2679          else          else
2680            {
2681                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2682                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2683            }
2684  }  }
2685    
2686  void  void
2687  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2688  {  {
2689          XRectangle rect;          g_clip_rectangle.x = x;
2690            g_clip_rectangle.y = y;
2691          rect.x = x;          g_clip_rectangle.width = cx;
2692          rect.y = y;          g_clip_rectangle.height = cy;
2693          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);  
2694  }  }
2695    
2696  void  void
2697  ui_reset_clip(void)  ui_reset_clip(void)
2698  {  {
2699          XRectangle rect;          g_clip_rectangle.x = 0;
2700            g_clip_rectangle.y = 0;
2701          rect.x = 0;          g_clip_rectangle.width = g_width;
2702          rect.y = 0;          g_clip_rectangle.height = g_height;
2703          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);  
2704  }  }
2705    
2706  void  void
# Line 1685  ui_patblt(uint8 opcode, Line 2741  ui_patblt(uint8 opcode,
2741          {          {
2742                  case 0: /* Solid */                  case 0: /* Solid */
2743                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2744                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2745                          break;                          break;
2746    
2747                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1696  ui_patblt(uint8 opcode, Line 2752  ui_patblt(uint8 opcode,
2752                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2753                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2754                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2755                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2756                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2757                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2758                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2759                          break;                          break;
2760    
2761                  case 3: /* Pattern */                  case 3: /* Pattern */
2762                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2763                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2764                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2765                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2766                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2767                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2768                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2769                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2770                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
2771                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2772                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2773                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2774                          break;                          break;
2775    
2776                  default:                  default:
# Line 1725  ui_patblt(uint8 opcode, Line 2778  ui_patblt(uint8 opcode,
2778          }          }
2779    
2780          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2781    
2782            if (g_ownbackstore)
2783                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2784            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2785                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2786                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2787  }  }
2788    
2789  void  void
# Line 1733  ui_screenblt(uint8 opcode, Line 2792  ui_screenblt(uint8 opcode,
2792               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2793  {  {
2794          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
         XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
2795          if (g_ownbackstore)          if (g_ownbackstore)
2796            {
2797                    XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2798                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2799                  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);
2800            }
2801            else
2802            {
2803                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2804            }
2805    
2806            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2807                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2808                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2809    
2810          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2811  }  }
2812    
2813  void  void
2814  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
2815            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2816            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
2817  {  {
2818          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2819          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);
2820            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2821                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2822                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2823          if (g_ownbackstore)          if (g_ownbackstore)
2824                  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);
2825          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1754  ui_memblt(uint8 opcode, Line 2828  ui_memblt(uint8 opcode,
2828  void  void
2829  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2830            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2831            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
2832            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2833  {  {
2834          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 1792  ui_line(uint8 opcode, Line 2866  ui_line(uint8 opcode,
2866          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2867          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2868          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2869            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2870                                                startx - sw->xoffset, starty - sw->yoffset,
2871                                                endx - sw->xoffset, endy - sw->yoffset));
2872          if (g_ownbackstore)          if (g_ownbackstore)
2873                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2874          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1806  ui_rect( Line 2883  ui_rect(
2883          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2884  }  }
2885    
2886    void
2887    ui_polygon(uint8 opcode,
2888               /* mode */ uint8 fillmode,
2889               /* dest */ RD_POINT * point, int npoints,
2890               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2891    {
2892            uint8 style, i, ipattern[8];
2893            Pixmap fill;
2894    
2895            SET_FUNCTION(opcode);
2896    
2897            switch (fillmode)
2898            {
2899                    case ALTERNATE:
2900                            XSetFillRule(g_display, g_gc, EvenOddRule);
2901                            break;
2902                    case WINDING:
2903                            XSetFillRule(g_display, g_gc, WindingRule);
2904                            break;
2905                    default:
2906                            unimpl("fill mode %d\n", fillmode);
2907            }
2908    
2909            if (brush)
2910                    style = brush->style;
2911            else
2912                    style = 0;
2913    
2914            switch (style)
2915            {
2916                    case 0: /* Solid */
2917                            SET_FOREGROUND(fgcolour);
2918                            FILL_POLYGON((XPoint *) point, npoints);
2919                            break;
2920    
2921                    case 2: /* Hatch */
2922                            fill = (Pixmap) ui_create_glyph(8, 8,
2923                                                            hatch_patterns + brush->pattern[0] * 8);
2924                            SET_FOREGROUND(fgcolour);
2925                            SET_BACKGROUND(bgcolour);
2926                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2927                            XSetStipple(g_display, g_gc, fill);
2928                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2929                            FILL_POLYGON((XPoint *) point, npoints);
2930                            XSetFillStyle(g_display, g_gc, FillSolid);
2931                            XSetTSOrigin(g_display, g_gc, 0, 0);
2932                            ui_destroy_glyph((RD_HGLYPH) fill);
2933                            break;
2934    
2935                    case 3: /* Pattern */
2936                            for (i = 0; i != 8; i++)
2937                                    ipattern[7 - i] = brush->pattern[i];
2938                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2939                            SET_FOREGROUND(bgcolour);
2940                            SET_BACKGROUND(fgcolour);
2941                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2942                            XSetStipple(g_display, g_gc, fill);
2943                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2944                            FILL_POLYGON((XPoint *) point, npoints);
2945                            XSetFillStyle(g_display, g_gc, FillSolid);
2946                            XSetTSOrigin(g_display, g_gc, 0, 0);
2947                            ui_destroy_glyph((RD_HGLYPH) fill);
2948                            break;
2949    
2950                    default:
2951                            unimpl("brush %d\n", brush->style);
2952            }
2953    
2954            RESET_FUNCTION(opcode);
2955    }
2956    
2957    void
2958    ui_polyline(uint8 opcode,
2959                /* dest */ RD_POINT * points, int npoints,
2960                /* pen */ PEN * pen)
2961    {
2962            /* TODO: set join style */
2963            SET_FUNCTION(opcode);
2964            SET_FOREGROUND(pen->colour);
2965            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2966            if (g_ownbackstore)
2967                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2968                               CoordModePrevious);
2969    
2970            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2971                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2972    
2973            RESET_FUNCTION(opcode);
2974    }
2975    
2976    void
2977    ui_ellipse(uint8 opcode,
2978               /* mode */ uint8 fillmode,
2979               /* dest */ int x, int y, int cx, int cy,
2980               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2981    {
2982            uint8 style, i, ipattern[8];
2983            Pixmap fill;
2984    
2985            SET_FUNCTION(opcode);
2986    
2987            if (brush)
2988                    style = brush->style;
2989            else
2990                    style = 0;
2991    
2992            switch (style)
2993            {
2994                    case 0: /* Solid */
2995                            SET_FOREGROUND(fgcolour);
2996                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2997                            break;
2998    
2999                    case 2: /* Hatch */
3000                            fill = (Pixmap) ui_create_glyph(8, 8,
3001                                                            hatch_patterns + brush->pattern[0] * 8);
3002                            SET_FOREGROUND(fgcolour);
3003                            SET_BACKGROUND(bgcolour);
3004                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3005                            XSetStipple(g_display, g_gc, fill);
3006                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3007                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3008                            XSetFillStyle(g_display, g_gc, FillSolid);
3009                            XSetTSOrigin(g_display, g_gc, 0, 0);
3010                            ui_destroy_glyph((RD_HGLYPH) fill);
3011                            break;
3012    
3013                    case 3: /* Pattern */
3014                            for (i = 0; i != 8; i++)
3015                                    ipattern[7 - i] = brush->pattern[i];
3016                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3017                            SET_FOREGROUND(bgcolour);
3018                            SET_BACKGROUND(fgcolour);
3019                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3020                            XSetStipple(g_display, g_gc, fill);
3021                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3022                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3023                            XSetFillStyle(g_display, g_gc, FillSolid);
3024                            XSetTSOrigin(g_display, g_gc, 0, 0);
3025                            ui_destroy_glyph((RD_HGLYPH) fill);
3026                            break;
3027    
3028                    default:
3029                            unimpl("brush %d\n", brush->style);
3030            }
3031    
3032            RESET_FUNCTION(opcode);
3033    }
3034    
3035  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3036  void  void
3037  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3038                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3039                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3040                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3041  {  {
3042          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 1830  ui_draw_glyph(int mixmode, Line 3056  ui_draw_glyph(int mixmode,
3056  {\  {\
3057    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3058    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3059      {\
3060        xyoffset = ttext[++idx];\
3061        if ((xyoffset & 0x80))\
3062      {\      {\
3063        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3064        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[idx+1] | (ttext[idx+2] << 8);\  
           else\  
             x += ttext[idx+1] | (ttext[idx+2] << 8);\  
           idx += 2;\  
         }\  
3065        else\        else\
3066          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3067            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3068      }\      }\
3069    if (glyph != NULL)\      else\
3070      {\      {\
3071        ui_draw_glyph (mixmode, x + glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3072                       y + glyph->baseline,\          y += xyoffset;\
3073                       glyph->width, glyph->height,\        else\
3074                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3075      }\      }\
3076      }\
3077      if (glyph != NULL)\
3078      {\
3079        x1 = x + glyph->offset;\
3080        y1 = y + glyph->baseline;\
3081        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3082        XSetTSOrigin(g_display, g_gc, x1, y1);\
3083        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3084        if (flags & TEXT2_IMPLICIT_X)\
3085          x += glyph->width;\
3086      }\
3087  }  }
3088    
3089  void  void
3090  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,
3091               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3092               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3093               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3094  {  {
3095            /* TODO: use brush appropriately */
3096    
3097          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3098          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3099          DATABLOB *entry;          DATABLOB *entry;
3100    
3101          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3102    
3103            /* Sometimes, the boxcx value is something really large, like
3104               32691. This makes XCopyArea fail with Xvnc. The code below
3105               is a quick fix. */
3106            if (boxx + boxcx > g_width)
3107                    boxcx = g_width - boxx;
3108    
3109          if (boxcx > 1)          if (boxcx > 1)
3110          {          {
3111                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
# Line 1880  ui_draw_text(uint8 font, uint8 flags, in Line 3115  ui_draw_text(uint8 font, uint8 flags, in
3115                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3116          }          }
3117    
3118            SET_FOREGROUND(fgcolour);
3119            SET_BACKGROUND(bgcolour);
3120            XSetFillStyle(g_display, g_gc, FillStippled);
3121    
3122          /* Paint text, character by character */          /* Paint text, character by character */
3123          for (i = 0; i < length;)          for (i = 0; i < length;)
3124          {          {
3125                  switch (text[i])                  switch (text[i])
3126                  {                  {
3127                          case 0xff:                          case 0xff:
3128                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3129                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3130                                  {                                  {
3131                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3132                                          exit(1);                                          for (j = 0; j < length; j++)
3133                                                    fprintf(stderr, "%02x ", text[j]);
3134                                            fprintf(stderr, "\n");
3135                                            i = length = 0;
3136                                            break;
3137                                  }                                  }
3138                                    cache_put_text(text[i + 1], text, text[i + 2]);
3139                                    i += 3;
3140                                    length -= i;
3141                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3142                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3143                                  i = 0;                                  i = 0;
3144                                  break;                                  break;
3145    
3146                          case 0xfe:                          case 0xfe:
3147                                    /* At least one byte needs to follow */
3148                                    if (i + 2 > length)
3149                                    {
3150                                            warning("Skipping short 0xfe command:");
3151                                            for (j = 0; j < length; j++)
3152                                                    fprintf(stderr, "%02x ", text[j]);
3153                                            fprintf(stderr, "\n");
3154                                            i = length = 0;
3155                                            break;
3156                                    }
3157                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3158                                  if (entry != NULL)                                  if (entry->data != NULL)
3159                                  {                                  {
3160                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3161                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3162                                          {                                          {
3163                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3164                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 1930  ui_draw_text(uint8 font, uint8 flags, in Line 3184  ui_draw_text(uint8 font, uint8 flags, in
3184                                  break;                                  break;
3185                  }                  }
3186          }          }
3187    
3188            XSetFillStyle(g_display, g_gc, FillSolid);
3189    
3190          if (g_ownbackstore)          if (g_ownbackstore)
3191          {          {
3192                  if (boxcx > 1)                  if (boxcx > 1)
3193                    {
3194                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3195                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3196                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3197                                                    (g_display, g_backstore, sw->wnd, g_gc,
3198                                                     boxx, boxy,
3199                                                     boxcx, boxcy,
3200                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3201                    }
3202                  else                  else
3203                    {
3204                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3205                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3206                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3207                                                    (g_display, g_backstore, sw->wnd, g_gc,
3208                                                     clipx, clipy,
3209                                                     clipcx, clipcy, clipx - sw->xoffset,
3210                                                     clipy - sw->yoffset));
3211                    }
3212          }          }
3213  }  }
3214    
# Line 1950  ui_desktop_save(uint32 offset, int x, in Line 3221  ui_desktop_save(uint32 offset, int x, in
3221          if (g_ownbackstore)          if (g_ownbackstore)
3222          {          {
3223                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3224                    exit_if_null(image);
3225          }          }
3226          else          else
3227          {          {
3228                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3229                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3230                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3231                    exit_if_null(image);
3232                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3233          }          }
3234    
# Line 1977  ui_desktop_restore(uint32 offset, int x, Line 3250  ui_desktop_restore(uint32 offset, int x,
3250                  return;                  return;
3251    
3252          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3253                               (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);                               (char *) data, cx, cy, g_bpp, 0);
3254    
3255          if (g_ownbackstore)          if (g_ownbackstore)
3256          {          {
3257                  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);
3258                  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);
3259                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3260                                            (g_display, g_backstore, sw->wnd, g_gc,
3261                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3262          }          }
3263          else          else
3264          {          {
3265                  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);
3266                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3267                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3268                                             x - sw->xoffset, y - sw->yoffset));
3269          }          }
3270    
3271          XFree(image);          XFree(image);
3272  }  }
3273    
3274    /* these do nothing here but are used in uiports */
3275    void
3276    ui_begin_update(void)
3277    {
3278    }
3279    
3280    void
3281    ui_end_update(void)
3282    {
3283    }
3284    
3285    
3286    void
3287    ui_seamless_begin(RD_BOOL hidden)
3288    {
3289            if (!g_seamless_rdp)
3290                    return;
3291    
3292            if (g_seamless_started)
3293                    return;
3294    
3295            g_seamless_started = True;
3296            g_seamless_hidden = hidden;
3297    
3298            if (!hidden)
3299                    ui_seamless_toggle();
3300    }
3301    
3302    
3303    void
3304    ui_seamless_hide_desktop()
3305    {
3306            if (!g_seamless_rdp)
3307                    return;
3308    
3309            if (!g_seamless_started)
3310                    return;
3311    
3312            if (g_seamless_active)
3313                    ui_seamless_toggle();
3314    
3315            g_seamless_hidden = True;
3316    }
3317    
3318    
3319    void
3320    ui_seamless_unhide_desktop()
3321    {
3322            if (!g_seamless_rdp)
3323                    return;
3324    
3325            if (!g_seamless_started)
3326                    return;
3327    
3328            g_seamless_hidden = False;
3329    
3330            ui_seamless_toggle();
3331    }
3332    
3333    
3334    void
3335    ui_seamless_toggle()
3336    {
3337            if (!g_seamless_rdp)
3338                    return;
3339    
3340            if (!g_seamless_started)
3341                    return;
3342    
3343            if (g_seamless_hidden)
3344                    return;
3345    
3346            if (g_seamless_active)
3347            {
3348                    /* Deactivate */
3349                    while (g_seamless_windows)
3350                    {
3351                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3352                            sw_remove_window(g_seamless_windows);
3353                    }
3354                    XMapWindow(g_display, g_wnd);
3355            }
3356            else
3357            {
3358                    /* Activate */
3359                    XUnmapWindow(g_display, g_wnd);
3360                    seamless_send_sync();
3361            }
3362    
3363            g_seamless_active = !g_seamless_active;
3364    }
3365    
3366    
3367    void
3368    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3369                              unsigned long flags)
3370    {
3371            Window wnd;
3372            XSetWindowAttributes attribs;
3373            XClassHint *classhints;
3374            XSizeHints *sizehints;
3375            XWMHints *wmhints;
3376            long input_mask;
3377            seamless_window *sw, *sw_parent;
3378    
3379            if (!g_seamless_active)
3380                    return;
3381    
3382            /* Ignore CREATEs for existing windows */
3383            sw = sw_get_window_by_id(id);
3384            if (sw)
3385                    return;
3386    
3387            get_window_attribs(&attribs);
3388            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3389                                InputOutput, g_visual,
3390                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3391    
3392            XStoreName(g_display, wnd, "SeamlessRDP");
3393            ewmh_set_wm_name(wnd, "SeamlessRDP");
3394    
3395            mwm_hide_decorations(wnd);
3396    
3397            classhints = XAllocClassHint();
3398            if (classhints != NULL)
3399            {
3400                    classhints->res_name = "rdesktop";
3401                    classhints->res_class = "SeamlessRDP";
3402                    XSetClassHint(g_display, wnd, classhints);
3403                    XFree(classhints);
3404            }
3405    
3406            /* WM_NORMAL_HINTS */
3407            sizehints = XAllocSizeHints();
3408            if (sizehints != NULL)
3409            {
3410                    sizehints->flags = USPosition;
3411                    XSetWMNormalHints(g_display, wnd, sizehints);
3412                    XFree(sizehints);
3413            }
3414    
3415            /* Parent-less transient windows */
3416            if (parent == 0xFFFFFFFF)
3417            {
3418                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3419                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3420                       using some other hints. */
3421                    ewmh_set_window_popup(wnd);
3422            }
3423            /* Normal transient windows */
3424            else if (parent != 0x00000000)
3425            {
3426                    sw_parent = sw_get_window_by_id(parent);
3427                    if (sw_parent)
3428                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3429                    else
3430                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3431            }
3432    
3433            if (flags & SEAMLESSRDP_CREATE_MODAL)
3434            {
3435                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3436                       somewhat at least */
3437                    if (parent == 0x00000000)
3438                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3439                    ewmh_set_window_modal(wnd);
3440            }
3441    
3442            /* FIXME: Support for Input Context:s */
3443    
3444            get_input_mask(&input_mask);
3445            input_mask |= PropertyChangeMask;
3446    
3447            XSelectInput(g_display, wnd, input_mask);
3448    
3449            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3450               seamless window, we could try to close the window on the
3451               serverside, instead of terminating rdesktop */
3452            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3453    
3454            sw = xmalloc(sizeof(seamless_window));
3455            sw->wnd = wnd;
3456            sw->id = id;
3457            sw->behind = 0;
3458            sw->group = sw_find_group(group, False);
3459            sw->group->refcnt++;
3460            sw->xoffset = 0;
3461            sw->yoffset = 0;
3462            sw->width = 0;
3463            sw->height = 0;
3464            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3465            sw->desktop = 0;
3466            sw->position_timer = xmalloc(sizeof(struct timeval));
3467            timerclear(sw->position_timer);
3468    
3469            sw->outstanding_position = False;
3470            sw->outpos_serial = 0;
3471            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3472            sw->outpos_width = sw->outpos_height = 0;
3473    
3474            sw->next = g_seamless_windows;
3475            g_seamless_windows = sw;
3476    
3477            /* WM_HINTS */
3478            wmhints = XAllocWMHints();
3479            if (wmhints)
3480            {
3481                    wmhints->flags = WindowGroupHint;
3482                    wmhints->window_group = sw->group->wnd;
3483                    XSetWMHints(g_display, sw->wnd, wmhints);
3484                    XFree(wmhints);
3485            }
3486    }
3487    
3488    
3489    void
3490    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3491    {
3492            seamless_window *sw;
3493    
3494            if (!g_seamless_active)
3495                    return;
3496    
3497            sw = sw_get_window_by_id(id);
3498            if (!sw)
3499            {
3500                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3501                    return;
3502            }
3503    
3504            XDestroyWindow(g_display, sw->wnd);
3505            sw_remove_window(sw);
3506    }
3507    
3508    
3509    void
3510    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3511    {
3512            seamless_window *sw, *sw_next;
3513    
3514            if (!g_seamless_active)
3515                    return;
3516    
3517            for (sw = g_seamless_windows; sw; sw = sw_next)
3518            {
3519                    sw_next = sw->next;
3520    
3521                    if (sw->group->id == id)
3522                    {
3523                            XDestroyWindow(g_display, sw->wnd);
3524                            sw_remove_window(sw);
3525                    }
3526            }
3527    }
3528    
3529    
3530    void
3531    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3532    {
3533            seamless_window *sw;
3534    
3535            if (!g_seamless_active)
3536                    return;
3537    
3538            sw = sw_get_window_by_id(id);
3539            if (!sw)
3540            {
3541                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3542                    return;
3543            }
3544    
3545            /* We ignore server updates until it has handled our request. */
3546            if (sw->outstanding_position)
3547                    return;
3548    
3549            if (!width || !height)
3550                    /* X11 windows must be at least 1x1 */
3551                    return;
3552    
3553            sw->xoffset = x;
3554            sw->yoffset = y;
3555            sw->width = width;
3556            sw->height = height;
3557    
3558            /* If we move the window in a maximized state, then KDE won't
3559               accept restoration */
3560            switch (sw->state)
3561            {
3562                    case SEAMLESSRDP_MINIMIZED:
3563                    case SEAMLESSRDP_MAXIMIZED:
3564                            return;
3565            }
3566    
3567            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3568            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3569    }
3570    
3571    
3572    void
3573    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3574    {
3575            seamless_window *sw;
3576    
3577            if (!g_seamless_active)
3578                    return;
3579    
3580            sw = sw_get_window_by_id(id);
3581            if (!sw)
3582            {
3583                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3584                    return;
3585            }
3586    
3587            if (behind)
3588            {
3589                    seamless_window *sw_behind;
3590                    Window wnds[2];
3591    
3592                    sw_behind = sw_get_window_by_id(behind);
3593                    if (!sw_behind)
3594                    {
3595                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3596                                    behind);
3597                            return;
3598                    }
3599    
3600                    wnds[1] = sw_behind->wnd;
3601                    wnds[0] = sw->wnd;
3602    
3603                    XRestackWindows(g_display, wnds, 2);
3604            }
3605            else
3606            {
3607                    XRaiseWindow(g_display, sw->wnd);
3608            }
3609    
3610            sw_restack_window(sw, behind);
3611    }
3612    
3613    
3614    void
3615    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3616    {
3617            seamless_window *sw;
3618    
3619            if (!g_seamless_active)
3620                    return;
3621    
3622            sw = sw_get_window_by_id(id);
3623            if (!sw)
3624            {
3625                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3626                    return;
3627            }
3628    
3629            /* FIXME: Might want to convert the name for non-EWMH WMs */
3630            XStoreName(g_display, sw->wnd, title);
3631            ewmh_set_wm_name(sw->wnd, title);
3632    }
3633    
3634    
3635    void
3636    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3637    {
3638            seamless_window *sw;
3639    
3640            if (!g_seamless_active)
3641                    return;
3642    
3643            sw = sw_get_window_by_id(id);
3644            if (!sw)
3645            {
3646                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3647                    return;
3648            }
3649    
3650            switch (state)
3651            {
3652                    case SEAMLESSRDP_NORMAL:
3653                    case SEAMLESSRDP_MAXIMIZED:
3654                            ewmh_change_state(sw->wnd, state);
3655                            XMapWindow(g_display, sw->wnd);
3656                            break;
3657                    case SEAMLESSRDP_MINIMIZED:
3658                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3659                               the Window Manager should probably just ignore the request, since
3660                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3661                               such as minimization, rather than an independent state." Besides,
3662                               XIconifyWindow is easier. */
3663                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3664                            {
3665                                    XWMHints *hints;
3666                                    hints = XGetWMHints(g_display, sw->wnd);
3667                                    if (hints)
3668                                    {
3669                                            hints->flags |= StateHint;
3670                                            hints->initial_state = IconicState;
3671                                            XSetWMHints(g_display, sw->wnd, hints);
3672                                            XFree(hints);
3673                                    }
3674                                    XMapWindow(g_display, sw->wnd);
3675                            }
3676                            else
3677                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3678                            break;
3679                    default:
3680                            warning("SeamlessRDP: Invalid state %d\n", state);
3681                            break;
3682            }
3683    
3684            sw->state = state;
3685    }
3686    
3687    
3688    void
3689    ui_seamless_syncbegin(unsigned long flags)
3690    {
3691            if (!g_seamless_active)
3692                    return;
3693    
3694            /* Destroy all seamless windows */
3695            while (g_seamless_windows)
3696            {
3697                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3698                    sw_remove_window(g_seamless_windows);
3699            }
3700    }
3701    
3702    
3703    void
3704    ui_seamless_ack(unsigned int serial)
3705    {
3706            seamless_window *sw;
3707            for (sw = g_seamless_windows; sw; sw = sw->next)
3708            {
3709                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3710                    {
3711                            sw->xoffset = sw->outpos_xoffset;
3712                            sw->yoffset = sw->outpos_yoffset;
3713                            sw->width = sw->outpos_width;
3714                            sw->height = sw->outpos_height;
3715                            sw->outstanding_position = False;
3716    
3717                            /* Do a complete redraw of the window as part of the
3718                               completion of the move. This is to remove any
3719                               artifacts caused by our lack of synchronization. */
3720                            XCopyArea(g_display, g_backstore,
3721                                      sw->wnd, g_gc,
3722                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3723    
3724                            break;
3725                    }
3726            }
3727    }

Legend:
Removed from v.542  
changed lines
  Added in v.1407

  ViewVC Help
Powered by ViewVC 1.1.26