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

Legend:
Removed from v.448  
changed lines
  Added in v.1453

  ViewVC Help
Powered by ViewVC 1.1.26