/[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 844 by jdmeijer, Thu Mar 10 22:48:15 2005 UTC revision 1380 by astrand, Wed Jan 17 07:39:31 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-2005     Copyright (C) Matthew Chapman 1999-2007
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <X11/Xproto.h>
24  #include <unistd.h>  #include <unistd.h>
25  #include <sys/time.h>  #include <sys/time.h>
26  #include <time.h>  #include <time.h>
# Line 32  extern int g_width; Line 33  extern int g_width;
33  extern int g_height;  extern int g_height;
34  extern int g_xpos;  extern int g_xpos;
35  extern int g_ypos;  extern int g_ypos;
36  extern BOOL g_sendmotion;  extern int g_pos;
37  extern BOOL g_fullscreen;  extern RD_BOOL g_sendmotion;
38  extern BOOL g_grab_keyboard;  extern RD_BOOL g_fullscreen;
39  extern BOOL g_hide_decorations;  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 45  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    
53    /* 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;  extern uint32 g_embed_wnd;
87  BOOL g_enable_compose = False;  RD_BOOL g_enable_compose = False;
88  BOOL g_Unobscured;              /* used for screenblt */  RD_BOOL g_Unobscured;           /* used for screenblt */
89  static GC g_gc = NULL;  static GC g_gc = NULL;
90  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
91  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
92    static XRectangle g_clip_rectangle;
93  static Visual *g_visual;  static Visual *g_visual;
94    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
95       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
96       as far as we're concerned. */
97  static int g_depth;  static int g_depth;
98    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
99       This may be larger than g_depth, in which case some of the bits would
100       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
101  static int g_bpp;  static int g_bpp;
102  static XIM g_IM;  static XIM g_IM;
103  static XIC g_IC;  static XIC g_IC;
104  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
105  static Cursor g_current_cursor;  static Cursor g_current_cursor;
106  static HCURSOR g_null_cursor = NULL;  static RD_HCURSOR g_null_cursor = NULL;
107  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
108  static BOOL g_focused;  extern Atom g_net_wm_state_atom;
109  static BOOL g_mouse_in_wnd;  extern Atom g_net_wm_desktop_atom;
110  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  static RD_BOOL g_focused;
111    static RD_BOOL g_mouse_in_wnd;
112    /* Indicates that:
113       1) visual has 15, 16 or 24 depth and the same color channel masks
114          as its RDP equivalent (implies X server is LE),
115       2) host is LE
116       This will trigger an optimization whose real value is questionable.
117    */
118    static RD_BOOL g_compatible_arch;
119    /* Indicates whether RDP's bitmaps and our XImages have the same
120       binary format. If so, we can avoid an expensive translation.
121       Note that this can be true when g_compatible_arch is false,
122       e.g.:
123      
124         RDP(LE) <-> host(BE) <-> X-Server(LE)
125        
126       ('host' is the machine running rdesktop; the host simply memcpy's
127        so its endianess doesn't matter)
128     */
129    static RD_BOOL g_no_translate_image = False;
130    
131  /* endianness */  /* endianness */
132  static BOOL g_host_be;  static RD_BOOL g_host_be;
133  static BOOL g_xserver_be;  static RD_BOOL g_xserver_be;
134  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;  static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
135  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
136    
137  /* software backing store */  /* software backing store */
138  extern BOOL g_ownbackstore;  extern RD_BOOL g_ownbackstore;
139  static Pixmap g_backstore = 0;  static Pixmap g_backstore = 0;
140    
141  /* Moving in single app mode */  /* Moving in single app mode */
142  static BOOL g_moving_wnd;  static RD_BOOL g_moving_wnd;
143  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
144  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
145    static RD_BOOL g_using_full_workarea = False;
146    
147  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
148  extern int g_dsp_fd;  extern RD_BOOL g_rdpsnd;
 extern BOOL g_dsp_busy;  
 extern BOOL g_rdpsnd;  
149  #endif  #endif
150    
151  /* MWM decorations */  /* MWM decorations */
# Line 90  extern BOOL g_rdpsnd; Line 153  extern BOOL g_rdpsnd;
153  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
154  typedef struct  typedef struct
155  {  {
156          uint32 flags;          unsigned long flags;
157          uint32 functions;          unsigned long functions;
158          uint32 decorations;          unsigned long decorations;
159          sint32 inputMode;          long inputMode;
160          uint32 status;          unsigned long status;
161  }  }
162  PropMotifWmHints;  PropMotifWmHints;
163    
# Line 106  typedef struct Line 169  typedef struct
169  }  }
170  PixelColour;  PixelColour;
171    
172    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
173            do { \
174                    seamless_window *sw; \
175                    XRectangle rect; \
176                    if (!g_seamless_windows) break; \
177                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
178                        rect.x = g_clip_rectangle.x - sw->xoffset; \
179                        rect.y = g_clip_rectangle.y - sw->yoffset; \
180                        rect.width = g_clip_rectangle.width; \
181                        rect.height = g_clip_rectangle.height; \
182                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
183                        func args; \
184                    } \
185                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
186            } while (0)
187    
188    static void
189    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
190    {
191            points[0].x -= xoffset;
192            points[0].y -= yoffset;
193            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
194            points[0].x += xoffset;
195            points[0].y += yoffset;
196    }
197    
198    static void
199    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
200    {
201            points[0].x -= xoffset;
202            points[0].y -= yoffset;
203            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
204            points[0].x += xoffset;
205            points[0].y += yoffset;
206    }
207    
208  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
209  { \  { \
210          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
211            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
212          if (g_ownbackstore) \          if (g_ownbackstore) \
213                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
214  }  }
# Line 124  PixelColour; Line 223  PixelColour;
223          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
224          if (g_ownbackstore) \          if (g_ownbackstore) \
225                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
226            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
227  }  }
228    
229  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 132  PixelColour; Line 232  PixelColour;
232          { \          { \
233                  case 0: /* Outline */ \                  case 0: /* Outline */ \
234                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
235                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
236                          if (g_ownbackstore) \                          if (g_ownbackstore) \
237                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
238                          break; \                          break; \
239                  case 1: /* Filled */ \                  case 1: /* Filled */ \
240                          XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \                          XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
241                                   cx, cy, 0, 360*64); \                          ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
242                          if (g_ownbackstore) \                          if (g_ownbackstore) \
243                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \                                  XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
244                          break; \                          break; \
245          } \          } \
246  }  }
247    
248  /* colour maps */  /* colour maps */
249  extern BOOL g_owncolmap;  extern RD_BOOL g_owncolmap;
250  static Colormap g_xcolmap;  static Colormap g_xcolmap;
251  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
252    
253  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
254  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
255  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
256    
# Line 175  static int rop2_map[] = { Line 276  static int rop2_map[] = {
276  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
277  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
278    
279    static seamless_window *
280    sw_get_window_by_id(unsigned long id)
281    {
282            seamless_window *sw;
283            for (sw = g_seamless_windows; sw; sw = sw->next)
284            {
285                    if (sw->id == id)
286                            return sw;
287            }
288            return NULL;
289    }
290    
291    
292    static seamless_window *
293    sw_get_window_by_wnd(Window wnd)
294    {
295            seamless_window *sw;
296            for (sw = g_seamless_windows; sw; sw = sw->next)
297            {
298                    if (sw->wnd == wnd)
299                            return sw;
300            }
301            return NULL;
302    }
303    
304    
305  static void  static void
306  mwm_hide_decorations(void)  sw_remove_window(seamless_window * win)
307    {
308            seamless_window *sw, **prevnext = &g_seamless_windows;
309            for (sw = g_seamless_windows; sw; sw = sw->next)
310            {
311                    if (sw == win)
312                    {
313                            *prevnext = sw->next;
314                            sw->group->refcnt--;
315                            if (sw->group->refcnt == 0)
316                            {
317                                    XDestroyWindow(g_display, sw->group->wnd);
318                                    xfree(sw->group);
319                            }
320                            xfree(sw->position_timer);
321                            xfree(sw);
322                            return;
323                    }
324                    prevnext = &sw->next;
325            }
326            return;
327    }
328    
329    
330    /* Move all windows except wnd to new desktop */
331    static void
332    sw_all_to_desktop(Window wnd, unsigned int desktop)
333    {
334            seamless_window *sw;
335            for (sw = g_seamless_windows; sw; sw = sw->next)
336            {
337                    if (sw->wnd == wnd)
338                            continue;
339                    if (sw->desktop != desktop)
340                    {
341                            ewmh_move_to_desktop(sw->wnd, desktop);
342                            sw->desktop = desktop;
343                    }
344            }
345    }
346    
347    
348    /* Send our position */
349    static void
350    sw_update_position(seamless_window * sw)
351    {
352            XWindowAttributes wa;
353            int x, y;
354            Window child_return;
355            unsigned int serial;
356    
357            XGetWindowAttributes(g_display, sw->wnd, &wa);
358            XTranslateCoordinates(g_display, sw->wnd, wa.root,
359                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
360    
361            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
362    
363            sw->outstanding_position = True;
364            sw->outpos_serial = serial;
365    
366            sw->outpos_xoffset = x;
367            sw->outpos_yoffset = y;
368            sw->outpos_width = wa.width;
369            sw->outpos_height = wa.height;
370    }
371    
372    
373    /* Check if it's time to send our position */
374    static void
375    sw_check_timers()
376    {
377            seamless_window *sw;
378            struct timeval now;
379    
380            gettimeofday(&now, NULL);
381            for (sw = g_seamless_windows; sw; sw = sw->next)
382            {
383                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
384                    {
385                            timerclear(sw->position_timer);
386                            sw_update_position(sw);
387                    }
388            }
389    }
390    
391    
392    static void
393    sw_restack_window(seamless_window * sw, unsigned long behind)
394    {
395            seamless_window *sw_above;
396    
397            /* Remove window from stack */
398            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
399            {
400                    if (sw_above->behind == sw->id)
401                            break;
402            }
403    
404            if (sw_above)
405                    sw_above->behind = sw->behind;
406    
407            /* And then add it at the new position */
408            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
409            {
410                    if (sw_above->behind == behind)
411                            break;
412            }
413    
414            if (sw_above)
415                    sw_above->behind = sw->id;
416    
417            sw->behind = behind;
418    }
419    
420    
421    static void
422    sw_handle_restack(seamless_window * sw)
423    {
424            Status status;
425            Window root, parent, *children;
426            unsigned int nchildren, i;
427            seamless_window *sw_below;
428    
429            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
430                                &root, &parent, &children, &nchildren);
431            if (!status || !nchildren)
432                    return;
433    
434            sw_below = NULL;
435    
436            i = 0;
437            while (children[i] != sw->wnd)
438            {
439                    i++;
440                    if (i >= nchildren)
441                            goto end;
442            }
443    
444            for (i++; i < nchildren; i++)
445            {
446                    sw_below = sw_get_window_by_wnd(children[i]);
447                    if (sw_below)
448                            break;
449            }
450    
451            if (!sw_below && !sw->behind)
452                    goto end;
453            if (sw_below && (sw_below->id == sw->behind))
454                    goto end;
455    
456            if (sw_below)
457            {
458                    seamless_send_zchange(sw->id, sw_below->id, 0);
459                    sw_restack_window(sw, sw_below->id);
460            }
461            else
462            {
463                    seamless_send_zchange(sw->id, 0, 0);
464                    sw_restack_window(sw, 0);
465            }
466    
467          end:
468            XFree(children);
469    }
470    
471    
472    static seamless_group *
473    sw_find_group(unsigned long id, RD_BOOL dont_create)
474    {
475            seamless_window *sw;
476            seamless_group *sg;
477            XSetWindowAttributes attribs;
478    
479            for (sw = g_seamless_windows; sw; sw = sw->next)
480            {
481                    if (sw->group->id == id)
482                            return sw->group;
483            }
484    
485            if (dont_create)
486                    return NULL;
487    
488            sg = xmalloc(sizeof(seamless_group));
489    
490            sg->wnd =
491                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
492                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
493    
494            sg->id = id;
495            sg->refcnt = 0;
496    
497            return sg;
498    }
499    
500    
501    static void
502    mwm_hide_decorations(Window wnd)
503  {  {
504          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
505          Atom hintsatom;          Atom hintsatom;
# Line 193  mwm_hide_decorations(void) Line 516  mwm_hide_decorations(void)
516                  return;                  return;
517          }          }
518    
519          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
520                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
521    
522  }  }
523    
524  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 228  mwm_hide_decorations(void) Line 552  mwm_hide_decorations(void)
552  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
553                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
554    
555    /* The following macros output the same octet sequences
556       on both BE and LE hosts: */
557    
558  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
559  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
560  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
# Line 239  static uint32 Line 566  static uint32
566  translate_colour(uint32 colour)  translate_colour(uint32 colour)
567  {  {
568          PixelColour pc;          PixelColour pc;
569          switch (g_server_bpp)          switch (g_server_depth)
570          {          {
571                  case 15:                  case 15:
572                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 250  translate_colour(uint32 colour) Line 577  translate_colour(uint32 colour)
577                  case 24:                  case 24:
578                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
579                          break;                          break;
580                    default:
581                            /* Avoid warning */
582                            pc.red = 0;
583                            pc.green = 0;
584                            pc.blue = 0;
585                            break;
586          }          }
587          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
588  }  }
# Line 301  translate8to16(const uint8 * data, uint8 Line 634  translate8to16(const uint8 * data, uint8
634  {  {
635          uint16 value;          uint16 value;
636    
637          if (g_arch_match)          if (g_compatible_arch)
638          {          {
639                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
640                  REPEAT2                  REPEAT2
# Line 335  translate8to24(const uint8 * data, uint8 Line 668  translate8to24(const uint8 * data, uint8
668  {  {
669          uint32 value;          uint32 value;
670    
671          if (g_xserver_be)          if (g_compatible_arch)
672          {          {
673                  while (out < end)                  while (out < end)
674                  {                  {
# Line 358  translate8to32(const uint8 * data, uint8 Line 691  translate8to32(const uint8 * data, uint8
691  {  {
692          uint32 value;          uint32 value;
693    
694          if (g_arch_match)          if (g_compatible_arch)
695          {          {
696                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
697                  REPEAT4                  REPEAT4
# Line 430  translate15to24(const uint16 * data, uin Line 763  translate15to24(const uint16 * data, uin
763          uint16 pixel;          uint16 pixel;
764          PixelColour pc;          PixelColour pc;
765    
766          if (g_arch_match)          if (g_compatible_arch)
767          {          {
768                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
769                  REPEAT3                  REPEAT3
# Line 480  translate15to32(const uint16 * data, uin Line 813  translate15to32(const uint16 * data, uin
813          uint32 value;          uint32 value;
814          PixelColour pc;          PixelColour pc;
815    
816          if (g_arch_match)          if (g_compatible_arch)
817          {          {
818                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
819                  REPEAT4                  REPEAT4
# Line 588  translate16to24(const uint16 * data, uin Line 921  translate16to24(const uint16 * data, uin
921          uint16 pixel;          uint16 pixel;
922          PixelColour pc;          PixelColour pc;
923    
924          if (g_arch_match)          if (g_compatible_arch)
925          {          {
926                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
927                  REPEAT3                  REPEAT3
# Line 658  translate16to32(const uint16 * data, uin Line 991  translate16to32(const uint16 * data, uin
991          uint32 value;          uint32 value;
992          PixelColour pc;          PixelColour pc;
993    
994          if (g_arch_match)          if (g_compatible_arch)
995          {          {
996                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
997                  REPEAT4                  REPEAT4
# Line 787  translate24to32(const uint8 * data, uint Line 1120  translate24to32(const uint8 * data, uint
1120          uint32 value;          uint32 value;
1121          PixelColour pc;          PixelColour pc;
1122    
1123          if (g_arch_match)          if (g_compatible_arch)
1124          {          {
1125                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
1126  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 801  translate24to32(const uint8 * data, uint Line 1134  translate24to32(const uint8 * data, uint
1134  #else  #else
1135                  REPEAT4                  REPEAT4
1136                  (                  (
1137                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1138                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1139                          data += 3;                   out += 4;
1140                     data += 3;
1141                  )                  )
1142  #endif  #endif
1143                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 841  translate_image(int width, int height, u Line 1175  translate_image(int width, int height, u
1175          uint8 *out;          uint8 *out;
1176          uint8 *end;          uint8 *end;
1177    
1178          /* if server and xserver bpp match, */          /*
1179          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1180          /* just return data */             and arch(endian) matches, no need to translate:
1181          if (g_arch_match)             just return data.
1182               Note: select_visual should've already ensured g_no_translate
1183               is only set for compatible depths, but the RDP depth might've
1184               changed during connection negotiations.
1185             */
1186            if (g_no_translate_image)
1187          {          {
1188                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1189                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1190                  if (g_depth == 16 && g_server_bpp == 16)                      (g_depth == 24 && g_server_depth == 24))
                         return data;  
                 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)  
1191                          return data;                          return data;
1192          }          }
1193    
# Line 858  translate_image(int width, int height, u Line 1195  translate_image(int width, int height, u
1195          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1196          end = out + size;          end = out + size;
1197    
1198          switch (g_server_bpp)          switch (g_server_depth)
1199          {          {
1200                  case 24:                  case 24:
1201                          switch (g_bpp)                          switch (g_bpp)
# Line 923  translate_image(int width, int height, u Line 1260  translate_image(int width, int height, u
1260          return out;          return out;
1261  }  }
1262    
1263  BOOL  RD_BOOL
1264  get_key_state(unsigned int state, uint32 keysym)  get_key_state(unsigned int state, uint32 keysym)
1265  {  {
1266          int modifierpos, key, keysymMask = 0;          int modifierpos, key, keysymMask = 0;
# Line 956  calculate_shifts(uint32 mask, int *shift Line 1293  calculate_shifts(uint32 mask, int *shift
1293          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1294  }  }
1295    
1296  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1297  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1298     */
1299    static unsigned
1300    calculate_mask_weight(uint32 mask)
1301    {
1302            unsigned weight = 0;
1303            do
1304            {
1305                    weight += (mask & 1);
1306            }
1307            while (mask >>= 1);
1308            return weight;
1309    }
1310    
1311    static RD_BOOL
1312    select_visual(int screen_num)
1313  {  {
         XVisualInfo vi;  
1314          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1315          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1316          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1317          XVisualInfo template;          XVisualInfo template;
1318          Bool TrueColorVisual = False;          int i;
1319            unsigned red_weight, blue_weight, green_weight;
1320    
1321          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1322          if (g_display == NULL)  
1323            if (g_server_depth == -1)
1324          {          {
1325                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1326          }          }
1327    
1328          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1329          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1330          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1331          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1332                    XCloseDisplay(g_display);
1333                    return False;
1334            }
1335    
1336          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1337          template.class = TrueColor;          template.class = TrueColor;
1338          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          template.screen = screen_num;
1339            vmatches =
1340                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1341                                   &visuals_count);
1342            g_visual = NULL;
1343            g_no_translate_image = False;
1344            g_compatible_arch = False;
1345            if (vmatches != NULL)
1346            {
1347                    for (i = 0; i < visuals_count; ++i)
1348                    {
1349                            XVisualInfo *visual_info = &vmatches[i];
1350                            RD_BOOL can_translate_to_bpp = False;
1351                            int j;
1352    
1353                            /* Try to find a no-translation visual that'll
1354                               allow us to use RDP bitmaps directly as ZPixmaps. */
1355                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1356                                                   /* R5G5B5 */
1357                                                   (visual_info->red_mask == 0x7c00) &&
1358                                                   (visual_info->green_mask == 0x3e0) &&
1359                                                   (visual_info->blue_mask == 0x1f)) ||
1360                                                  ((visual_info->depth == 16) &&
1361                                                   /* R5G6B5 */
1362                                                   (visual_info->red_mask == 0xf800) &&
1363                                                   (visual_info->green_mask == 0x7e0) &&
1364                                                   (visual_info->blue_mask == 0x1f)) ||
1365                                                  ((visual_info->depth == 24) &&
1366                                                   /* R8G8B8 */
1367                                                   (visual_info->red_mask == 0xff0000) &&
1368                                                   (visual_info->green_mask == 0xff00) &&
1369                                                   (visual_info->blue_mask == 0xff))))
1370                            {
1371                                    g_visual = visual_info->visual;
1372                                    g_depth = visual_info->depth;
1373                                    g_compatible_arch = !g_host_be;
1374                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1375                                    if (g_no_translate_image)
1376                                            /* We found the best visual */
1377                                            break;
1378                            }
1379                            else
1380                            {
1381                                    g_compatible_arch = False;
1382                            }
1383    
1384                            if (visual_info->depth > 24)
1385                            {
1386                                    /* Avoid 32-bit visuals and likes like the plague.
1387                                       They're either untested or proven to work bad
1388                                       (e.g. nvidia's Composite 32-bit visual).
1389                                       Most implementation offer a 24-bit visual anyway. */
1390                                    continue;
1391                            }
1392    
1393          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1394          while (nvisuals >= 0)                             we have a translateXtoY function. */
1395          {                          for (j = 0; j < pixmap_formats_count; ++j)
1396                  if ((vmatches + nvisuals)->depth > g_depth)                          {
1397                  {                                  if (pfm[j].depth == visual_info->depth)
1398                          g_depth = (vmatches + nvisuals)->depth;                                  {
1399                                            if ((pfm[j].bits_per_pixel == 16) ||
1400                                                (pfm[j].bits_per_pixel == 24) ||
1401                                                (pfm[j].bits_per_pixel == 32))
1402                                            {
1403                                                    can_translate_to_bpp = True;
1404                                            }
1405                                            break;
1406                                    }
1407                            }
1408    
1409                            /* Prefer formats which have the most colour depth.
1410                               We're being truly aristocratic here, minding each
1411                               weight on its own. */
1412                            if (can_translate_to_bpp)
1413                            {
1414                                    unsigned vis_red_weight =
1415                                            calculate_mask_weight(visual_info->red_mask);
1416                                    unsigned vis_green_weight =
1417                                            calculate_mask_weight(visual_info->green_mask);
1418                                    unsigned vis_blue_weight =
1419                                            calculate_mask_weight(visual_info->blue_mask);
1420                                    if ((vis_red_weight >= red_weight)
1421                                        && (vis_green_weight >= green_weight)
1422                                        && (vis_blue_weight >= blue_weight))
1423                                    {
1424                                            red_weight = vis_red_weight;
1425                                            green_weight = vis_green_weight;
1426                                            blue_weight = vis_blue_weight;
1427                                            g_visual = visual_info->visual;
1428                                            g_depth = visual_info->depth;
1429                                    }
1430                            }
1431                  }                  }
1432                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1433          }          }
1434    
1435          test = 1;          if (g_visual != NULL)
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
         if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))  
1436          {          {
1437                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1438                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1439                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1440                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
                 /* Do not allocate colours on a TrueColor visual */  
                 if (g_visual->class == TrueColor)  
                 {  
                         g_owncolmap = False;  
                 }  
1441          }          }
1442          else          else
1443          {          {
1444                  /* need a truecolour visual */                  template.class = PseudoColor;
1445                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1446                  {                  template.colormap_size = 256;
1447                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1448                            XGetVisualInfo(g_display,
1449                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1450                                           &template, &visuals_count);
1451                    if (vmatches == NULL)
1452                    {
1453                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1454                            XCloseDisplay(g_display);
1455                            XFree(pfm);
1456                          return False;                          return False;
1457                  }                  }
1458    
1459                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1460                  g_owncolmap = False;                  g_owncolmap = True;
1461                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1462                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1463                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1464    
1465                  /* if RGB video and everything is little endian */          g_bpp = 0;
1466                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1467                      !g_xserver_be && !g_host_be)          {
1468                    XPixmapFormatValues *pf = &pfm[i];
1469                    if (pf->depth == g_depth)
1470                  {                  {
1471                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1472                                                g_blue_shift_l == 0))  
1473                            if (g_no_translate_image)
1474                          {                          {
1475                                  g_arch_match = True;                                  switch (g_server_depth)
1476                                    {
1477                                            case 15:
1478                                            case 16:
1479                                                    if (g_bpp != 16)
1480                                                            g_no_translate_image = False;
1481                                                    break;
1482                                            case 24:
1483                                                    /* Yes, this will force image translation
1484                                                       on most modern servers which use 32 bits
1485                                                       for R8G8B8. */
1486                                                    if (g_bpp != 24)
1487                                                            g_no_translate_image = False;
1488                                                    break;
1489                                            default:
1490                                                    g_no_translate_image = False;
1491                                                    break;
1492                                    }
1493                          }                          }
                 }  
1494    
1495                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1496                  {                             there's just a single entry for every depth,
1497                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1498                            break;
1499                  }                  }
1500          }          }
1501            XFree(pfm);
1502            pfm = NULL;
1503            return True;
1504    }
1505    
1506    static XErrorHandler g_old_error_handler;
1507    
1508          pfm = XListPixmapFormats(g_display, &i);  static int
1509          if (pfm != NULL)  error_handler(Display * dpy, XErrorEvent * eev)
1510    {
1511            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1512          {          {
1513                  /* Use maximum bpp for this depth - this is generally                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1514                     desirable, e.g. 24 bits->32 bits. */                  fprintf(stderr,
1515                  while (i--)                          "This is most likely caused by a broken window manager (commonly KWin).\n");
1516                  {                  return 0;
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1517          }          }
1518    
1519          if (g_bpp < 8)          return g_old_error_handler(dpy, eev);
1520    }
1521    
1522    RD_BOOL
1523    ui_init(void)
1524    {
1525            int screen_num;
1526    
1527            g_display = XOpenDisplay(NULL);
1528            if (g_display == NULL)
1529          {          {
1530                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
1531                  XCloseDisplay(g_display);                  return False;
1532            }
1533    
1534            {
1535                    uint16 endianess_test = 1;
1536                    g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1537            }
1538    
1539            g_old_error_handler = XSetErrorHandler(error_handler);
1540            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1541            screen_num = DefaultScreen(g_display);
1542            g_x_socket = ConnectionNumber(g_display);
1543            g_screen = ScreenOfDisplay(g_display, screen_num);
1544            g_depth = DefaultDepthOfScreen(g_screen);
1545    
1546            if (!select_visual(screen_num))
1547                  return False;                  return False;
1548    
1549            if (g_no_translate_image)
1550            {
1551                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1552            }
1553    
1554            if (g_server_depth > g_bpp)
1555            {
1556                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1557                            g_server_depth, g_bpp);
1558          }          }
1559    
1560            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1561                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1562    
1563          if (!g_owncolmap)          if (!g_owncolmap)
1564          {          {
1565                  g_xcolmap =                  g_xcolmap =
1566                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1567                                          AllocNone);                                          AllocNone);
1568                  if (g_depth <= 8)                  if (g_depth <= 8)
1569                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");                          warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1570          }          }
1571    
1572          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1573          {          {
1574                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1575                  g_ownbackstore = True;                  g_ownbackstore = True;
1576          }          }
1577    
# Line 1086  ui_init(void) Line 1582  ui_init(void)
1582          {          {
1583                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1584                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1585                    g_using_full_workarea = True;
1586          }          }
1587          else if (g_width < 0)          else if (g_width < 0)
1588          {          {
1589                  /* Percent of screen */                  /* Percent of screen */
1590                    if (-g_width >= 100)
1591                            g_using_full_workarea = True;
1592                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1593                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1594          }          }
# Line 1097  ui_init(void) Line 1596  ui_init(void)
1596          {          {
1597                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1598                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1599                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1600                  {                  {
1601                          g_width = cx;                          g_width = cx;
1602                          g_height = cy;                          g_height = cy;
1603                            g_using_full_workarea = True;
1604                  }                  }
1605                  else                  else
1606                  {                  {
1607                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");                          warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1608                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1609                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1610                  }                  }
1611          }          }
1612    
# Line 1122  ui_init(void) Line 1621  ui_init(void)
1621                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1622    
1623          xclip_init();          xclip_init();
1624            ewmh_init();
1625            if (g_seamless_rdp)
1626                    seamless_init();
1627    
1628          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1629    
1630          return True;          return True;
1631  }  }
# Line 1131  ui_init(void) Line 1633  ui_init(void)
1633  void  void
1634  ui_deinit(void)  ui_deinit(void)
1635  {  {
1636            while (g_seamless_windows)
1637            {
1638                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1639                    sw_remove_window(g_seamless_windows);
1640            }
1641    
1642            xclip_deinit();
1643    
1644          if (g_IM != NULL)          if (g_IM != NULL)
1645                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1646    
# Line 1147  ui_deinit(void) Line 1657  ui_deinit(void)
1657          g_display = NULL;          g_display = NULL;
1658  }  }
1659    
1660  BOOL  
1661    static void
1662    get_window_attribs(XSetWindowAttributes * attribs)
1663    {
1664            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1665            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1666            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1667            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1668            attribs->override_redirect = g_fullscreen;
1669            attribs->colormap = g_xcolmap;
1670    }
1671    
1672    static void
1673    get_input_mask(long *input_mask)
1674    {
1675            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1676                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1677    
1678            if (g_sendmotion)
1679                    *input_mask |= PointerMotionMask;
1680            if (g_ownbackstore)
1681                    *input_mask |= ExposureMask;
1682            if (g_fullscreen || g_grab_keyboard)
1683                    *input_mask |= EnterWindowMask;
1684            if (g_grab_keyboard)
1685                    *input_mask |= LeaveWindowMask;
1686    }
1687    
1688    RD_BOOL
1689  ui_create_window(void)  ui_create_window(void)
1690  {  {
1691          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
# Line 1163  ui_create_window(void) Line 1701  ui_create_window(void)
1701          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1702          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1703    
1704          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1705          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1706          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1707          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1708          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1709    
1710            get_window_attribs(&attribs);
1711    
1712          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1713                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1175  ui_create_window(void) Line 1715  ui_create_window(void)
1715                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1716    
1717          if (g_gc == NULL)          if (g_gc == NULL)
1718            {
1719                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1720                    ui_reset_clip();
1721            }
1722    
1723          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1724                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1190  ui_create_window(void) Line 1733  ui_create_window(void)
1733          }          }
1734    
1735          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1736            ewmh_set_wm_name(g_wnd, g_title);
1737    
1738          if (g_hide_decorations)          if (g_hide_decorations)
1739                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1740    
1741          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1742          if (classhints != NULL)          if (classhints != NULL)
# Line 1206  ui_create_window(void) Line 1750  ui_create_window(void)
1750          if (sizehints)          if (sizehints)
1751          {          {
1752                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1753                    if (g_pos)
1754                            sizehints->flags |= PPosition;
1755                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1756                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1757                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 1217  ui_create_window(void) Line 1763  ui_create_window(void)
1763                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1764          }          }
1765    
1766          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask;  
   
         if (g_sendmotion)  
                 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;  
1767    
1768          if (g_IM != NULL)          if (g_IM != NULL)
1769          {          {
# Line 1312  xwin_toggle_fullscreen(void) Line 1848  xwin_toggle_fullscreen(void)
1848  {  {
1849          Pixmap contents = 0;          Pixmap contents = 0;
1850    
1851            if (g_seamless_active)
1852                    /* Turn off SeamlessRDP mode */
1853                    ui_seamless_toggle();
1854    
1855          if (!g_ownbackstore)          if (!g_ownbackstore)
1856          {          {
1857                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1332  xwin_toggle_fullscreen(void) Line 1872  xwin_toggle_fullscreen(void)
1872          }          }
1873  }  }
1874    
1875  /* Process all events in Xlib queue  static void
1876    handle_button_event(XEvent xevent, RD_BOOL down)
1877    {
1878            uint16 button, flags = 0;
1879            g_last_gesturetime = xevent.xbutton.time;
1880            button = xkeymap_translate_button(xevent.xbutton.button);
1881            if (button == 0)
1882                    return;
1883    
1884            if (down)
1885                    flags = MOUSE_FLAG_DOWN;
1886    
1887            /* Stop moving window when button is released, regardless of cursor position */
1888            if (g_moving_wnd && (xevent.type == ButtonRelease))
1889                    g_moving_wnd = False;
1890    
1891            /* If win_button_size is nonzero, enable single app mode */
1892            if (xevent.xbutton.y < g_win_button_size)
1893            {
1894                    /*  Check from right to left: */
1895                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1896                    {
1897                            /* The close button, continue */
1898                            ;
1899                    }
1900                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1901                    {
1902                            /* The maximize/restore button. Do not send to
1903                               server.  It might be a good idea to change the
1904                               cursor or give some other visible indication
1905                               that rdesktop inhibited this click */
1906                            if (xevent.type == ButtonPress)
1907                                    return;
1908                    }
1909                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1910                    {
1911                            /* The minimize button. Iconify window. */
1912                            if (xevent.type == ButtonRelease)
1913                            {
1914                                    /* Release the mouse button outside the minimize button, to prevent the
1915                                       actual minimazation to happen */
1916                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1917                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1918                                    return;
1919                            }
1920                    }
1921                    else if (xevent.xbutton.x <= g_win_button_size)
1922                    {
1923                            /* The system menu. Ignore. */
1924                            if (xevent.type == ButtonPress)
1925                                    return;
1926                    }
1927                    else
1928                    {
1929                            /* The title bar. */
1930                            if (xevent.type == ButtonPress)
1931                            {
1932                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1933                                    {
1934                                            g_moving_wnd = True;
1935                                            g_move_x_offset = xevent.xbutton.x;
1936                                            g_move_y_offset = xevent.xbutton.y;
1937                                    }
1938                                    return;
1939                            }
1940                    }
1941            }
1942    
1943            if (xevent.xmotion.window == g_wnd)
1944            {
1945                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1946                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1947            }
1948            else
1949            {
1950                    /* SeamlessRDP */
1951                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1952                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1953            }
1954    }
1955    
1956    
1957    /* Process events in Xlib queue
1958     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1959  static int  static int
1960  xwin_process_events(void)  xwin_process_events(void)
1961  {  {
1962          XEvent xevent;          XEvent xevent;
1963          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1964          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1965          char str[256];          char str[256];
1966          Status status;          Status status;
1967            int events = 0;
1968            seamless_window *sw;
1969    
1970          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1971          {          {
1972                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1973    
# Line 1355  xwin_process_events(void) Line 1977  xwin_process_events(void)
1977                          continue;                          continue;
1978                  }                  }
1979    
                 flags = 0;  
   
1980                  switch (xevent.type)                  switch (xevent.type)
1981                  {                  {
1982                          case VisibilityNotify:                          case VisibilityNotify:
1983                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1984                                            g_Unobscured =
1985                                                    xevent.xvisibility.state == VisibilityUnobscured;
1986    
1987                                  break;                                  break;
1988                          case ClientMessage:                          case ClientMessage:
1989                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1393  xwin_process_events(void) Line 2016  xwin_process_events(void)
2016                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2017                                  }                                  }
2018    
2019                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2020                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2021    
2022                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2023                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2024                                          break;                                          break;
2025    
2026                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2027                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, 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);  
   
2028                                  break;                                  break;
2029    
2030                          case KeyRelease:                          case KeyRelease:
# Line 1418  xwin_process_events(void) Line 2032  xwin_process_events(void)
2032                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2033                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2034    
2035                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2036                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2037    
2038                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2039                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2040                                          break;                                          break;
2041    
2042                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2043                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2044                                  break;                                  break;
2045    
2046                          case ButtonPress:                          case ButtonPress:
2047                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2048                                  /* fall through */                                  break;
2049    
2050                          case ButtonRelease:                          case ButtonRelease:
2051                                  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);  
2052                                  break;                                  break;
2053    
2054                          case MotionNotify:                          case MotionNotify:
# Line 1511  xwin_process_events(void) Line 2063  xwin_process_events(void)
2063                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2064                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2065                                                         CurrentTime);                                                         CurrentTime);
2066                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2067                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2068                                    {
2069                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2070                                                           xevent.xmotion.x, xevent.xmotion.y);
2071                                    }
2072                                    else
2073                                    {
2074                                            /* SeamlessRDP */
2075                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2076                                                           xevent.xmotion.x_root,
2077                                                           xevent.xmotion.y_root);
2078                                    }
2079                                  break;                                  break;
2080    
2081                          case FocusIn:                          case FocusIn:
# Line 1523  xwin_process_events(void) Line 2086  xwin_process_events(void)
2086                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2087                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2088                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2089    
2090                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2091                                    if (!sw)
2092                                            break;
2093    
2094                                    if (sw->id != g_seamless_focused)
2095                                    {
2096                                            seamless_send_focus(sw->id, 0);
2097                                            g_seamless_focused = sw->id;
2098                                    }
2099                                  break;                                  break;
2100    
2101                          case FocusOut:                          case FocusOut:
# Line 1555  xwin_process_events(void) Line 2128  xwin_process_events(void)
2128                                  break;                                  break;
2129    
2130                          case Expose:                          case Expose:
2131                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2132                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2133                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2134                                            xevent.xexpose.height,                                                    g_gc,
2135                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2136                                                      xevent.xexpose.width, xevent.xexpose.height,
2137                                                      xevent.xexpose.x, xevent.xexpose.y);
2138                                    }
2139                                    else
2140                                    {
2141                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2142                                            if (!sw)
2143                                                    break;
2144                                            XCopyArea(g_display, g_backstore,
2145                                                      xevent.xexpose.window, g_gc,
2146                                                      xevent.xexpose.x + sw->xoffset,
2147                                                      xevent.xexpose.y + sw->yoffset,
2148                                                      xevent.xexpose.width,
2149                                                      xevent.xexpose.height, xevent.xexpose.x,
2150                                                      xevent.xexpose.y);
2151                                    }
2152    
2153                                  break;                                  break;
2154    
2155                          case MappingNotify:                          case MappingNotify:
# Line 1588  xwin_process_events(void) Line 2178  xwin_process_events(void)
2178                                  break;                                  break;
2179                          case PropertyNotify:                          case PropertyNotify:
2180                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2181                                    if (xevent.xproperty.window == g_wnd)
2182                                            break;
2183                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2184                                            break;
2185    
2186                                    /* seamless */
2187                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2188                                    if (!sw)
2189                                            break;
2190    
2191                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2192                                        && (xevent.xproperty.state == PropertyNewValue))
2193                                    {
2194                                            sw->state = ewmh_get_window_state(sw->wnd);
2195                                            seamless_send_state(sw->id, sw->state, 0);
2196                                    }
2197    
2198                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2199                                        && (xevent.xproperty.state == PropertyNewValue))
2200                                    {
2201                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2202                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2203                                    }
2204    
2205                                    break;
2206                            case MapNotify:
2207                                    if (!g_seamless_active)
2208                                            rdp_send_client_window_status(1);
2209                                    break;
2210                            case UnmapNotify:
2211                                    if (!g_seamless_active)
2212                                            rdp_send_client_window_status(0);
2213                                    break;
2214                            case ConfigureNotify:
2215                                    if (!g_seamless_active)
2216                                            break;
2217    
2218                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2219                                    if (!sw)
2220                                            break;
2221    
2222                                    gettimeofday(sw->position_timer, NULL);
2223                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2224                                        1000000)
2225                                    {
2226                                            sw->position_timer->tv_usec +=
2227                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2228                                            sw->position_timer->tv_sec += 1;
2229                                    }
2230                                    else
2231                                    {
2232                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2233                                    }
2234    
2235                                    sw_handle_restack(sw);
2236                                  break;                                  break;
2237                  }                  }
2238          }          }
# Line 1602  ui_select(int rdp_socket) Line 2247  ui_select(int rdp_socket)
2247          int n;          int n;
2248          fd_set rfds, wfds;          fd_set rfds, wfds;
2249          struct timeval tv;          struct timeval tv;
2250          BOOL s_timeout = False;          RD_BOOL s_timeout = False;
2251    
2252          while (True)          while (True)
2253          {          {
# Line 1612  ui_select(int rdp_socket) Line 2257  ui_select(int rdp_socket)
2257                          /* User quit */                          /* User quit */
2258                          return 0;                          return 0;
2259    
2260                    if (g_seamless_active)
2261                            sw_check_timers();
2262    
2263                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2264                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2265                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2266                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2267    
 #ifdef WITH_RDPSND  
                 /* FIXME: there should be an API for registering fds */  
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd > n) ? g_dsp_fd : n;  
                 }  
 #endif  
2268                  /* default timeout */                  /* default timeout */
2269                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2270                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2271    
2272    #ifdef WITH_RDPSND
2273                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2274    #endif
2275    
2276                  /* add redirection handles */                  /* add redirection handles */
2277                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2278                    seamless_select_timeout(&tv);
2279    
2280                  n++;                  n++;
2281    
# Line 1640  ui_select(int rdp_socket) Line 2285  ui_select(int rdp_socket)
2285                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2286    
2287                          case 0:                          case 0:
2288    #ifdef WITH_RDPSND
2289                                    rdpsnd_check_fds(&rfds, &wfds);
2290    #endif
2291    
2292                                  /* Abort serial read calls */                                  /* Abort serial read calls */
2293                                  if (s_timeout)                                  if (s_timeout)
2294                                          rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                          rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2295                                  continue;                                  continue;
2296                  }                  }
2297    
2298                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);  #ifdef WITH_RDPSND
2299                    rdpsnd_check_fds(&rfds, &wfds);
2300    #endif
2301    
2302                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2303    
2304                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2305                          return 1;                          return 1;
2306    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2307          }          }
2308  }  }
2309    
# Line 1664  ui_move_pointer(int x, int y) Line 2313  ui_move_pointer(int x, int y)
2313          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);
2314  }  }
2315    
2316  HBITMAP  RD_HBITMAP
2317  ui_create_bitmap(int width, int height, uint8 * data)  ui_create_bitmap(int width, int height, uint8 * data)
2318  {  {
2319          XImage *image;          XImage *image;
# Line 1672  ui_create_bitmap(int width, int height, Line 2321  ui_create_bitmap(int width, int height,
2321          uint8 *tdata;          uint8 *tdata;
2322          int bitmap_pad;          int bitmap_pad;
2323    
2324          if (g_server_bpp == 8)          if (g_server_depth == 8)
2325          {          {
2326                  bitmap_pad = 8;                  bitmap_pad = 8;
2327          }          }
# Line 1694  ui_create_bitmap(int width, int height, Line 2343  ui_create_bitmap(int width, int height,
2343          XFree(image);          XFree(image);
2344          if (tdata != data)          if (tdata != data)
2345                  xfree(tdata);                  xfree(tdata);
2346          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2347  }  }
2348    
2349  void  void
# Line 1704  ui_paint_bitmap(int x, int y, int cx, in Line 2353  ui_paint_bitmap(int x, int y, int cx, in
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 1724  ui_paint_bitmap(int x, int y, int cx, in Line 2373  ui_paint_bitmap(int x, int y, int cx, in
2373          {          {
2374                  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);
2375                  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);
2376                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2377                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2378                                             x - sw->xoffset, y - sw->yoffset));
2379          }          }
2380          else          else
2381          {          {
2382                  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);
2383                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2384                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2385                                             x - sw->xoffset, y - sw->yoffset));
2386          }          }
2387    
2388          XFree(image);          XFree(image);
# Line 1736  ui_paint_bitmap(int x, int y, int cx, in Line 2391  ui_paint_bitmap(int x, int y, int cx, in
2391  }  }
2392    
2393  void  void
2394  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2395  {  {
2396          XFreePixmap(g_display, (Pixmap) bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2397  }  }
2398    
2399  HGLYPH  RD_HGLYPH
2400  ui_create_glyph(int width, int height, uint8 * data)  ui_create_glyph(int width, int height, uint8 * data)
2401  {  {
2402          XImage *image;          XImage *image;
# Line 1763  ui_create_glyph(int width, int height, u Line 2418  ui_create_glyph(int width, int height, u
2418          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2419    
2420          XFree(image);          XFree(image);
2421          return (HGLYPH) bitmap;          return (RD_HGLYPH) bitmap;
2422  }  }
2423    
2424  void  void
2425  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2426  {  {
2427          XFreePixmap(g_display, (Pixmap) glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2428  }  }
2429    
2430  HCURSOR  RD_HCURSOR
2431  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,
2432                   uint8 * andmask, uint8 * xormask)                   uint8 * andmask, uint8 * xormask)
2433  {  {
2434          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2435          XColor bg, fg;          XColor bg, fg;
2436          Cursor xcursor;          Cursor xcursor;
2437          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 1840  ui_create_cursor(unsigned int x, unsigne Line 2495  ui_create_cursor(unsigned int x, unsigne
2495          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2496          xfree(mask);          xfree(mask);
2497          xfree(cursor);          xfree(cursor);
2498          return (HCURSOR) xcursor;          return (RD_HCURSOR) xcursor;
2499  }  }
2500    
2501  void  void
2502  ui_set_cursor(HCURSOR cursor)  ui_set_cursor(RD_HCURSOR cursor)
2503  {  {
2504          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2505          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2506            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2507  }  }
2508    
2509  void  void
2510  ui_destroy_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2511  {  {
2512          XFreeCursor(g_display, (Cursor) cursor);          XFreeCursor(g_display, (Cursor) cursor);
2513  }  }
# Line 1869  ui_set_null_cursor(void) Line 2525  ui_set_null_cursor(void)
2525                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2526    
2527    
2528  HCOLOURMAP  RD_HCOLOURMAP
2529  ui_create_colourmap(COLOURMAP * colours)  ui_create_colourmap(COLOURMAP * colours)
2530  {  {
2531          COLOURENTRY *entry;          COLOURENTRY *entry;
# Line 1965  ui_create_colourmap(COLOURMAP * colours) Line 2621  ui_create_colourmap(COLOURMAP * colours)
2621                  XStoreColors(g_display, map, xcolours, ncolours);                  XStoreColors(g_display, map, xcolours, ncolours);
2622    
2623                  xfree(xcolours);                  xfree(xcolours);
2624                  return (HCOLOURMAP) map;                  return (RD_HCOLOURMAP) map;
2625          }          }
2626  }  }
2627    
2628  void  void
2629  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2630  {  {
2631          if (!g_owncolmap)          if (!g_owncolmap)
2632                  xfree(map);                  xfree(map);
# Line 1979  ui_destroy_colourmap(HCOLOURMAP map) Line 2635  ui_destroy_colourmap(HCOLOURMAP map)
2635  }  }
2636    
2637  void  void
2638  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2639  {  {
2640          if (!g_owncolmap)          if (!g_owncolmap)
2641          {          {
# Line 1989  ui_set_colourmap(HCOLOURMAP map) Line 2645  ui_set_colourmap(HCOLOURMAP map)
2645                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2646          }          }
2647          else          else
2648            {
2649                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2650                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2651            }
2652  }  }
2653    
2654  void  void
2655  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2656  {  {
2657          XRectangle rect;          g_clip_rectangle.x = x;
2658            g_clip_rectangle.y = y;
2659          rect.x = x;          g_clip_rectangle.width = cx;
2660          rect.y = y;          g_clip_rectangle.height = cy;
2661          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);  
2662  }  }
2663    
2664  void  void
2665  ui_reset_clip(void)  ui_reset_clip(void)
2666  {  {
2667          XRectangle rect;          g_clip_rectangle.x = 0;
2668            g_clip_rectangle.y = 0;
2669          rect.x = 0;          g_clip_rectangle.width = g_width;
2670          rect.y = 0;          g_clip_rectangle.height = g_height;
2671          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);  
2672  }  }
2673    
2674  void  void
# Line 2068  ui_patblt(uint8 opcode, Line 2723  ui_patblt(uint8 opcode,
2723                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2724                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2725                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2726                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2727                          break;                          break;
2728    
2729                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2083  ui_patblt(uint8 opcode, Line 2738  ui_patblt(uint8 opcode,
2738                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2739                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2740                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2741                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2742                          break;                          break;
2743    
2744                  default:                  default:
# Line 2094  ui_patblt(uint8 opcode, Line 2749  ui_patblt(uint8 opcode,
2749    
2750          if (g_ownbackstore)          if (g_ownbackstore)
2751                  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);
2752            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2753                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2754                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2755  }  }
2756    
2757  void  void
# Line 2104  ui_screenblt(uint8 opcode, Line 2762  ui_screenblt(uint8 opcode,
2762          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2763          if (g_ownbackstore)          if (g_ownbackstore)
2764          {          {
2765                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2766                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2767                          XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  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);  
                 }  
                 else  
                 {  
                         XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
                         XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,  
                                   y);  
                 }  
2768          }          }
2769          else          else
2770          {          {
2771                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2772          }          }
2773    
2774            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2775                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2776                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2777    
2778          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2779  }  }
2780    
2781  void  void
2782  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
2783            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2784            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
2785  {  {
2786          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2787          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);
2788            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2789                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2790                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2791          if (g_ownbackstore)          if (g_ownbackstore)
2792                  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);
2793          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2139  ui_memblt(uint8 opcode, Line 2796  ui_memblt(uint8 opcode,
2796  void  void
2797  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2798            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2799            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
2800            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2801  {  {
2802          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
# Line 2177  ui_line(uint8 opcode, Line 2834  ui_line(uint8 opcode,
2834          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2835          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2836          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2837            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2838                                                startx - sw->xoffset, starty - sw->yoffset,
2839                                                endx - sw->xoffset, endy - sw->yoffset));
2840          if (g_ownbackstore)          if (g_ownbackstore)
2841                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2842          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2194  ui_rect( Line 2854  ui_rect(
2854  void  void
2855  ui_polygon(uint8 opcode,  ui_polygon(uint8 opcode,
2856             /* mode */ uint8 fillmode,             /* mode */ uint8 fillmode,
2857             /* dest */ POINT * point, int npoints,             /* dest */ RD_POINT * point, int npoints,
2858             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)             /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2859  {  {
2860          uint8 style, i, ipattern[8];          uint8 style, i, ipattern[8];
# Line 2237  ui_polygon(uint8 opcode, Line 2897  ui_polygon(uint8 opcode,
2897                          FILL_POLYGON((XPoint *) point, npoints);                          FILL_POLYGON((XPoint *) point, npoints);
2898                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2899                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2900                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2901                          break;                          break;
2902    
2903                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2252  ui_polygon(uint8 opcode, Line 2912  ui_polygon(uint8 opcode,
2912                          FILL_POLYGON((XPoint *) point, npoints);                          FILL_POLYGON((XPoint *) point, npoints);
2913                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2914                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2915                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2916                          break;                          break;
2917    
2918                  default:                  default:
# Line 2264  ui_polygon(uint8 opcode, Line 2924  ui_polygon(uint8 opcode,
2924    
2925  void  void
2926  ui_polyline(uint8 opcode,  ui_polyline(uint8 opcode,
2927              /* dest */ POINT * points, int npoints,              /* dest */ RD_POINT * points, int npoints,
2928              /* pen */ PEN * pen)              /* pen */ PEN * pen)
2929  {  {
2930          /* TODO: set join style */          /* TODO: set join style */
# Line 2274  ui_polyline(uint8 opcode, Line 2934  ui_polyline(uint8 opcode,
2934          if (g_ownbackstore)          if (g_ownbackstore)
2935                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2936                             CoordModePrevious);                             CoordModePrevious);
2937    
2938            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2939                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2940    
2941          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2942  }  }
2943    
# Line 2311  ui_ellipse(uint8 opcode, Line 2975  ui_ellipse(uint8 opcode,
2975                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2976                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2977                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2978                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2979                          break;                          break;
2980    
2981                  case 3: /* Pattern */                  case 3: /* Pattern */
# Line 2326  ui_ellipse(uint8 opcode, Line 2990  ui_ellipse(uint8 opcode,
2990                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);                          DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2991                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2992                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2993                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((RD_HGLYPH) fill);
2994                          break;                          break;
2995    
2996                  default:                  default:
# Line 2340  ui_ellipse(uint8 opcode, Line 3004  ui_ellipse(uint8 opcode,
3004  void  void
3005  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3006                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3007                /* src */ HGLYPH glyph, int srcx, int srcy,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3008                int bgcolour, int fgcolour)                int bgcolour, int fgcolour)
3009  {  {
3010          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
# Line 2429  ui_draw_text(uint8 font, uint8 flags, ui Line 3093  ui_draw_text(uint8 font, uint8 flags, ui
3093                  switch (text[i])                  switch (text[i])
3094                  {                  {
3095                          case 0xff:                          case 0xff:
3096                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3097                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3098                                  {                                  {
3099                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3100                                          exit(1);                                          for (j = 0; j < length; j++)
3101                                                    fprintf(stderr, "%02x ", text[j]);
3102                                            fprintf(stderr, "\n");
3103                                            i = length = 0;
3104                                            break;
3105                                  }                                  }
3106                                    cache_put_text(text[i + 1], text, text[i + 2]);
3107                                    i += 3;
3108                                    length -= i;
3109                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3110                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3111                                  i = 0;                                  i = 0;
3112                                  break;                                  break;
3113    
3114                          case 0xfe:                          case 0xfe:
3115                                    /* At least one byte needs to follow */
3116                                    if (i + 2 > length)
3117                                    {
3118                                            warning("Skipping short 0xfe command:");
3119                                            for (j = 0; j < length; j++)
3120                                                    fprintf(stderr, "%02x ", text[j]);
3121                                            fprintf(stderr, "\n");
3122                                            i = length = 0;
3123                                            break;
3124                                    }
3125                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3126                                  if (entry != NULL)                                  if (entry->data != NULL)
3127                                  {                                  {
3128                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3129                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3130                                          {                                          {
3131                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3132                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2479  ui_draw_text(uint8 font, uint8 flags, ui Line 3158  ui_draw_text(uint8 font, uint8 flags, ui
3158          if (g_ownbackstore)          if (g_ownbackstore)
3159          {          {
3160                  if (boxcx > 1)                  if (boxcx > 1)
3161                    {
3162                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3163                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3164                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3165                                                    (g_display, g_backstore, sw->wnd, g_gc,
3166                                                     boxx, boxy,
3167                                                     boxcx, boxcy,
3168                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3169                    }
3170                  else                  else
3171                    {
3172                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3173                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3174                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3175                                                    (g_display, g_backstore, sw->wnd, g_gc,
3176                                                     clipx, clipy,
3177                                                     clipcx, clipcy, clipx - sw->xoffset,
3178                                                     clipy - sw->yoffset));
3179                    }
3180          }          }
3181  }  }
3182    
# Line 2496  ui_desktop_save(uint32 offset, int x, in Line 3189  ui_desktop_save(uint32 offset, int x, in
3189          if (g_ownbackstore)          if (g_ownbackstore)
3190          {          {
3191                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3192                    exit_if_null(image);
3193          }          }
3194          else          else
3195          {          {
3196                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3197                  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);
3198                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3199                    exit_if_null(image);
3200                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3201          }          }
3202    
# Line 2529  ui_desktop_restore(uint32 offset, int x, Line 3224  ui_desktop_restore(uint32 offset, int x,
3224          {          {
3225                  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);
3226                  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);
3227                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3228                                            (g_display, g_backstore, sw->wnd, g_gc,
3229                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3230          }          }
3231          else          else
3232          {          {
3233                  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);
3234                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3235                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3236                                             x - sw->xoffset, y - sw->yoffset));
3237          }          }
3238    
3239          XFree(image);          XFree(image);
# Line 2548  void Line 3249  void
3249  ui_end_update(void)  ui_end_update(void)
3250  {  {
3251  }  }
3252    
3253    
3254    void
3255    ui_seamless_begin(RD_BOOL hidden)
3256    {
3257            if (!g_seamless_rdp)
3258                    return;
3259    
3260            if (g_seamless_started)
3261                    return;
3262    
3263            g_seamless_started = True;
3264            g_seamless_hidden = hidden;
3265    
3266            if (!hidden)
3267                    ui_seamless_toggle();
3268    }
3269    
3270    
3271    void
3272    ui_seamless_hide_desktop()
3273    {
3274            if (!g_seamless_rdp)
3275                    return;
3276    
3277            if (!g_seamless_started)
3278                    return;
3279    
3280            if (g_seamless_active)
3281                    ui_seamless_toggle();
3282    
3283            g_seamless_hidden = True;
3284    }
3285    
3286    
3287    void
3288    ui_seamless_unhide_desktop()
3289    {
3290            if (!g_seamless_rdp)
3291                    return;
3292    
3293            if (!g_seamless_started)
3294                    return;
3295    
3296            g_seamless_hidden = False;
3297    
3298            ui_seamless_toggle();
3299    }
3300    
3301    
3302    void
3303    ui_seamless_toggle()
3304    {
3305            if (!g_seamless_rdp)
3306                    return;
3307    
3308            if (!g_seamless_started)
3309                    return;
3310    
3311            if (g_seamless_hidden)
3312                    return;
3313    
3314            if (g_seamless_active)
3315            {
3316                    /* Deactivate */
3317                    while (g_seamless_windows)
3318                    {
3319                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3320                            sw_remove_window(g_seamless_windows);
3321                    }
3322                    XMapWindow(g_display, g_wnd);
3323            }
3324            else
3325            {
3326                    /* Activate */
3327                    XUnmapWindow(g_display, g_wnd);
3328                    seamless_send_sync();
3329            }
3330    
3331            g_seamless_active = !g_seamless_active;
3332    }
3333    
3334    
3335    void
3336    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3337                              unsigned long flags)
3338    {
3339            Window wnd;
3340            XSetWindowAttributes attribs;
3341            XClassHint *classhints;
3342            XSizeHints *sizehints;
3343            XWMHints *wmhints;
3344            long input_mask;
3345            seamless_window *sw, *sw_parent;
3346    
3347            if (!g_seamless_active)
3348                    return;
3349    
3350            /* Ignore CREATEs for existing windows */
3351            sw = sw_get_window_by_id(id);
3352            if (sw)
3353                    return;
3354    
3355            get_window_attribs(&attribs);
3356            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3357                                InputOutput, g_visual,
3358                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3359    
3360            XStoreName(g_display, wnd, "SeamlessRDP");
3361            ewmh_set_wm_name(wnd, "SeamlessRDP");
3362    
3363            mwm_hide_decorations(wnd);
3364    
3365            classhints = XAllocClassHint();
3366            if (classhints != NULL)
3367            {
3368                    classhints->res_name = "rdesktop";
3369                    classhints->res_class = "SeamlessRDP";
3370                    XSetClassHint(g_display, wnd, classhints);
3371                    XFree(classhints);
3372            }
3373    
3374            /* WM_NORMAL_HINTS */
3375            sizehints = XAllocSizeHints();
3376            if (sizehints != NULL)
3377            {
3378                    sizehints->flags = USPosition;
3379                    XSetWMNormalHints(g_display, wnd, sizehints);
3380                    XFree(sizehints);
3381            }
3382    
3383            /* Parent-less transient windows */
3384            if (parent == 0xFFFFFFFF)
3385            {
3386                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3387                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3388                       using some other hints. */
3389                    ewmh_set_window_popup(wnd);
3390            }
3391            /* Normal transient windows */
3392            else if (parent != 0x00000000)
3393            {
3394                    sw_parent = sw_get_window_by_id(parent);
3395                    if (sw_parent)
3396                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3397                    else
3398                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3399            }
3400    
3401            if (flags & SEAMLESSRDP_CREATE_MODAL)
3402            {
3403                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3404                       somewhat at least */
3405                    if (parent == 0x00000000)
3406                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3407                    ewmh_set_window_modal(wnd);
3408            }
3409    
3410            /* FIXME: Support for Input Context:s */
3411    
3412            get_input_mask(&input_mask);
3413            input_mask |= PropertyChangeMask;
3414    
3415            XSelectInput(g_display, wnd, input_mask);
3416    
3417            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3418               seamless window, we could try to close the window on the
3419               serverside, instead of terminating rdesktop */
3420            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3421    
3422            sw = xmalloc(sizeof(seamless_window));
3423            sw->wnd = wnd;
3424            sw->id = id;
3425            sw->behind = 0;
3426            sw->group = sw_find_group(group, False);
3427            sw->group->refcnt++;
3428            sw->xoffset = 0;
3429            sw->yoffset = 0;
3430            sw->width = 0;
3431            sw->height = 0;
3432            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3433            sw->desktop = 0;
3434            sw->position_timer = xmalloc(sizeof(struct timeval));
3435            timerclear(sw->position_timer);
3436    
3437            sw->outstanding_position = False;
3438            sw->outpos_serial = 0;
3439            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3440            sw->outpos_width = sw->outpos_height = 0;
3441    
3442            sw->next = g_seamless_windows;
3443            g_seamless_windows = sw;
3444    
3445            /* WM_HINTS */
3446            wmhints = XAllocWMHints();
3447            if (wmhints)
3448            {
3449                    wmhints->flags = WindowGroupHint;
3450                    wmhints->window_group = sw->group->wnd;
3451                    XSetWMHints(g_display, sw->wnd, wmhints);
3452                    XFree(wmhints);
3453            }
3454    }
3455    
3456    
3457    void
3458    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3459    {
3460            seamless_window *sw;
3461    
3462            if (!g_seamless_active)
3463                    return;
3464    
3465            sw = sw_get_window_by_id(id);
3466            if (!sw)
3467            {
3468                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3469                    return;
3470            }
3471    
3472            XDestroyWindow(g_display, sw->wnd);
3473            sw_remove_window(sw);
3474    }
3475    
3476    
3477    void
3478    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3479    {
3480            seamless_window *sw, *sw_next;
3481    
3482            if (!g_seamless_active)
3483                    return;
3484    
3485            for (sw = g_seamless_windows; sw; sw = sw_next)
3486            {
3487                    sw_next = sw->next;
3488    
3489                    if (sw->group->id == id)
3490                    {
3491                            XDestroyWindow(g_display, sw->wnd);
3492                            sw_remove_window(sw);
3493                    }
3494            }
3495    }
3496    
3497    
3498    void
3499    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3500    {
3501            seamless_window *sw;
3502    
3503            if (!g_seamless_active)
3504                    return;
3505    
3506            sw = sw_get_window_by_id(id);
3507            if (!sw)
3508            {
3509                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3510                    return;
3511            }
3512    
3513            /* We ignore server updates until it has handled our request. */
3514            if (sw->outstanding_position)
3515                    return;
3516    
3517            if (!width || !height)
3518                    /* X11 windows must be at least 1x1 */
3519                    return;
3520    
3521            sw->xoffset = x;
3522            sw->yoffset = y;
3523            sw->width = width;
3524            sw->height = height;
3525    
3526            /* If we move the window in a maximized state, then KDE won't
3527               accept restoration */
3528            switch (sw->state)
3529            {
3530                    case SEAMLESSRDP_MINIMIZED:
3531                    case SEAMLESSRDP_MAXIMIZED:
3532                            return;
3533            }
3534    
3535            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3536            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3537    }
3538    
3539    
3540    void
3541    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3542    {
3543            seamless_window *sw;
3544    
3545            if (!g_seamless_active)
3546                    return;
3547    
3548            sw = sw_get_window_by_id(id);
3549            if (!sw)
3550            {
3551                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3552                    return;
3553            }
3554    
3555            if (behind)
3556            {
3557                    seamless_window *sw_behind;
3558                    Window wnds[2];
3559    
3560                    sw_behind = sw_get_window_by_id(behind);
3561                    if (!sw_behind)
3562                    {
3563                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3564                                    behind);
3565                            return;
3566                    }
3567    
3568                    wnds[1] = sw_behind->wnd;
3569                    wnds[0] = sw->wnd;
3570    
3571                    XRestackWindows(g_display, wnds, 2);
3572            }
3573            else
3574            {
3575                    XRaiseWindow(g_display, sw->wnd);
3576            }
3577    
3578            sw_restack_window(sw, behind);
3579    }
3580    
3581    
3582    void
3583    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3584    {
3585            seamless_window *sw;
3586    
3587            if (!g_seamless_active)
3588                    return;
3589    
3590            sw = sw_get_window_by_id(id);
3591            if (!sw)
3592            {
3593                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3594                    return;
3595            }
3596    
3597            /* FIXME: Might want to convert the name for non-EWMH WMs */
3598            XStoreName(g_display, sw->wnd, title);
3599            ewmh_set_wm_name(sw->wnd, title);
3600    }
3601    
3602    
3603    void
3604    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3605    {
3606            seamless_window *sw;
3607    
3608            if (!g_seamless_active)
3609                    return;
3610    
3611            sw = sw_get_window_by_id(id);
3612            if (!sw)
3613            {
3614                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3615                    return;
3616            }
3617    
3618            switch (state)
3619            {
3620                    case SEAMLESSRDP_NORMAL:
3621                    case SEAMLESSRDP_MAXIMIZED:
3622                            ewmh_change_state(sw->wnd, state);
3623                            XMapWindow(g_display, sw->wnd);
3624                            break;
3625                    case SEAMLESSRDP_MINIMIZED:
3626                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3627                               the Window Manager should probably just ignore the request, since
3628                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3629                               such as minimization, rather than an independent state." Besides,
3630                               XIconifyWindow is easier. */
3631                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3632                            {
3633                                    XWMHints *hints;
3634                                    hints = XGetWMHints(g_display, sw->wnd);
3635                                    if (hints)
3636                                    {
3637                                            hints->flags |= StateHint;
3638                                            hints->initial_state = IconicState;
3639                                            XSetWMHints(g_display, sw->wnd, hints);
3640                                            XFree(hints);
3641                                    }
3642                                    XMapWindow(g_display, sw->wnd);
3643                            }
3644                            else
3645                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3646                            break;
3647                    default:
3648                            warning("SeamlessRDP: Invalid state %d\n", state);
3649                            break;
3650            }
3651    
3652            sw->state = state;
3653    }
3654    
3655    
3656    void
3657    ui_seamless_syncbegin(unsigned long flags)
3658    {
3659            if (!g_seamless_active)
3660                    return;
3661    
3662            /* Destroy all seamless windows */
3663            while (g_seamless_windows)
3664            {
3665                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3666                    sw_remove_window(g_seamless_windows);
3667            }
3668    }
3669    
3670    
3671    void
3672    ui_seamless_ack(unsigned int serial)
3673    {
3674            seamless_window *sw;
3675            for (sw = g_seamless_windows; sw; sw = sw->next)
3676            {
3677                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3678                    {
3679                            sw->xoffset = sw->outpos_xoffset;
3680                            sw->yoffset = sw->outpos_yoffset;
3681                            sw->width = sw->outpos_width;
3682                            sw->height = sw->outpos_height;
3683                            sw->outstanding_position = False;
3684    
3685                            /* Do a complete redraw of the window as part of the
3686                               completion of the move. This is to remove any
3687                               artifacts caused by our lack of synchronization. */
3688                            XCopyArea(g_display, g_backstore,
3689                                      sw->wnd, g_gc,
3690                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3691    
3692                            break;
3693                    }
3694            }
3695    }

Legend:
Removed from v.844  
changed lines
  Added in v.1380

  ViewVC Help
Powered by ViewVC 1.1.26