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

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

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

sourceforge.net/trunk/rdesktop/xwin.c revision 519 by matthewc, Tue Oct 28 03:40:26 2003 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1170 by astrand, Mon Mar 20 15:43:15 2006 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 20  Line 20 
20    
21  #include <X11/Xlib.h>  #include <X11/Xlib.h>
22  #include <X11/Xutil.h>  #include <X11/Xutil.h>
23    #include <unistd.h>
24    #include <sys/time.h>
25  #include <time.h>  #include <time.h>
26  #include <errno.h>  #include <errno.h>
27    #include <strings.h>
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31  extern int g_width;  extern int g_width;
32  extern int g_height;  extern int g_height;
33    extern int g_xpos;
34    extern int g_ypos;
35    extern int g_pos;
36  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
37  extern BOOL g_fullscreen;  extern BOOL g_fullscreen;
38  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
39  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
40  extern char g_title[];  extern char g_title[];
41  extern int g_server_bpp;  /* Color depth of the RDP session.
42       As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44  extern int g_win_button_size;  extern int g_win_button_size;
45    
46  Display *g_display;  Display *g_display;
# Line 40  Time g_last_gesturetime; Line 48  Time g_last_gesturetime;
48  static int g_x_socket;  static int g_x_socket;
49  static Screen *g_screen;  static Screen *g_screen;
50  Window g_wnd;  Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            unsigned long behind;
58            int xoffset, yoffset;
59            int width, height;
60            int state;              /* normal/minimized/maximized. */
61            unsigned int desktop;
62            struct timeval *position_timer;
63    
64            BOOL outstanding_position;
65            unsigned int outpos_serial;
66            int outpos_xoffset, outpos_yoffset;
67            int outpos_width, outpos_height;
68    
69            struct _seamless_window *next;
70    } seamless_window;
71    static seamless_window *g_seamless_windows = NULL;
72    static unsigned long g_seamless_focused = 0;
73    static BOOL g_seamless_started = False; /* Server end is up and running */
74    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
75    extern BOOL g_seamless_rdp;
76    
77    extern uint32 g_embed_wnd;
78  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
79  static GC g_gc;  BOOL g_Unobscured;              /* used for screenblt */
80    static GC g_gc = NULL;
81    static GC g_create_bitmap_gc = NULL;
82    static GC g_create_glyph_gc = NULL;
83    static XRectangle g_clip_rectangle;
84  static Visual *g_visual;  static Visual *g_visual;
85    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
86       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
87       as far as we're concerned. */
88  static int g_depth;  static int g_depth;
89    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
90       This may be larger than g_depth, in which case some of the bits would
91       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
92  static int g_bpp;  static int g_bpp;
93  static XIM g_IM;  static XIM g_IM;
94  static XIC g_IC;  static XIC g_IC;
95  static XModifierKeymap *g_mod_map;  static XModifierKeymap *g_mod_map;
96  static Cursor g_current_cursor;  static Cursor g_current_cursor;
97  static HCURSOR g_null_cursor;  static HCURSOR g_null_cursor = NULL;
98  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
99    extern Atom g_net_wm_state_atom;
100    extern Atom g_net_wm_desktop_atom;
101  static BOOL g_focused;  static BOOL g_focused;
102  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
103    /* Indicates that:
104       1) visual has 15, 16 or 24 depth and the same color channel masks
105          as its RDP equivalent (implies X server is LE),
106       2) host is LE
107       This will trigger an optimization whose real value is questionable.
108    */
109    static BOOL g_compatible_arch;
110    /* Indicates whether RDP's bitmaps and our XImages have the same
111       binary format. If so, we can avoid an expensive translation.
112       Note that this can be true when g_compatible_arch is false,
113       e.g.:
114      
115         RDP(LE) <-> host(BE) <-> X-Server(LE)
116        
117       ('host' is the machine running rdesktop; the host simply memcpy's
118        so its endianess doesn't matter)
119     */
120    static BOOL g_no_translate_image = False;
121    
122  /* endianness */  /* endianness */
123  static BOOL g_host_be;  static BOOL g_host_be;
124  static BOOL g_xserver_be;  static BOOL g_xserver_be;
125    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
126    static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
127    
128  /* software backing store */  /* software backing store */
129  static BOOL g_ownbackstore;  extern BOOL g_ownbackstore;
130  static Pixmap g_backstore;  static Pixmap g_backstore = 0;
131    
132  /* Moving in single app mode */  /* Moving in single app mode */
133  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
134  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
135  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
136    static BOOL g_using_full_workarea = False;
137    
138  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
139  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 78  extern BOOL g_rdpsnd; Line 146  extern BOOL g_rdpsnd;
146  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
147  typedef struct  typedef struct
148  {  {
149          uint32 flags;          unsigned long flags;
150          uint32 functions;          unsigned long functions;
151          uint32 decorations;          unsigned long decorations;
152          sint32 inputMode;          long inputMode;
153          uint32 status;          unsigned long status;
154  }  }
155  PropMotifWmHints;  PropMotifWmHints;
156    
# Line 94  typedef struct Line 162  typedef struct
162  }  }
163  PixelColour;  PixelColour;
164    
165    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
166            do { \
167                    seamless_window *sw; \
168                    XRectangle rect; \
169                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
170                        rect.x = g_clip_rectangle.x - sw->xoffset; \
171                        rect.y = g_clip_rectangle.y - sw->yoffset; \
172                        rect.width = g_clip_rectangle.width; \
173                        rect.height = g_clip_rectangle.height; \
174                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
175                        func args; \
176                    } \
177                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
178            } while (0)
179    
180    static void
181    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
182    {
183            points[0].x -= xoffset;
184            points[0].y -= yoffset;
185            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
186            points[0].x += xoffset;
187            points[0].y += yoffset;
188    }
189    
190    static void
191    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
192    {
193            points[0].x -= xoffset;
194            points[0].y -= yoffset;
195            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
196            points[0].x += xoffset;
197            points[0].y += yoffset;
198    }
199    
200  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
201  { \  { \
202          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
203            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
204          if (g_ownbackstore) \          if (g_ownbackstore) \
205                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
206  }  }
# Line 107  PixelColour; Line 210  PixelColour;
210          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
211  }  }
212    
213    #define FILL_POLYGON(p,np)\
214    { \
215            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
216            if (g_ownbackstore) \
217                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
218            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
219    }
220    
221    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
222    { \
223            switch (m) \
224            { \
225                    case 0: /* Outline */ \
226                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
227                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
228                            if (g_ownbackstore) \
229                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
230                            break; \
231                    case 1: /* Filled */ \
232                            XFillArc(g_display, g_wnd, g_gc, x, y, \
233                                     cx, cy, 0, 360*64); \
234                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
235                            if (g_ownbackstore) \
236                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
237                            break; \
238            } \
239    }
240    
241  /* colour maps */  /* colour maps */
242  BOOL g_owncolmap = False;  extern BOOL g_owncolmap;
243  static Colormap g_xcolmap;  static Colormap g_xcolmap;
244  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
245    
246  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : translate_colour(g_colmap[col]) )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
247  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
248  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
249    
# Line 138  static int rop2_map[] = { Line 269  static int rop2_map[] = {
269  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
270  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
271    
272  static void  static seamless_window *
273  mwm_hide_decorations(void)  sw_get_window_by_id(unsigned long id)
274  {  {
275          PropMotifWmHints motif_hints;          seamless_window *sw;
276          Atom hintsatom;          for (sw = g_seamless_windows; sw; sw = sw->next)
277            {
278                    if (sw->id == id)
279                            return sw;
280            }
281            return NULL;
282    }
283    
         /* setup the property */  
         motif_hints.flags = MWM_HINTS_DECORATIONS;  
         motif_hints.decorations = 0;  
284    
285          /* get the atom for the property */  static seamless_window *
286          hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);  sw_get_window_by_wnd(Window wnd)
287          if (!hintsatom)  {
288            seamless_window *sw;
289            for (sw = g_seamless_windows; sw; sw = sw->next)
290          {          {
291                  warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");                  if (sw->wnd == wnd)
292                  return;                          return sw;
293          }          }
294            return NULL;
295    }
296    
297          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,  
298                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);  static void
299    sw_remove_window(seamless_window * win)
300    {
301            seamless_window *sw, **prevnext = &g_seamless_windows;
302            for (sw = g_seamless_windows; sw; sw = sw->next)
303            {
304                    if (sw == win)
305                    {
306                            *prevnext = sw->next;
307                            xfree(sw);
308                            return;
309                    }
310                    prevnext = &sw->next;
311            }
312            return;
313  }  }
314    
315  static PixelColour  
316  split_colour15(uint32 colour)  /* Move all windows except wnd to new desktop */
317    static void
318    sw_all_to_desktop(Window wnd, unsigned int desktop)
319  {  {
320          PixelColour rv;          seamless_window *sw;
321          rv.red = (colour & 0x7c00) >> 10;          for (sw = g_seamless_windows; sw; sw = sw->next)
322          rv.red = (rv.red * 0xff) / 0x1f;          {
323          rv.green = (colour & 0x03e0) >> 5;                  if (sw->wnd == wnd)
324          rv.green = (rv.green * 0xff) / 0x1f;                          continue;
325          rv.blue = (colour & 0x1f);                  if (sw->desktop != desktop)
326          rv.blue = (rv.blue * 0xff) / 0x1f;                  {
327          return rv;                          ewmh_move_to_desktop(sw->wnd, desktop);
328  }                          sw->desktop = desktop;
329                    }
330  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;  
331  }  }
332    
333  static uint32  
334  make_colour16(PixelColour pc)  /* Send our position */
335    static void
336    sw_update_position(seamless_window * sw)
337  {  {
338          pc.red = (pc.red * 0x1f) / 0xff;          XWindowAttributes wa;
339          pc.green = (pc.green * 0x3f) / 0xff;          int x, y;
340          pc.blue = (pc.blue * 0x1f) / 0xff;          Window child_return;
341          return (pc.red << 11) | (pc.green << 5) | pc.blue;          unsigned int serial;
342    
343            XGetWindowAttributes(g_display, sw->wnd, &wa);
344            XTranslateCoordinates(g_display, sw->wnd, wa.root,
345                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
346    
347            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
348    
349            sw->outstanding_position = True;
350            sw->outpos_serial = serial;
351    
352            sw->outpos_xoffset = x;
353            sw->outpos_yoffset = y;
354            sw->outpos_width = wa.width;
355            sw->outpos_height = wa.height;
356  }  }
357    
358  static uint32  
359  make_colour24(PixelColour pc)  /* Check if it's time to send our position */
360    static void
361    sw_check_timers()
362  {  {
363          if (g_xserver_be)          seamless_window *sw;
364            struct timeval now;
365    
366            gettimeofday(&now, NULL);
367            for (sw = g_seamless_windows; sw; sw = sw->next)
368            {
369                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
370                    {
371                            timerclear(sw->position_timer);
372                            sw_update_position(sw);
373                    }
374            }
375    }
376    
377    
378    static void
379    sw_restack_window(seamless_window * sw, unsigned long behind)
380    {
381            seamless_window *sw_above;
382    
383            /* Remove window from stack */
384            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
385          {          {
386                  return pc.red | (pc.green << 8) | (pc.blue << 16);                  if (sw_above->behind == sw->id)
387                            break;
388          }          }
389          else  
390            if (sw_above)
391                    sw_above->behind = sw->behind;
392    
393            /* And then add it at the new position */
394    
395            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
396          {          {
397                  return (pc.red << 16) | (pc.green << 8) | pc.blue;                  if (sw_above->behind == behind)
398                            break;
399          }          }
400    
401            if (sw_above)
402                    sw_above->behind = sw->id;
403    
404            sw->behind = behind;
405  }  }
406    
407  static uint32  
408  make_colour32(PixelColour pc)  static void
409    sw_handle_restack(seamless_window * sw)
410  {  {
411          if (g_xserver_be)          Status status;
412            Window root, parent, *children;
413            unsigned int nchildren, i;
414            seamless_window *sw_below;
415    
416            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
417                                &root, &parent, &children, &nchildren);
418            if (!status || !nchildren)
419                    return;
420    
421            sw_below = NULL;
422    
423            i = 0;
424            while (children[i] != sw->wnd)
425            {
426                    i++;
427                    if (i >= nchildren)
428                            return;
429            }
430    
431            for (i++; i < nchildren; i++)
432          {          {
433                  return pc.red | (pc.green << 8) | (pc.blue << 16);                  sw_below = sw_get_window_by_wnd(children[i]);
434                    if (sw_below)
435                            break;
436            }
437    
438            if (!sw_below && !sw->behind)
439                    return;
440            if (sw_below && (sw_below->id == sw->behind))
441                    return;
442    
443            if (sw_below)
444            {
445                    seamless_send_zchange(sw->id, sw_below->id, 0);
446                    sw_restack_window(sw, sw_below->id);
447          }          }
448          else          else
449          {          {
450                  return (pc.red << 16) | (pc.green << 8) | pc.blue;                  seamless_send_zchange(sw->id, 0, 0);
451                    sw_restack_window(sw, 0);
452          }          }
453  }  }
454    
455    
456    static void
457    mwm_hide_decorations(Window wnd)
458    {
459            PropMotifWmHints motif_hints;
460            Atom hintsatom;
461    
462            /* setup the property */
463            motif_hints.flags = MWM_HINTS_DECORATIONS;
464            motif_hints.decorations = 0;
465    
466            /* get the atom for the property */
467            hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
468            if (!hintsatom)
469            {
470                    warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
471                    return;
472            }
473    
474            XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
475                            (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
476    
477    }
478    
479    #define SPLITCOLOUR15(colour, rv) \
480    { \
481            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
482            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
483            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
484    }
485    
486    #define SPLITCOLOUR16(colour, rv) \
487    { \
488            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
489            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
490            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
491    } \
492    
493    #define SPLITCOLOUR24(colour, rv) \
494    { \
495            rv.blue = (colour & 0xff0000) >> 16; \
496            rv.green = (colour & 0x00ff00) >> 8; \
497            rv.red = (colour & 0x0000ff); \
498    }
499    
500    #define MAKECOLOUR(pc) \
501            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
502                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
503                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
504    
505  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
506  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
507  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
508                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
509    
510    /* The following macros output the same octet sequences
511       on both BE and LE hosts: */
512    
513    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
514    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
515    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
516    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
517    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
518    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
519    
520  static uint32  static uint32
521  translate_colour(uint32 colour)  translate_colour(uint32 colour)
522  {  {
523          switch (g_server_bpp)          PixelColour pc;
524            switch (g_server_depth)
525          {          {
526                  case 15:                  case 15:
527                          switch (g_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;  
                         }  
528                          break;                          break;
529                  case 16:                  case 16:
530                          switch (g_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;  
                         }  
531                          break;                          break;
532                  case 24:                  case 24:
533                          switch (g_bpp)                          SPLITCOLOUR24(colour, pc);
534                          {                          break;
535                                  case 16:                  default:
536                                          colour = make_colour16(split_colour24(colour));                          /* Avoid warning */
537                                          break;                          pc.red = 0;
538                                  case 24:                          pc.green = 0;
539                                          break;                          pc.blue = 0;
                                 case 32:  
                                         colour = make_colour32(split_colour24(colour));  
                                         break;  
                         }  
540                          break;                          break;
541          }          }
542          return colour;          return MAKECOLOUR(pc);
543    }
544    
545    /* indent is confused by UNROLL8 */
546    /* *INDENT-OFF* */
547    
548    /* repeat and unroll, similar to bitmap.c */
549    /* potentialy any of the following translate */
550    /* functions can use repeat but just doing */
551    /* the most common ones */
552    
553    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
554    /* 2 byte output repeat */
555    #define REPEAT2(stm) \
556    { \
557            while (out <= end - 8 * 2) \
558                    UNROLL8(stm) \
559            while (out < end) \
560                    { stm } \
561    }
562    /* 3 byte output repeat */
563    #define REPEAT3(stm) \
564    { \
565            while (out <= end - 8 * 3) \
566                    UNROLL8(stm) \
567            while (out < end) \
568                    { stm } \
569    }
570    /* 4 byte output repeat */
571    #define REPEAT4(stm) \
572    { \
573            while (out <= end - 8 * 4) \
574                    UNROLL8(stm) \
575            while (out < end) \
576                    { stm } \
577  }  }
578    /* *INDENT-ON* */
579    
580  static void  static void
581  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
582  {  {
583          while (out < end)          while (out < end)
584                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
585  }  }
586    
587  static void  static void
588  translate8to16(uint8 * data, uint16 * out, uint16 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
589  {  {
590          while (out < end)          uint16 value;
591                  *(out++) = (uint16) g_colmap[*(data++)];  
592            if (g_compatible_arch)
593            {
594                    /* *INDENT-OFF* */
595                    REPEAT2
596                    (
597                            *((uint16 *) out) = g_colmap[*(data++)];
598                            out += 2;
599                    )
600                    /* *INDENT-ON* */
601            }
602            else if (g_xserver_be)
603            {
604                    while (out < end)
605                    {
606                            value = (uint16) g_colmap[*(data++)];
607                            BOUT16(out, value);
608                    }
609            }
610            else
611            {
612                    while (out < end)
613                    {
614                            value = (uint16) g_colmap[*(data++)];
615                            LOUT16(out, value);
616                    }
617            }
618  }  }
619    
620  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
621  static void  static void
622  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
623  {  {
624          uint32 value;          uint32 value;
625    
626          while (out < end)          if (g_compatible_arch)
627            {
628                    while (out < end)
629                    {
630                            value = g_colmap[*(data++)];
631                            BOUT24(out, value);
632                    }
633            }
634            else
635          {          {
636                  value = g_colmap[*(data++)];                  while (out < end)
637                  *(out++) = value;                  {
638                  *(out++) = value >> 8;                          value = g_colmap[*(data++)];
639                  *(out++) = value >> 16;                          LOUT24(out, value);
640                    }
641          }          }
642  }  }
643    
644  static void  static void
645  translate8to32(uint8 * data, uint32 * out, uint32 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
646  {  {
647          while (out < end)          uint32 value;
                 *(out++) = g_colmap[*(data++)];  
 }  
648    
649  /* todo the remaining translate function might need some big endian check ?? */          if (g_compatible_arch)
650            {
651                    /* *INDENT-OFF* */
652                    REPEAT4
653                    (
654                            *((uint32 *) out) = g_colmap[*(data++)];
655                            out += 4;
656                    )
657                    /* *INDENT-ON* */
658            }
659            else if (g_xserver_be)
660            {
661                    while (out < end)
662                    {
663                            value = g_colmap[*(data++)];
664                            BOUT32(out, value);
665                    }
666            }
667            else
668            {
669                    while (out < end)
670                    {
671                            value = g_colmap[*(data++)];
672                            LOUT32(out, value);
673                    }
674            }
675    }
676    
677  static void  static void
678  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
679  {  {
680          uint16 pixel;          uint16 pixel;
681          uint16 value;          uint16 value;
682            PixelColour pc;
683    
684          while (out < end)          if (g_xserver_be)
685          {          {
686                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                 BSWAP16(pixel)}  
   
                 value = make_colour16(split_colour15(pixel));  
   
                 if (g_xserver_be)  
687                  {                  {
688                          *(out++) = value >> 8;                          pixel = *(data++);
689                          *(out++) = value;                          if (g_host_be)
690                            {
691                                    BSWAP16(pixel);
692                            }
693                            SPLITCOLOUR15(pixel, pc);
694                            value = MAKECOLOUR(pc);
695                            BOUT16(out, value);
696                  }                  }
697                  else          }
698            else
699            {
700                    while (out < end)
701                  {                  {
702                          *(out++) = value;                          pixel = *(data++);
703                          *(out++) = value >> 8;                          if (g_host_be)
704                            {
705                                    BSWAP16(pixel);
706                            }
707                            SPLITCOLOUR15(pixel, pc);
708                            value = MAKECOLOUR(pc);
709                            LOUT16(out, value);
710                  }                  }
711          }          }
712  }  }
713    
714  static void  static void
715  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
716  {  {
717          uint32 value;          uint32 value;
718          uint16 pixel;          uint16 pixel;
719            PixelColour pc;
720    
721          while (out < end)          if (g_compatible_arch)
722          {          {
723                  pixel = *(data++);                  /* *INDENT-OFF* */
724                    REPEAT3
725                  if (g_host_be)                  (
726                  {                          pixel = *(data++);
727                  BSWAP16(pixel)}                          SPLITCOLOUR15(pixel, pc);
728                            *(out++) = pc.blue;
729                  value = make_colour24(split_colour15(pixel));                          *(out++) = pc.green;
730                  if (g_xserver_be)                          *(out++) = pc.red;
731                    )
732                    /* *INDENT-ON* */
733            }
734            else if (g_xserver_be)
735            {
736                    while (out < end)
737                  {                  {
738                          *(out++) = value >> 16;                          pixel = *(data++);
739                          *(out++) = value >> 8;                          if (g_host_be)
740                          *(out++) = value;                          {
741                                    BSWAP16(pixel);
742                            }
743                            SPLITCOLOUR15(pixel, pc);
744                            value = MAKECOLOUR(pc);
745                            BOUT24(out, value);
746                  }                  }
747                  else          }
748            else
749            {
750                    while (out < end)
751                  {                  {
752                          *(out++) = value;                          pixel = *(data++);
753                          *(out++) = value >> 8;                          if (g_host_be)
754                          *(out++) = value >> 16;                          {
755                                    BSWAP16(pixel);
756                            }
757                            SPLITCOLOUR15(pixel, pc);
758                            value = MAKECOLOUR(pc);
759                            LOUT24(out, value);
760                  }                  }
761          }          }
762  }  }
763    
764  static void  static void
765  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
766  {  {
767          uint16 pixel;          uint16 pixel;
768          uint32 value;          uint32 value;
769            PixelColour pc;
770    
771          while (out < end)          if (g_compatible_arch)
772          {          {
773                  pixel = *(data++);                  /* *INDENT-OFF* */
774                    REPEAT4
775                  if (g_host_be)                  (
776                  {                          pixel = *(data++);
777                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
778                  }                          *(out++) = pc.blue;
779                            *(out++) = pc.green;
780                  value = make_colour32(split_colour15(pixel));                          *(out++) = pc.red;
781                            *(out++) = 0;
782                  if (g_xserver_be)                  )
783                    /* *INDENT-ON* */
784            }
785            else if (g_xserver_be)
786            {
787                    while (out < end)
788                  {                  {
789                          *(out++) = value >> 24;                          pixel = *(data++);
790                          *(out++) = value >> 16;                          if (g_host_be)
791                          *(out++) = value >> 8;                          {
792                          *(out++) = value;                                  BSWAP16(pixel);
793                            }
794                            SPLITCOLOUR15(pixel, pc);
795                            value = MAKECOLOUR(pc);
796                            BOUT32(out, value);
797                  }                  }
798                  else          }
799            else
800            {
801                    while (out < end)
802                  {                  {
803                          *(out++) = value;                          pixel = *(data++);
804                          *(out++) = value >> 8;                          if (g_host_be)
805                          *(out++) = value >> 16;                          {
806                          *(out++) = value >> 24;                                  BSWAP16(pixel);
807                            }
808                            SPLITCOLOUR15(pixel, pc);
809                            value = MAKECOLOUR(pc);
810                            LOUT32(out, value);
811                  }                  }
812          }          }
813  }  }
814    
815  static void  static void
816  translate16to16(uint16 * data, uint16 * out, uint16 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
817  {  {
818            uint16 pixel;
819          uint16 value;          uint16 value;
820            PixelColour pc;
821    
822          if (g_xserver_be)          if (g_xserver_be)
823          {          {
824                  while (out < end)                  if (g_host_be)
825                  {                  {
826                          value = *data;                          while (out < end)
827                          BSWAP16(value);                          {
828                          *out = value;                                  pixel = *(data++);
829                          data++;                                  BSWAP16(pixel);
830                          out++;                                  SPLITCOLOUR16(pixel, pc);
831                                    value = MAKECOLOUR(pc);
832                                    BOUT16(out, value);
833                            }
834                    }
835                    else
836                    {
837                            while (out < end)
838                            {
839                                    pixel = *(data++);
840                                    SPLITCOLOUR16(pixel, pc);
841                                    value = MAKECOLOUR(pc);
842                                    BOUT16(out, value);
843                            }
844                  }                  }
   
845          }          }
846          else          else
847          {          {
848                  while (out < end)                  if (g_host_be)
849                  {                  {
850                          *out = *data;                          while (out < end)
851                          out++;                          {
852                          data++;                                  pixel = *(data++);
853                                    BSWAP16(pixel);
854                                    SPLITCOLOUR16(pixel, pc);
855                                    value = MAKECOLOUR(pc);
856                                    LOUT16(out, value);
857                            }
858                    }
859                    else
860                    {
861                            while (out < end)
862                            {
863                                    pixel = *(data++);
864                                    SPLITCOLOUR16(pixel, pc);
865                                    value = MAKECOLOUR(pc);
866                                    LOUT16(out, value);
867                            }
868                  }                  }
869          }          }
870  }  }
871    
   
872  static void  static void
873  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
874  {  {
875          uint32 value;          uint32 value;
876          uint16 pixel;          uint16 pixel;
877            PixelColour pc;
878    
879          while (out < end)          if (g_compatible_arch)
880            {
881                    /* *INDENT-OFF* */
882                    REPEAT3
883                    (
884                            pixel = *(data++);
885                            SPLITCOLOUR16(pixel, pc);
886                            *(out++) = pc.blue;
887                            *(out++) = pc.green;
888                            *(out++) = pc.red;
889                    )
890                    /* *INDENT-ON* */
891            }
892            else if (g_xserver_be)
893          {          {
                 pixel = *(data++);  
   
894                  if (g_host_be)                  if (g_host_be)
895                  {                  {
896                  BSWAP16(pixel)}                          while (out < end)
897                            {
898                  value = make_colour24(split_colour16(pixel));                                  pixel = *(data++);
899                                    BSWAP16(pixel);
900                  if (g_xserver_be)                                  SPLITCOLOUR16(pixel, pc);
901                                    value = MAKECOLOUR(pc);
902                                    BOUT24(out, value);
903                            }
904                    }
905                    else
906                  {                  {
907                          *(out++) = value >> 16;                          while (out < end)
908                          *(out++) = value >> 8;                          {
909                          *(out++) = value;                                  pixel = *(data++);
910                                    SPLITCOLOUR16(pixel, pc);
911                                    value = MAKECOLOUR(pc);
912                                    BOUT24(out, value);
913                            }
914                    }
915            }
916            else
917            {
918                    if (g_host_be)
919                    {
920                            while (out < end)
921                            {
922                                    pixel = *(data++);
923                                    BSWAP16(pixel);
924                                    SPLITCOLOUR16(pixel, pc);
925                                    value = MAKECOLOUR(pc);
926                                    LOUT24(out, value);
927                            }
928                  }                  }
929                  else                  else
930                  {                  {
931                          *(out++) = value;                          while (out < end)
932                          *(out++) = value >> 8;                          {
933                          *(out++) = value >> 16;                                  pixel = *(data++);
934                                    SPLITCOLOUR16(pixel, pc);
935                                    value = MAKECOLOUR(pc);
936                                    LOUT24(out, value);
937                            }
938                  }                  }
939          }          }
940  }  }
941    
942  static void  static void
943  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
944  {  {
945          uint16 pixel;          uint16 pixel;
946          uint32 value;          uint32 value;
947            PixelColour pc;
948    
949          while (out < end)          if (g_compatible_arch)
950            {
951                    /* *INDENT-OFF* */
952                    REPEAT4
953                    (
954                            pixel = *(data++);
955                            SPLITCOLOUR16(pixel, pc);
956                            *(out++) = pc.blue;
957                            *(out++) = pc.green;
958                            *(out++) = pc.red;
959                            *(out++) = 0;
960                    )
961                    /* *INDENT-ON* */
962            }
963            else if (g_xserver_be)
964          {          {
                 pixel = *(data++);  
   
965                  if (g_host_be)                  if (g_host_be)
966                  {                  {
967                  BSWAP16(pixel)}                          while (out < end)
968                            {
969                  value = make_colour32(split_colour16(pixel));                                  pixel = *(data++);
970                                    BSWAP16(pixel);
971                  if (g_xserver_be)                                  SPLITCOLOUR16(pixel, pc);
972                                    value = MAKECOLOUR(pc);
973                                    BOUT32(out, value);
974                            }
975                    }
976                    else
977                    {
978                            while (out < end)
979                            {
980                                    pixel = *(data++);
981                                    SPLITCOLOUR16(pixel, pc);
982                                    value = MAKECOLOUR(pc);
983                                    BOUT32(out, value);
984                            }
985                    }
986            }
987            else
988            {
989                    if (g_host_be)
990                  {                  {
991                          *(out++) = value >> 24;                          while (out < end)
992                          *(out++) = value >> 16;                          {
993                          *(out++) = value >> 8;                                  pixel = *(data++);
994                          *(out++) = value;                                  BSWAP16(pixel);
995                                    SPLITCOLOUR16(pixel, pc);
996                                    value = MAKECOLOUR(pc);
997                                    LOUT32(out, value);
998                            }
999                  }                  }
1000                  else                  else
1001                  {                  {
1002                          *(out++) = value;                          while (out < end)
1003                          *(out++) = value >> 8;                          {
1004                          *(out++) = value >> 16;                                  pixel = *(data++);
1005                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
1006                                    value = MAKECOLOUR(pc);
1007                                    LOUT32(out, value);
1008                            }
1009                  }                  }
1010          }          }
1011  }  }
1012    
1013  static void  static void
1014  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1015  {  {
1016          uint32 pixel = 0;          uint32 pixel = 0;
1017          uint16 value;          uint16 value;
1018            PixelColour pc;
1019    
1020          while (out < end)          while (out < end)
1021          {          {
1022                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1023                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1024                  pixel |= *(data++);                  pixel |= *(data++);
1025                    SPLITCOLOUR24(pixel, pc);
1026                  value = (uint16) make_colour16(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1027                  if (g_xserver_be)                  if (g_xserver_be)
1028                  {                  {
1029                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1030                  }                  }
1031                  else                  else
1032                  {                  {
1033                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1034                  }                  }
1035          }          }
1036  }  }
1037    
1038  static void  static void
1039  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1040  {  {
1041          while (out < end)          uint32 pixel;
1042            uint32 value;
1043            PixelColour pc;
1044    
1045            if (g_xserver_be)
1046          {          {
1047                  *(out++) = (*(data++));                  while (out < end)
1048                    {
1049                            pixel = *(data++) << 16;
1050                            pixel |= *(data++) << 8;
1051                            pixel |= *(data++);
1052                            SPLITCOLOUR24(pixel, pc);
1053                            value = MAKECOLOUR(pc);
1054                            BOUT24(out, value);
1055                    }
1056            }
1057            else
1058            {
1059                    while (out < end)
1060                    {
1061                            pixel = *(data++) << 16;
1062                            pixel |= *(data++) << 8;
1063                            pixel |= *(data++);
1064                            SPLITCOLOUR24(pixel, pc);
1065                            value = MAKECOLOUR(pc);
1066                            LOUT24(out, value);
1067                    }
1068          }          }
1069  }  }
1070    
1071  static void  static void
1072  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1073  {  {
1074          while (out < end)          uint32 pixel;
1075            uint32 value;
1076            PixelColour pc;
1077    
1078            if (g_compatible_arch)
1079          {          {
1080                  if (g_xserver_be)                  /* *INDENT-OFF* */
1081                  {  #ifdef NEED_ALIGN
1082                          *(out++) = 0x00;                  REPEAT4
1083                    (
1084                          *(out++) = *(data++);                          *(out++) = *(data++);
1085                          *(out++) = *(data++);                          *(out++) = *(data++);
1086                          *(out++) = *(data++);                          *(out++) = *(data++);
1087                            *(out++) = 0;
1088                    )
1089    #else
1090                    REPEAT4
1091                    (
1092                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1093                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1094                     out += 4;
1095                     data += 3;
1096                    )
1097    #endif
1098                    /* *INDENT-ON* */
1099            }
1100            else if (g_xserver_be)
1101            {
1102                    while (out < end)
1103                    {
1104                            pixel = *(data++) << 16;
1105                            pixel |= *(data++) << 8;
1106                            pixel |= *(data++);
1107                            SPLITCOLOUR24(pixel, pc);
1108                            value = MAKECOLOUR(pc);
1109                            BOUT32(out, value);
1110                  }                  }
1111                  else          }
1112            else
1113            {
1114                    while (out < end)
1115                  {                  {
1116                          *(out++) = *(data++);                          pixel = *(data++) << 16;
1117                          *(out++) = *(data++);                          pixel |= *(data++) << 8;
1118                          *(out++) = *(data++);                          pixel |= *(data++);
1119                          *(out++) = 0x00;                          SPLITCOLOUR24(pixel, pc);
1120                            value = MAKECOLOUR(pc);
1121                            LOUT32(out, value);
1122                  }                  }
1123          }          }
1124  }  }
# Line 569  translate24to32(uint8 * data, uint8 * ou Line 1126  translate24to32(uint8 * data, uint8 * ou
1126  static uint8 *  static uint8 *
1127  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1128  {  {
1129          int size = width * height * g_bpp / 8;          int size;
1130          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1131          uint8 *end = out + size;          uint8 *end;
1132    
1133          switch (g_server_bpp)          /*
1134               If RDP depth and X Visual depths match,
1135               and arch(endian) matches, no need to translate:
1136               just return data.
1137               Note: select_visual should've already ensured g_no_translate
1138               is only set for compatible depths, but the RDP depth might've
1139               changed during connection negotiations.
1140             */
1141            if (g_no_translate_image)
1142            {
1143                    if ((g_depth == 15 && g_server_depth == 15) ||
1144                        (g_depth == 16 && g_server_depth == 16) ||
1145                        (g_depth == 24 && g_server_depth == 24))
1146                            return data;
1147            }
1148    
1149            size = width * height * (g_bpp / 8);
1150            out = (uint8 *) xmalloc(size);
1151            end = out + size;
1152    
1153            switch (g_server_depth)
1154          {          {
1155                  case 24:                  case 24:
1156                          switch (g_bpp)                          switch (g_bpp)
# Line 599  translate_image(int width, int height, u Line 1176  translate_image(int width, int height, u
1176                                          translate16to24((uint16 *) data, out, end);                                          translate16to24((uint16 *) data, out, end);
1177                                          break;                                          break;
1178                                  case 16:                                  case 16:
1179                                          translate16to16((uint16 *) data, (uint16 *) out,                                          translate16to16((uint16 *) data, out, end);
                                                         (uint16 *) end);  
1180                                          break;                                          break;
1181                          }                          }
1182                          break;                          break;
# Line 625  translate_image(int width, int height, u Line 1201  translate_image(int width, int height, u
1201                                          translate8to8(data, out, end);                                          translate8to8(data, out, end);
1202                                          break;                                          break;
1203                                  case 16:                                  case 16:
1204                                          translate8to16(data, (uint16 *) out, (uint16 *) end);                                          translate8to16(data, out, end);
1205                                          break;                                          break;
1206                                  case 24:                                  case 24:
1207                                          translate8to24(data, out, end);                                          translate8to24(data, out, end);
1208                                          break;                                          break;
1209                                  case 32:                                  case 32:
1210                                          translate8to32(data, (uint32 *) out, (uint32 *) end);                                          translate8to32(data, out, end);
1211                                          break;                                          break;
1212                          }                          }
1213                          break;                          break;
# Line 664  get_key_state(unsigned int state, uint32 Line 1240  get_key_state(unsigned int state, uint32
1240          return (state & keysymMask) ? True : False;          return (state & keysymMask) ? True : False;
1241  }  }
1242    
1243  BOOL  static void
1244  ui_init(void)  calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1245    {
1246            *shift_l = ffs(mask) - 1;
1247            mask >>= *shift_l;
1248            *shift_r = 8 - ffs(mask & ~(mask >> 1));
1249    }
1250    
1251    /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1252       calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1253     */
1254    static unsigned
1255    calculate_mask_weight(uint32 mask)
1256    {
1257            unsigned weight = 0;
1258            do
1259            {
1260                    weight += (mask & 1);
1261            }
1262            while (mask >>= 1);
1263            return weight;
1264    }
1265    
1266    static BOOL
1267    select_visual()
1268  {  {
1269          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1270          uint16 test;          int pixmap_formats_count, visuals_count;
1271            XVisualInfo *vmatches = NULL;
1272            XVisualInfo template;
1273          int i;          int i;
1274            unsigned red_weight, blue_weight, green_weight;
1275    
1276          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1277          if (g_display == NULL)  
1278            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1279            if (pfm == NULL)
1280          {          {
1281                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1282                    XCloseDisplay(g_display);
1283                  return False;                  return False;
1284          }          }
1285    
1286          g_x_socket = ConnectionNumber(g_display);          /* Search for best TrueColor visual */
1287          g_screen = DefaultScreenOfDisplay(g_display);          template.class = TrueColor;
1288          g_visual = DefaultVisualOfScreen(g_screen);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1289          g_depth = DefaultDepthOfScreen(g_screen);          g_visual = NULL;
1290            g_no_translate_image = False;
1291            g_compatible_arch = False;
1292            if (vmatches != NULL)
1293            {
1294                    for (i = 0; i < visuals_count; ++i)
1295                    {
1296                            XVisualInfo *visual_info = &vmatches[i];
1297    
1298                            /* Try to find a no-translation visual that'll
1299                               allow us to use RDP bitmaps directly as ZPixmaps. */
1300                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1301                                                   /* R5G5B5 */
1302                                                   (visual_info->red_mask == 0x7c00) &&
1303                                                   (visual_info->green_mask == 0x3e0) &&
1304                                                   (visual_info->blue_mask == 0x1f)) ||
1305                                                  ((visual_info->depth == 16) &&
1306                                                   /* R5G6B5 */
1307                                                   (visual_info->red_mask == 0xf800) &&
1308                                                   (visual_info->green_mask == 0x7e0) &&
1309                                                   (visual_info->blue_mask == 0x1f)) ||
1310                                                  ((visual_info->depth == 24) &&
1311                                                   /* R8G8B8 */
1312                                                   (visual_info->red_mask == 0xff0000) &&
1313                                                   (visual_info->green_mask == 0xff00) &&
1314                                                   (visual_info->blue_mask == 0xff))))
1315                            {
1316                                    g_visual = visual_info->visual;
1317                                    g_depth = visual_info->depth;
1318                                    g_compatible_arch = !g_host_be;
1319                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1320                                    if (g_no_translate_image)
1321                                            /* We found the best visual */
1322                                            break;
1323                            }
1324                            else
1325                            {
1326                                    g_compatible_arch = False;
1327                            }
1328    
1329                            if (visual_info->depth > 24)
1330                            {
1331                                    /* Avoid 32-bit visuals and likes like the plague.
1332                                       They're either untested or proven to work bad
1333                                       (e.g. nvidia's Composite 32-bit visual).
1334                                       Most implementation offer a 24-bit visual anyway. */
1335                                    continue;
1336                            }
1337    
1338          pfm = XListPixmapFormats(g_display, &i);                          /* Only care for visuals, for whose BPPs (not depths!)
1339          if (pfm != NULL)                             we have a translateXtoY function. */
1340                            BOOL can_translate_to_bpp = False;
1341                            int j;
1342                            for (j = 0; j < pixmap_formats_count; ++j)
1343                            {
1344                                    if (pfm[j].depth == visual_info->depth)
1345                                    {
1346                                            if ((pfm[j].bits_per_pixel == 16) ||
1347                                                (pfm[j].bits_per_pixel == 24) ||
1348                                                (pfm[j].bits_per_pixel == 32))
1349                                            {
1350                                                    can_translate_to_bpp = True;
1351                                            }
1352                                            break;
1353                                    }
1354                            }
1355    
1356                            /* Prefer formats which have the most colour depth.
1357                               We're being truly aristocratic here, minding each
1358                               weight on its own. */
1359                            if (can_translate_to_bpp)
1360                            {
1361                                    unsigned vis_red_weight =
1362                                            calculate_mask_weight(visual_info->red_mask);
1363                                    unsigned vis_green_weight =
1364                                            calculate_mask_weight(visual_info->green_mask);
1365                                    unsigned vis_blue_weight =
1366                                            calculate_mask_weight(visual_info->blue_mask);
1367                                    if ((vis_red_weight >= red_weight)
1368                                        && (vis_green_weight >= green_weight)
1369                                        && (vis_blue_weight >= blue_weight))
1370                                    {
1371                                            red_weight = vis_red_weight;
1372                                            green_weight = vis_green_weight;
1373                                            blue_weight = vis_blue_weight;
1374                                            g_visual = visual_info->visual;
1375                                            g_depth = visual_info->depth;
1376                                    }
1377                            }
1378                    }
1379                    XFree(vmatches);
1380            }
1381    
1382            if (g_visual != NULL)
1383          {          {
1384                  /* Use maximum bpp for this depth - this is generally                  g_owncolmap = False;
1385                     desirable, e.g. 24 bits->32 bits. */                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1386                  while (i--)                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1387                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1388            }
1389            else
1390            {
1391                    template.class = PseudoColor;
1392                    template.depth = 8;
1393                    template.colormap_size = 256;
1394                    vmatches =
1395                            XGetVisualInfo(g_display,
1396                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1397                                           &template, &visuals_count);
1398                    if (vmatches == NULL)
1399                  {                  {
1400                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          error("No usable TrueColor or PseudoColor visuals on this display.\n");
1401                            XCloseDisplay(g_display);
1402                            XFree(pfm);
1403                            return False;
1404                    }
1405    
1406                    /* we use a colourmap, so the default visual should do */
1407                    g_owncolmap = True;
1408                    g_visual = vmatches[0].visual;
1409                    g_depth = vmatches[0].depth;
1410            }
1411    
1412            g_bpp = 0;
1413            for (i = 0; i < pixmap_formats_count; ++i)
1414            {
1415                    XPixmapFormatValues *pf = &pfm[i];
1416                    if (pf->depth == g_depth)
1417                    {
1418                            g_bpp = pf->bits_per_pixel;
1419    
1420                            if (g_no_translate_image)
1421                          {                          {
1422                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1423                                    {
1424                                            case 15:
1425                                            case 16:
1426                                                    if (g_bpp != 16)
1427                                                            g_no_translate_image = False;
1428                                                    break;
1429                                            case 24:
1430                                                    /* Yes, this will force image translation
1431                                                       on most modern servers which use 32 bits
1432                                                       for R8G8B8. */
1433                                                    if (g_bpp != 24)
1434                                                            g_no_translate_image = False;
1435                                                    break;
1436                                            default:
1437                                                    g_no_translate_image = False;
1438                                                    break;
1439                                    }
1440                          }                          }
1441    
1442                            /* Pixmap formats list is a depth-to-bpp mapping --
1443                               there's just a single entry for every depth,
1444                               so we can safely break here */
1445                            break;
1446                  }                  }
1447                  XFree(pfm);          }
1448            XFree(pfm);
1449            pfm = NULL;
1450            return True;
1451    }
1452    
1453    BOOL
1454    ui_init(void)
1455    {
1456            int screen_num;
1457    
1458            g_display = XOpenDisplay(NULL);
1459            if (g_display == NULL)
1460            {
1461                    error("Failed to open display: %s\n", XDisplayName(NULL));
1462                    return False;
1463          }          }
1464    
         if (g_bpp < 8)  
1465          {          {
1466                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1467                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1468            }
1469    
1470            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1471            screen_num = DefaultScreen(g_display);
1472            g_x_socket = ConnectionNumber(g_display);
1473            g_screen = ScreenOfDisplay(g_display, screen_num);
1474            g_depth = DefaultDepthOfScreen(g_screen);
1475    
1476            if (!select_visual())
1477                  return False;                  return False;
1478    
1479            if (g_no_translate_image)
1480            {
1481                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1482          }          }
1483    
1484          /* private colour map code only works for 8 bpp */          if (g_server_depth > g_bpp)
1485          if (g_owncolmap && (g_bpp > 8))          {
1486                  g_owncolmap = False;                  warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1487                            g_server_depth, g_bpp);
1488            }
1489    
1490            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1491                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1492    
1493          if (!g_owncolmap)          if (!g_owncolmap)
1494          {          {
1495                  g_xcolmap = DefaultColormapOfScreen(g_screen);                  g_xcolmap =
1496                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1497                                            AllocNone);
1498                  if (g_depth <= 8)                  if (g_depth <= 8)
1499                          warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");                          warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1500          }          }
1501    
1502          g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1503            {
1504          if (DoesBackingStore(g_screen) != Always)                  warning("External BackingStore not available. Using internal.\n");
1505                  g_ownbackstore = True;                  g_ownbackstore = True;
1506            }
         test = 1;  
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
1507    
1508          /*          /*
1509           * Determine desktop size           * Determine desktop size
1510           */           */
1511          if (g_width < 0)          if (g_fullscreen)
1512            {
1513                    g_width = WidthOfScreen(g_screen);
1514                    g_height = HeightOfScreen(g_screen);
1515                    g_using_full_workarea = True;
1516            }
1517            else if (g_width < 0)
1518          {          {
1519                  /* Percent of screen */                  /* Percent of screen */
1520                    if (-g_width >= 100)
1521                            g_using_full_workarea = True;
1522                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1523                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1524          }          }
# Line 738  ui_init(void) Line 1526  ui_init(void)
1526          {          {
1527                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1528                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1529                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1530                  {                  {
1531                          g_width = cx;                          g_width = cx;
1532                          g_height = cy;                          g_height = cy;
1533                            g_using_full_workarea = True;
1534                  }                  }
1535                  else                  else
1536                  {                  {
1537                          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");
1538                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1539                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1540                  }                  }
1541          }          }
         else if (g_fullscreen)  
         {  
                 g_width = WidthOfScreen(g_screen);  
                 g_height = HeightOfScreen(g_screen);  
         }  
1542    
1543          /* make sure width is a multiple of 4 */          /* make sure width is a multiple of 4 */
1544          g_width = (g_width + 3) & ~3;          g_width = (g_width + 3) & ~3;
1545    
         if (g_ownbackstore)  
         {  
                 g_backstore =  
                         XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,  
                                       g_depth);  
   
                 /* clear to prevent rubbish being exposed at startup */  
                 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));  
                 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);  
         }  
   
1546          g_mod_map = XGetModifierMapping(g_display);          g_mod_map = XGetModifierMapping(g_display);
1547    
1548          xkeymap_init();          xkeymap_init();
# Line 779  ui_init(void) Line 1551  ui_init(void)
1551                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1552    
1553          xclip_init();          xclip_init();
1554            ewmh_init();
1555            if (g_seamless_rdp)
1556                    seamless_init();
1557    
1558          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));          DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1559    
1560          return True;          return True;
1561  }  }
# Line 791  ui_deinit(void) Line 1566  ui_deinit(void)
1566          if (g_IM != NULL)          if (g_IM != NULL)
1567                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1568    
1569            if (g_null_cursor != NULL)
1570                    ui_destroy_cursor(g_null_cursor);
1571    
1572          XFreeModifiermap(g_mod_map);          XFreeModifiermap(g_mod_map);
1573    
1574          if (g_ownbackstore)          if (g_ownbackstore)
# Line 801  ui_deinit(void) Line 1579  ui_deinit(void)
1579          g_display = NULL;          g_display = NULL;
1580  }  }
1581    
1582  #define NULL_POINTER_MASK       "\x80"  
1583  #define NULL_POINTER_DATA       "\x0\x0\x0"  static void
1584            get_window_attribs(XSetWindowAttributes * attribs)
1585    {
1586            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1587            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1588            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1589            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1590            attribs->override_redirect = g_fullscreen;
1591            attribs->colormap = g_xcolmap;
1592    }
1593    
1594    static void
1595    get_input_mask(long *input_mask)
1596    {
1597            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1598                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1599    
1600            if (g_sendmotion)
1601                    *input_mask |= PointerMotionMask;
1602            if (g_ownbackstore)
1603                    *input_mask |= ExposureMask;
1604            if (g_fullscreen || g_grab_keyboard)
1605                    *input_mask |= EnterWindowMask;
1606            if (g_grab_keyboard)
1607                    *input_mask |= LeaveWindowMask;
1608    }
1609    
1610  BOOL  BOOL
1611  ui_create_window(void)  ui_create_window(void)
1612  {  {
1613            uint8 null_pointer_mask[1] = { 0x80 };
1614            uint8 null_pointer_data[24] = { 0x00 };
1615    
1616          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1617          XClassHint *classhints;          XClassHint *classhints;
1618          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 817  ui_create_window(void) Line 1623  ui_create_window(void)
1623          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1624          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1625    
1626          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1627          attribs.backing_store = g_ownbackstore ? NotUseful : Always;          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1628          attribs.override_redirect = g_fullscreen;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1629            if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1630          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1631                                0, CopyFromParent, InputOutput, CopyFromParent,  
1632                                CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);          get_window_attribs(&attribs);
1633    
1634            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1635                                  wndheight, 0, g_depth, InputOutput, g_visual,
1636                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1637                                  CWBorderPixel, &attribs);
1638    
1639            if (g_gc == NULL)
1640            {
1641                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1642                    ui_reset_clip();
1643            }
1644    
1645            if (g_create_bitmap_gc == NULL)
1646                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1647    
1648            if ((g_ownbackstore) && (g_backstore == 0))
1649            {
1650                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1651    
1652                    /* clear to prevent rubbish being exposed at startup */
1653                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1654                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1655            }
1656    
1657          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1658    
1659          if (g_hide_decorations)          if (g_hide_decorations)
1660                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1661    
1662          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1663          if (classhints != NULL)          if (classhints != NULL)
# Line 842  ui_create_window(void) Line 1671  ui_create_window(void)
1671          if (sizehints)          if (sizehints)
1672          {          {
1673                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1674                    if (g_pos)
1675                            sizehints->flags |= PPosition;
1676                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1677                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1678                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1679                  XFree(sizehints);                  XFree(sizehints);
1680          }          }
1681    
1682          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          if (g_embed_wnd)
1683                  VisibilityChangeMask | FocusChangeMask;          {
1684                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1685            }
1686    
1687          if (g_sendmotion)          get_input_mask(&input_mask);
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
1688    
1689          if (g_IM != NULL)          if (g_IM != NULL)
1690          {          {
# Line 871  ui_create_window(void) Line 1697  ui_create_window(void)
1697          }          }
1698    
1699          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1700    
1701            XMapWindow(g_display, g_wnd);
1702          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1703          do          do
1704          {          {
1705                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1706          }          }
1707          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1708            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1709    
1710          g_focused = False;          g_focused = False;
1711          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 889  ui_create_window(void) Line 1716  ui_create_window(void)
1716          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);          XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1717    
1718          /* create invisible 1x1 cursor to be used as null cursor */          /* create invisible 1x1 cursor to be used as null cursor */
1719          g_null_cursor = ui_create_cursor(0, 0, 1, 1, NULL_POINTER_MASK, NULL_POINTER_DATA);          if (g_null_cursor == NULL)
1720                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1721    
1722          return True;          return True;
1723  }  }
1724    
1725  void  void
1726    ui_resize_window()
1727    {
1728            XSizeHints *sizehints;
1729            Pixmap bs;
1730    
1731            sizehints = XAllocSizeHints();
1732            if (sizehints)
1733            {
1734                    sizehints->flags = PMinSize | PMaxSize;
1735                    sizehints->min_width = sizehints->max_width = g_width;
1736                    sizehints->min_height = sizehints->max_height = g_height;
1737                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1738                    XFree(sizehints);
1739            }
1740    
1741            if (!(g_fullscreen || g_embed_wnd))
1742            {
1743                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1744            }
1745    
1746            /* create new backstore pixmap */
1747            if (g_backstore != 0)
1748            {
1749                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1750                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1751                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1752                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1753                    XFreePixmap(g_display, g_backstore);
1754                    g_backstore = bs;
1755            }
1756    }
1757    
1758    void
1759  ui_destroy_window(void)  ui_destroy_window(void)
1760  {  {
         ui_destroy_cursor(g_null_cursor);  
           
1761          if (g_IC != NULL)          if (g_IC != NULL)
1762                  XDestroyIC(g_IC);                  XDestroyIC(g_IC);
1763    
# Line 910  xwin_toggle_fullscreen(void) Line 1769  xwin_toggle_fullscreen(void)
1769  {  {
1770          Pixmap contents = 0;          Pixmap contents = 0;
1771    
1772            if (g_seamless_active)
1773                    /* Turn off SeamlessRDP mode */
1774                    ui_seamless_toggle();
1775    
1776          if (!g_ownbackstore)          if (!g_ownbackstore)
1777          {          {
1778                  /* need to save contents of window */                  /* need to save contents of window */
# Line 930  xwin_toggle_fullscreen(void) Line 1793  xwin_toggle_fullscreen(void)
1793          }          }
1794  }  }
1795    
1796  /* Process all events in Xlib queue  static void
1797    handle_button_event(XEvent xevent, BOOL down)
1798    {
1799            uint16 button, flags = 0;
1800            g_last_gesturetime = xevent.xbutton.time;
1801            button = xkeymap_translate_button(xevent.xbutton.button);
1802            if (button == 0)
1803                    return;
1804    
1805            if (down)
1806                    flags = MOUSE_FLAG_DOWN;
1807    
1808            /* Stop moving window when button is released, regardless of cursor position */
1809            if (g_moving_wnd && (xevent.type == ButtonRelease))
1810                    g_moving_wnd = False;
1811    
1812            /* If win_button_size is nonzero, enable single app mode */
1813            if (xevent.xbutton.y < g_win_button_size)
1814            {
1815                    /*  Check from right to left: */
1816                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1817                    {
1818                            /* The close button, continue */
1819                            ;
1820                    }
1821                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1822                    {
1823                            /* The maximize/restore button. Do not send to
1824                               server.  It might be a good idea to change the
1825                               cursor or give some other visible indication
1826                               that rdesktop inhibited this click */
1827                            if (xevent.type == ButtonPress)
1828                                    return;
1829                    }
1830                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1831                    {
1832                            /* The minimize button. Iconify window. */
1833                            if (xevent.type == ButtonRelease)
1834                            {
1835                                    /* Release the mouse button outside the minimize button, to prevent the
1836                                       actual minimazation to happen */
1837                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1838                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1839                                    return;
1840                            }
1841                    }
1842                    else if (xevent.xbutton.x <= g_win_button_size)
1843                    {
1844                            /* The system menu. Ignore. */
1845                            if (xevent.type == ButtonPress)
1846                                    return;
1847                    }
1848                    else
1849                    {
1850                            /* The title bar. */
1851                            if (xevent.type == ButtonPress)
1852                            {
1853                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1854                                    {
1855                                            g_moving_wnd = True;
1856                                            g_move_x_offset = xevent.xbutton.x;
1857                                            g_move_y_offset = xevent.xbutton.y;
1858                                    }
1859                                    return;
1860                            }
1861                    }
1862            }
1863    
1864            if (xevent.xmotion.window == g_wnd)
1865            {
1866                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1867                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1868            }
1869            else
1870            {
1871                    /* SeamlessRDP */
1872                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1873                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1874            }
1875    }
1876    
1877    
1878    /* Process events in Xlib queue
1879     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1880  static int  static int
1881  xwin_process_events(void)  xwin_process_events(void)
1882  {  {
1883          XEvent xevent;          XEvent xevent;
1884          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1885          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1886          char str[256];          char str[256];
1887          Status status;          Status status;
1888          unsigned int state;          int events = 0;
1889          Window wdummy;          seamless_window *sw;
         int dummy;  
1890    
1891          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1892          {          {
1893                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1894    
# Line 956  xwin_process_events(void) Line 1898  xwin_process_events(void)
1898                          continue;                          continue;
1899                  }                  }
1900    
                 flags = 0;  
   
1901                  switch (xevent.type)                  switch (xevent.type)
1902                  {                  {
1903                            case VisibilityNotify:
1904                                    if (xevent.xvisibility.window == g_wnd)
1905                                            g_Unobscured =
1906                                                    xevent.xvisibility.state == VisibilityUnobscured;
1907    
1908                                    break;
1909                          case ClientMessage:                          case ClientMessage:
1910                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
1911                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 991  xwin_process_events(void) Line 1937  xwin_process_events(void)
1937                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1938                                  }                                  }
1939    
1940                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1941                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1942    
1943                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1944                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1945                                          break;                                          break;
1946    
1947                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1948                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, True, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 save_remote_modifiers(tr.scancode);  
                                 ensure_remote_modifiers(ev_time, tr);  
                                 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);  
                                 restore_remote_modifiers(ev_time, tr.scancode);  
   
1949                                  break;                                  break;
1950    
1951                          case KeyRelease:                          case KeyRelease:
# Line 1016  xwin_process_events(void) Line 1953  xwin_process_events(void)
1953                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1954                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1955    
1956                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1957                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1958    
1959                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1960                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1961                                          break;                                          break;
1962    
1963                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1964                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1965                                  break;                                  break;
1966    
1967                          case ButtonPress:                          case ButtonPress:
1968                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1969                                  /* fall through */                                  break;
1970    
1971                          case ButtonRelease:                          case ButtonRelease:
1972                                  g_last_gesturetime = xevent.xbutton.time;                                  handle_button_event(xevent, False);
                                 button = xkeymap_translate_button(xevent.xbutton.button);  
                                 if (button == 0)  
                                         break;  
   
                                 /* If win_button_size is nonzero, enable single app mode */  
                                 if (xevent.xbutton.y < g_win_button_size)  
                                 {  
                                         /* Stop moving window when button is released, regardless of cursor position */  
                                         if (g_moving_wnd && (xevent.type == ButtonRelease))  
                                                 g_moving_wnd = False;  
   
                                         /*  Check from right to left: */  
   
                                         if (xevent.xbutton.x >= g_width - g_win_button_size)  
                                         {  
                                                 /* The close button, continue */  
                                                 ;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 2)  
                                         {  
                                                 /* The maximize/restore button. Do not send to  
                                                    server.  It might be a good idea to change the  
                                                    cursor or give some other visible indication  
                                                    that rdesktop inhibited this click */  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x >=  
                                                  g_width - g_win_button_size * 3)  
                                         {  
                                                 /* The minimize button. Iconify window. */  
                                                 XIconifyWindow(g_display, g_wnd,  
                                                                DefaultScreen(g_display));  
                                                 break;  
                                         }  
                                         else if (xevent.xbutton.x <= g_win_button_size)  
                                         {  
                                                 /* The system menu. Ignore. */  
                                                 break;  
                                         }  
                                         else  
                                         {  
                                                 /* The title bar. */  
                                                 if ((xevent.type == ButtonPress) && !g_fullscreen  
                                                     && g_hide_decorations)  
                                                 {  
                                                         g_moving_wnd = True;  
                                                         g_move_x_offset = xevent.xbutton.x;  
                                                         g_move_y_offset = xevent.xbutton.y;  
                                                 }  
                                                 break;  
   
                                         }  
                                 }  
   
                                 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
                                                flags | button, xevent.xbutton.x, xevent.xbutton.y);  
1973                                  break;                                  break;
1974    
1975                          case MotionNotify:                          case MotionNotify:
# Line 1109  xwin_process_events(void) Line 1984  xwin_process_events(void)
1984                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1985                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1986                                                         CurrentTime);                                                         CurrentTime);
1987                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1988                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1989                                    {
1990                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1991                                                           xevent.xmotion.x, xevent.xmotion.y);
1992                                    }
1993                                    else
1994                                    {
1995                                            /* SeamlessRDP */
1996                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1997                                                           xevent.xmotion.x_root,
1998                                                           xevent.xmotion.y_root);
1999                                    }
2000                                  break;                                  break;
2001    
2002                          case FocusIn:                          case FocusIn:
2003                                  if (xevent.xfocus.mode == NotifyGrab)                                  if (xevent.xfocus.mode == NotifyGrab)
2004                                          break;                                          break;
2005                                  g_focused = True;                                  g_focused = True;
2006                                  XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,                                  reset_modifier_keys();
                                               &dummy, &dummy, &state);  
                                 reset_modifier_keys(state);  
2007                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2008                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2009                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2010    
2011                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2012                                    if (!sw)
2013                                            break;
2014    
2015                                    if (sw->id != g_seamless_focused)
2016                                    {
2017                                            seamless_send_focus(sw->id, 0);
2018                                            g_seamless_focused = sw->id;
2019                                    }
2020                                  break;                                  break;
2021    
2022                          case FocusOut:                          case FocusOut:
# Line 1155  xwin_process_events(void) Line 2049  xwin_process_events(void)
2049                                  break;                                  break;
2050    
2051                          case Expose:                          case Expose:
2052                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2053                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2054                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2055                                            xevent.xexpose.height,                                                    g_gc,
2056                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2057                                                      xevent.xexpose.width, xevent.xexpose.height,
2058                                                      xevent.xexpose.x, xevent.xexpose.y);
2059                                    }
2060                                    else
2061                                    {
2062                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2063                                            if (sw)
2064                                                    XCopyArea(g_display, g_backstore,
2065                                                              xevent.xexpose.window, g_gc,
2066                                                              xevent.xexpose.x + sw->xoffset,
2067                                                              xevent.xexpose.y + sw->yoffset,
2068                                                              xevent.xexpose.width,
2069                                                              xevent.xexpose.height, xevent.xexpose.x,
2070                                                              xevent.xexpose.y);
2071                                            else
2072                                            {
2073                                                    error("Expose for unknown window 0x%lx\n",
2074                                                          xevent.xexpose.window);
2075                                            }
2076                                    }
2077    
2078                                  break;                                  break;
2079    
2080                          case MappingNotify:                          case MappingNotify:
# Line 1188  xwin_process_events(void) Line 2103  xwin_process_events(void)
2103                                  break;                                  break;
2104                          case PropertyNotify:                          case PropertyNotify:
2105                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2106                                    if (xevent.xproperty.window == g_wnd)
2107                                            break;
2108                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2109                                            break;
2110    
2111                                    /* seamless */
2112                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2113                                    if (!sw)
2114                                            break;
2115    
2116                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2117                                        && (xevent.xproperty.state == PropertyNewValue))
2118                                    {
2119                                            sw->state = ewmh_get_window_state(sw->wnd);
2120                                            seamless_send_state(sw->id, sw->state, 0);
2121                                    }
2122    
2123                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2124                                        && (xevent.xproperty.state == PropertyNewValue))
2125                                    {
2126                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2127                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2128                                    }
2129    
2130                                    break;
2131                            case MapNotify:
2132                                    if (!g_seamless_active)
2133                                            rdp_send_client_window_status(1);
2134                                    break;
2135                            case UnmapNotify:
2136                                    if (!g_seamless_active)
2137                                            rdp_send_client_window_status(0);
2138                                    break;
2139                            case ConfigureNotify:
2140                                    if (!g_seamless_active)
2141                                            break;
2142    
2143                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2144                                    if (!sw)
2145                                    {
2146                                            error("ConfigureNotify for unknown window 0x%lx\n",
2147                                                  xevent.xconfigure.window);
2148                                    }
2149    
2150                                    gettimeofday(sw->position_timer, NULL);
2151                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2152                                        1000000)
2153                                    {
2154                                            sw->position_timer->tv_usec +=
2155                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2156                                            sw->position_timer->tv_sec += 1;
2157                                    }
2158                                    else
2159                                    {
2160                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2161                                    }
2162    
2163                                    sw_handle_restack(sw);
2164                                  break;                                  break;
2165                  }                  }
2166          }          }
# Line 1199  xwin_process_events(void) Line 2172  xwin_process_events(void)
2172  int  int
2173  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2174  {  {
2175          int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;          int n;
2176          fd_set rfds, wfds;          fd_set rfds, wfds;
2177            struct timeval tv;
2178            BOOL s_timeout = False;
2179    
2180          while (True)          while (True)
2181          {          {
2182                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2183                  /* Process any events already waiting */                  /* Process any events already waiting */
2184                  if (!xwin_process_events())                  if (!xwin_process_events())
2185                          /* User quit */                          /* User quit */
2186                          return 0;                          return 0;
2187    
2188                    if (g_seamless_active)
2189                            sw_check_timers();
2190    
2191                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2192                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2193                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
# Line 1219  ui_select(int rdp_socket) Line 2198  ui_select(int rdp_socket)
2198                  if (g_dsp_busy)                  if (g_dsp_busy)
2199                  {                  {
2200                          FD_SET(g_dsp_fd, &wfds);                          FD_SET(g_dsp_fd, &wfds);
2201                          n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;                          n = (g_dsp_fd > n) ? g_dsp_fd : n;
2202                  }                  }
2203  #endif  #endif
2204                    /* default timeout */
2205                    tv.tv_sec = 60;
2206                    tv.tv_usec = 0;
2207    
2208                    /* add redirection handles */
2209                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2210                    seamless_select_timeout(&tv);
2211    
2212                  switch (select(n, &rfds, &wfds, NULL, NULL))                  n++;
2213    
2214                    switch (select(n, &rfds, &wfds, NULL, &tv))
2215                  {                  {
2216                          case -1:                          case -1:
2217                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2218    
2219                          case 0:                          case 0:
2220                                    /* Abort serial read calls */
2221                                    if (s_timeout)
2222                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2223                                  continue;                                  continue;
2224                  }                  }
2225    
2226                    rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2227    
2228                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2229                          return 1;                          return 1;
2230    
# Line 1254  ui_create_bitmap(int width, int height, Line 2247  ui_create_bitmap(int width, int height,
2247          XImage *image;          XImage *image;
2248          Pixmap bitmap;          Pixmap bitmap;
2249          uint8 *tdata;          uint8 *tdata;
2250            int bitmap_pad;
2251    
2252            if (g_server_depth == 8)
2253            {
2254                    bitmap_pad = 8;
2255            }
2256            else
2257            {
2258                    bitmap_pad = g_bpp;
2259    
2260                    if (g_bpp == 24)
2261                            bitmap_pad = 32;
2262            }
2263    
2264          tdata = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2265          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2266          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2267                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2268    
2269          XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2270    
2271          XFree(image);          XFree(image);
2272          if (!g_owncolmap)          if (tdata != data)
2273                  xfree(tdata);                  xfree(tdata);
2274          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2275  }  }
# Line 1273  ui_paint_bitmap(int x, int y, int cx, in Line 2279  ui_paint_bitmap(int x, int y, int cx, in
2279  {  {
2280          XImage *image;          XImage *image;
2281          uint8 *tdata;          uint8 *tdata;
2282            int bitmap_pad;
2283    
2284            if (g_server_depth == 8)
2285            {
2286                    bitmap_pad = 8;
2287            }
2288            else
2289            {
2290                    bitmap_pad = g_bpp;
2291    
2292                    if (g_bpp == 24)
2293                            bitmap_pad = 32;
2294            }
2295    
2296          tdata = (g_owncolmap ? data : translate_image(width, height, data));          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2297          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2298                               (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2299    
2300          if (g_ownbackstore)          if (g_ownbackstore)
2301          {          {
2302                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2303                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2304                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2305                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2306                                             x - sw->xoffset, y - sw->yoffset));
2307          }          }
2308          else          else
2309          {          {
2310                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2311                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2312                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2313                                             x - sw->xoffset, y - sw->yoffset));
2314          }          }
2315    
2316          XFree(image);          XFree(image);
2317          if (!g_owncolmap)          if (tdata != data)
2318                  xfree(tdata);                  xfree(tdata);
2319  }  }
2320    
# Line 1304  ui_create_glyph(int width, int height, u Line 2330  ui_create_glyph(int width, int height, u
2330          XImage *image;          XImage *image;
2331          Pixmap bitmap;          Pixmap bitmap;
2332          int scanline;          int scanline;
         GC gc;  
2333    
2334          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2335    
2336          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2337          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2338                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2339    
2340          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2341                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1317  ui_create_glyph(int width, int height, u Line 2343  ui_create_glyph(int width, int height, u
2343          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2344          XInitImage(image);          XInitImage(image);
2345    
2346          XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2347    
2348          XFree(image);          XFree(image);
         XFreeGC(g_display, gc);  
2349          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2350  }  }
2351    
# Line 1406  ui_set_cursor(HCURSOR cursor) Line 2431  ui_set_cursor(HCURSOR cursor)
2431  {  {
2432          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2433          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2434            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2435  }  }
2436    
2437  void  void
# Line 1501  ui_create_colourmap(COLOURMAP * colours) Line 2527  ui_create_colourmap(COLOURMAP * colours)
2527    
2528                          }                          }
2529    
2530                            map[i] = colour;
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
2531                  }                  }
2532                  return map;                  return map;
2533          }          }
# Line 1549  ui_set_colourmap(HCOLOURMAP map) Line 2573  ui_set_colourmap(HCOLOURMAP map)
2573                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2574          }          }
2575          else          else
2576            {
2577                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2578                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2579            }
2580  }  }
2581    
2582  void  void
2583  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2584  {  {
2585          XRectangle rect;          g_clip_rectangle.x = x;
2586            g_clip_rectangle.y = y;
2587          rect.x = x;          g_clip_rectangle.width = cx;
2588          rect.y = y;          g_clip_rectangle.height = cy;
2589          rect.width = cx;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = cy;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
2590  }  }
2591    
2592  void  void
2593  ui_reset_clip(void)  ui_reset_clip(void)
2594  {  {
2595          XRectangle rect;          g_clip_rectangle.x = 0;
2596            g_clip_rectangle.y = 0;
2597          rect.x = 0;          g_clip_rectangle.width = g_width;
2598          rect.y = 0;          g_clip_rectangle.height = g_height;
2599          rect.width = g_width;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = g_height;  
         XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);  
2600  }  }
2601    
2602  void  void
# Line 1614  ui_patblt(uint8 opcode, Line 2637  ui_patblt(uint8 opcode,
2637          {          {
2638                  case 0: /* Solid */                  case 0: /* Solid */
2639                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2640                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2641                          break;                          break;
2642    
2643                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1625  ui_patblt(uint8 opcode, Line 2648  ui_patblt(uint8 opcode,
2648                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2649                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2650                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2651                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2652                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2653                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2654                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1635  ui_patblt(uint8 opcode, Line 2658  ui_patblt(uint8 opcode,
2658                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2659                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2660                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2661                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2662                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2663                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2664                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2665                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2666                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
2667                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2668                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2669                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1654  ui_patblt(uint8 opcode, Line 2674  ui_patblt(uint8 opcode,
2674          }          }
2675    
2676          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2677    
2678            if (g_ownbackstore)
2679                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2680            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2681                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2682                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2683  }  }
2684    
2685  void  void
# Line 1662  ui_screenblt(uint8 opcode, Line 2688  ui_screenblt(uint8 opcode,
2688               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2689  {  {
2690          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
         XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
2691          if (g_ownbackstore)          if (g_ownbackstore)
2692            {
2693                    XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2694                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2695                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2696            }
2697            else
2698            {
2699                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2700            }
2701    
2702            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2703                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2704                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2705    
2706          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2707  }  }
2708    
# Line 1675  ui_memblt(uint8 opcode, Line 2713  ui_memblt(uint8 opcode,
2713  {  {
2714          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2715          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2716            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2717                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2718                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2719          if (g_ownbackstore)          if (g_ownbackstore)
2720                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2721          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1721  ui_line(uint8 opcode, Line 2762  ui_line(uint8 opcode,
2762          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2763          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2764          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2765            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2766                                                startx - sw->xoffset, starty - sw->yoffset,
2767                                                endx - sw->xoffset, endy - sw->yoffset));
2768          if (g_ownbackstore)          if (g_ownbackstore)
2769                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2770          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1735  ui_rect( Line 2779  ui_rect(
2779          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2780  }  }
2781    
2782    void
2783    ui_polygon(uint8 opcode,
2784               /* mode */ uint8 fillmode,
2785               /* dest */ POINT * point, int npoints,
2786               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2787    {
2788            uint8 style, i, ipattern[8];
2789            Pixmap fill;
2790    
2791            SET_FUNCTION(opcode);
2792    
2793            switch (fillmode)
2794            {
2795                    case ALTERNATE:
2796                            XSetFillRule(g_display, g_gc, EvenOddRule);
2797                            break;
2798                    case WINDING:
2799                            XSetFillRule(g_display, g_gc, WindingRule);
2800                            break;
2801                    default:
2802                            unimpl("fill mode %d\n", fillmode);
2803            }
2804    
2805            if (brush)
2806                    style = brush->style;
2807            else
2808                    style = 0;
2809    
2810            switch (style)
2811            {
2812                    case 0: /* Solid */
2813                            SET_FOREGROUND(fgcolour);
2814                            FILL_POLYGON((XPoint *) point, npoints);
2815                            break;
2816    
2817                    case 2: /* Hatch */
2818                            fill = (Pixmap) ui_create_glyph(8, 8,
2819                                                            hatch_patterns + brush->pattern[0] * 8);
2820                            SET_FOREGROUND(fgcolour);
2821                            SET_BACKGROUND(bgcolour);
2822                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2823                            XSetStipple(g_display, g_gc, fill);
2824                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2825                            FILL_POLYGON((XPoint *) point, npoints);
2826                            XSetFillStyle(g_display, g_gc, FillSolid);
2827                            XSetTSOrigin(g_display, g_gc, 0, 0);
2828                            ui_destroy_glyph((HGLYPH) fill);
2829                            break;
2830    
2831                    case 3: /* Pattern */
2832                            for (i = 0; i != 8; i++)
2833                                    ipattern[7 - i] = brush->pattern[i];
2834                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2835                            SET_FOREGROUND(bgcolour);
2836                            SET_BACKGROUND(fgcolour);
2837                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2838                            XSetStipple(g_display, g_gc, fill);
2839                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2840                            FILL_POLYGON((XPoint *) point, npoints);
2841                            XSetFillStyle(g_display, g_gc, FillSolid);
2842                            XSetTSOrigin(g_display, g_gc, 0, 0);
2843                            ui_destroy_glyph((HGLYPH) fill);
2844                            break;
2845    
2846                    default:
2847                            unimpl("brush %d\n", brush->style);
2848            }
2849    
2850            RESET_FUNCTION(opcode);
2851    }
2852    
2853    void
2854    ui_polyline(uint8 opcode,
2855                /* dest */ POINT * points, int npoints,
2856                /* pen */ PEN * pen)
2857    {
2858            /* TODO: set join style */
2859            SET_FUNCTION(opcode);
2860            SET_FOREGROUND(pen->colour);
2861            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2862            if (g_ownbackstore)
2863                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2864                               CoordModePrevious);
2865    
2866            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2867                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2868    
2869            RESET_FUNCTION(opcode);
2870    }
2871    
2872    void
2873    ui_ellipse(uint8 opcode,
2874               /* mode */ uint8 fillmode,
2875               /* dest */ int x, int y, int cx, int cy,
2876               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2877    {
2878            uint8 style, i, ipattern[8];
2879            Pixmap fill;
2880    
2881            SET_FUNCTION(opcode);
2882    
2883            if (brush)
2884                    style = brush->style;
2885            else
2886                    style = 0;
2887    
2888            switch (style)
2889            {
2890                    case 0: /* Solid */
2891                            SET_FOREGROUND(fgcolour);
2892                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2893                            break;
2894    
2895                    case 2: /* Hatch */
2896                            fill = (Pixmap) ui_create_glyph(8, 8,
2897                                                            hatch_patterns + brush->pattern[0] * 8);
2898                            SET_FOREGROUND(fgcolour);
2899                            SET_BACKGROUND(bgcolour);
2900                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2901                            XSetStipple(g_display, g_gc, fill);
2902                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2903                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2904                            XSetFillStyle(g_display, g_gc, FillSolid);
2905                            XSetTSOrigin(g_display, g_gc, 0, 0);
2906                            ui_destroy_glyph((HGLYPH) fill);
2907                            break;
2908    
2909                    case 3: /* Pattern */
2910                            for (i = 0; i != 8; i++)
2911                                    ipattern[7 - i] = brush->pattern[i];
2912                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2913                            SET_FOREGROUND(bgcolour);
2914                            SET_BACKGROUND(fgcolour);
2915                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2916                            XSetStipple(g_display, g_gc, fill);
2917                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2918                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2919                            XSetFillStyle(g_display, g_gc, FillSolid);
2920                            XSetTSOrigin(g_display, g_gc, 0, 0);
2921                            ui_destroy_glyph((HGLYPH) fill);
2922                            break;
2923    
2924                    default:
2925                            unimpl("brush %d\n", brush->style);
2926            }
2927    
2928            RESET_FUNCTION(opcode);
2929    }
2930    
2931  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
2932  void  void
2933  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 1759  ui_draw_glyph(int mixmode, Line 2952  ui_draw_glyph(int mixmode,
2952  {\  {\
2953    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
2954    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
2955      {\
2956        xyoffset = ttext[++idx];\
2957        if ((xyoffset & 0x80))\
2958      {\      {\
2959        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
2960        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;\  
         }\  
2961        else\        else\
2962          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
2963            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
2964      }\      }\
2965    if (glyph != NULL)\      else\
2966      {\      {\
2967        ui_draw_glyph (mixmode, x + glyph->offset,\        if (flags & TEXT2_VERTICAL)\
2968                       y + glyph->baseline,\          y += xyoffset;\
2969                       glyph->width, glyph->height,\        else\
2970                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
2971      }\      }\
2972      }\
2973      if (glyph != NULL)\
2974      {\
2975        x1 = x + glyph->offset;\
2976        y1 = y + glyph->baseline;\
2977        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2978        XSetTSOrigin(g_display, g_gc, x1, y1);\
2979        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2980        if (flags & TEXT2_IMPLICIT_X)\
2981          x += glyph->width;\
2982      }\
2983  }  }
2984    
2985  void  void
2986  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,
2987               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2988               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2989               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2990  {  {
2991            /* TODO: use brush appropriately */
2992    
2993          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2994          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
2995          DATABLOB *entry;          DATABLOB *entry;
2996    
2997          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
2998    
2999            /* Sometimes, the boxcx value is something really large, like
3000               32691. This makes XCopyArea fail with Xvnc. The code below
3001               is a quick fix. */
3002            if (boxx + boxcx > g_width)
3003                    boxcx = g_width - boxx;
3004    
3005          if (boxcx > 1)          if (boxcx > 1)
3006          {          {
3007                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
# Line 1809  ui_draw_text(uint8 font, uint8 flags, in Line 3011  ui_draw_text(uint8 font, uint8 flags, in
3011                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3012          }          }
3013    
3014            SET_FOREGROUND(fgcolour);
3015            SET_BACKGROUND(bgcolour);
3016            XSetFillStyle(g_display, g_gc, FillStippled);
3017    
3018          /* Paint text, character by character */          /* Paint text, character by character */
3019          for (i = 0; i < length;)          for (i = 0; i < length;)
3020          {          {
3021                  switch (text[i])                  switch (text[i])
3022                  {                  {
3023                          case 0xff:                          case 0xff:
3024                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3025                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3026                                  {                                  {
3027                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3028                                          exit(1);                                          for (j = 0; j < length; j++)
3029                                                    fprintf(stderr, "%02x ", text[j]);
3030                                            fprintf(stderr, "\n");
3031                                            i = length = 0;
3032                                            break;
3033                                  }                                  }
3034                                    cache_put_text(text[i + 1], text, text[i + 2]);
3035                                    i += 3;
3036                                    length -= i;
3037                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3038                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3039                                  i = 0;                                  i = 0;
3040                                  break;                                  break;
3041    
3042                          case 0xfe:                          case 0xfe:
3043                                    /* At least one byte needs to follow */
3044                                    if (i + 2 > length)
3045                                    {
3046                                            warning("Skipping short 0xfe command:");
3047                                            for (j = 0; j < length; j++)
3048                                                    fprintf(stderr, "%02x ", text[j]);
3049                                            fprintf(stderr, "\n");
3050                                            i = length = 0;
3051                                            break;
3052                                    }
3053                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3054                                  if (entry != NULL)                                  if (entry->data != NULL)
3055                                  {                                  {
3056                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3057                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3058                                          {                                          {
3059                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3060                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 1859  ui_draw_text(uint8 font, uint8 flags, in Line 3080  ui_draw_text(uint8 font, uint8 flags, in
3080                                  break;                                  break;
3081                  }                  }
3082          }          }
3083    
3084            XSetFillStyle(g_display, g_gc, FillSolid);
3085    
3086          if (g_ownbackstore)          if (g_ownbackstore)
3087          {          {
3088                  if (boxcx > 1)                  if (boxcx > 1)
3089                    {
3090                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3091                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3092                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3093                                                    (g_display, g_backstore, sw->wnd, g_gc,
3094                                                     boxx, boxy,
3095                                                     boxcx, boxcy,
3096                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3097                    }
3098                  else                  else
3099                    {
3100                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3101                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3102                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3103                                                    (g_display, g_backstore, sw->wnd, g_gc,
3104                                                     clipx, clipy,
3105                                                     clipcx, clipcy, clipx - sw->xoffset,
3106                                                     clipy - sw->yoffset));
3107                    }
3108          }          }
3109  }  }
3110    
# Line 1912  ui_desktop_restore(uint32 offset, int x, Line 3150  ui_desktop_restore(uint32 offset, int x,
3150          {          {
3151                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3152                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3153                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3154                                            (g_display, g_backstore, sw->wnd, g_gc,
3155                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3156          }          }
3157          else          else
3158          {          {
3159                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3160                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3161                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3162                                             x - sw->xoffset, y - sw->yoffset));
3163          }          }
3164    
3165          XFree(image);          XFree(image);
3166  }  }
3167    
3168    /* these do nothing here but are used in uiports */
3169    void
3170    ui_begin_update(void)
3171    {
3172    }
3173    
3174    void
3175    ui_end_update(void)
3176    {
3177    }
3178    
3179    
3180    void
3181    ui_seamless_begin()
3182    {
3183            if (!g_seamless_rdp)
3184                    return;
3185    
3186            if (g_seamless_started)
3187                    return;
3188    
3189            g_seamless_started = True;
3190            ui_seamless_toggle();
3191    }
3192    
3193    
3194    void
3195    ui_seamless_toggle()
3196    {
3197            if (!g_seamless_rdp)
3198                    return;
3199    
3200            if (!g_seamless_started)
3201                    return;
3202    
3203            if (g_seamless_active)
3204            {
3205                    /* Deactivate */
3206                    while (g_seamless_windows)
3207                    {
3208                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3209                            sw_remove_window(g_seamless_windows);
3210                    }
3211                    XMapWindow(g_display, g_wnd);
3212            }
3213            else
3214            {
3215                    /* Activate */
3216                    XUnmapWindow(g_display, g_wnd);
3217                    seamless_send_sync();
3218            }
3219    
3220            g_seamless_active = !g_seamless_active;
3221    }
3222    
3223    
3224    void
3225    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3226    {
3227            Window wnd;
3228            XSetWindowAttributes attribs;
3229            XClassHint *classhints;
3230            XSizeHints *sizehints;
3231            long input_mask;
3232            seamless_window *sw, *sw_parent;
3233    
3234            if (!g_seamless_active)
3235                    return;
3236    
3237            /* Ignore CREATEs for existing windows */
3238            sw = sw_get_window_by_id(id);
3239            if (sw)
3240                    return;
3241    
3242            get_window_attribs(&attribs);
3243            attribs.override_redirect = False;
3244    
3245            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3246                                InputOutput, g_visual,
3247                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3248                                CWBorderPixel, &attribs);
3249    
3250            XStoreName(g_display, wnd, "SeamlessRDP");
3251            ewmh_set_wm_name(wnd, "SeamlessRDP");
3252    
3253            mwm_hide_decorations(wnd);
3254    
3255            classhints = XAllocClassHint();
3256            if (classhints != NULL)
3257            {
3258                    classhints->res_name = "rdesktop";
3259                    classhints->res_class = "SeamlessRDP";
3260                    XSetClassHint(g_display, wnd, classhints);
3261                    XFree(classhints);
3262            }
3263    
3264            /* WM_NORMAL_HINTS */
3265            sizehints = XAllocSizeHints();
3266            if (sizehints != NULL)
3267            {
3268                    sizehints->flags = USPosition;
3269                    XSetWMNormalHints(g_display, wnd, sizehints);
3270                    XFree(sizehints);
3271            }
3272    
3273            /* Handle popups without parents through some ewm hints */
3274            if (parent == 0xFFFFFFFF)
3275                    ewmh_set_window_popup(wnd);
3276            /* Set WM_TRANSIENT_FOR, if necessary */
3277            else if (parent != 0x00000000)
3278            {
3279                    sw_parent = sw_get_window_by_id(parent);
3280                    if (sw_parent)
3281                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3282                    else
3283                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3284            }
3285    
3286    
3287            /* FIXME: Support for Input Context:s */
3288    
3289            get_input_mask(&input_mask);
3290            input_mask |= PropertyChangeMask;
3291    
3292            XSelectInput(g_display, wnd, input_mask);
3293    
3294            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3295               seamless window, we could try to close the window on the
3296               serverside, instead of terminating rdesktop */
3297            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3298    
3299            sw = xmalloc(sizeof(seamless_window));
3300            sw->wnd = wnd;
3301            sw->id = id;
3302            sw->behind = 0;
3303            sw->xoffset = 0;
3304            sw->yoffset = 0;
3305            sw->width = 0;
3306            sw->height = 0;
3307            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3308            sw->desktop = 0;
3309            sw->position_timer = xmalloc(sizeof(struct timeval));
3310            timerclear(sw->position_timer);
3311            sw->outstanding_position = False;
3312            sw->next = g_seamless_windows;
3313            g_seamless_windows = sw;
3314    }
3315    
3316    
3317    void
3318    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3319    {
3320            seamless_window *sw;
3321    
3322            if (!g_seamless_active)
3323                    return;
3324    
3325            sw = sw_get_window_by_id(id);
3326            if (!sw)
3327            {
3328                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3329                    return;
3330            }
3331    
3332            XDestroyWindow(g_display, sw->wnd);
3333            sw_remove_window(sw);
3334    }
3335    
3336    
3337    void
3338    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3339    {
3340            seamless_window *sw;
3341    
3342            if (!g_seamless_active)
3343                    return;
3344    
3345            sw = sw_get_window_by_id(id);
3346            if (!sw)
3347            {
3348                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3349                    return;
3350            }
3351    
3352            /* We ignore server updates until it has handled our request. */
3353            if (sw->outstanding_position)
3354                    return;
3355    
3356            if (!width || !height)
3357                    /* X11 windows must be at least 1x1 */
3358                    return;
3359    
3360            sw->xoffset = x;
3361            sw->yoffset = y;
3362            sw->width = width;
3363            sw->height = height;
3364    
3365            /* If we move the window in a maximized state, then KDE won't
3366               accept restoration */
3367            switch (sw->state)
3368            {
3369                    case SEAMLESSRDP_MINIMIZED:
3370                    case SEAMLESSRDP_MAXIMIZED:
3371                            return;
3372            }
3373    
3374            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3375            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3376    }
3377    
3378    
3379    void
3380    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3381    {
3382            seamless_window *sw;
3383    
3384            if (!g_seamless_active)
3385                    return;
3386    
3387            sw = sw_get_window_by_id(id);
3388            if (!sw)
3389            {
3390                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3391                    return;
3392            }
3393    
3394            if (behind)
3395            {
3396                    seamless_window *sw_behind;
3397                    Window wnds[2];
3398    
3399                    sw_behind = sw_get_window_by_id(behind);
3400                    if (!sw_behind)
3401                    {
3402                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3403                                    behind);
3404                            return;
3405                    }
3406    
3407                    wnds[1] = sw_behind->wnd;
3408                    wnds[0] = sw->wnd;
3409    
3410                    XRestackWindows(g_display, wnds, 2);
3411            }
3412            else
3413            {
3414                    XRaiseWindow(g_display, sw->wnd);
3415            }
3416    
3417            sw_restack_window(sw, behind);
3418    }
3419    
3420    
3421    void
3422    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3423    {
3424            seamless_window *sw;
3425    
3426            if (!g_seamless_active)
3427                    return;
3428    
3429            sw = sw_get_window_by_id(id);
3430            if (!sw)
3431            {
3432                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3433                    return;
3434            }
3435    
3436            /* FIXME: Might want to convert the name for non-EWMH WMs */
3437            XStoreName(g_display, sw->wnd, title);
3438            ewmh_set_wm_name(sw->wnd, title);
3439    }
3440    
3441    
3442    void
3443    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3444    {
3445            seamless_window *sw;
3446    
3447            if (!g_seamless_active)
3448                    return;
3449    
3450            sw = sw_get_window_by_id(id);
3451            if (!sw)
3452            {
3453                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3454                    return;
3455            }
3456    
3457            switch (state)
3458            {
3459                    case SEAMLESSRDP_NORMAL:
3460                    case SEAMLESSRDP_MAXIMIZED:
3461                            ewmh_change_state(sw->wnd, state);
3462                            XMapWindow(g_display, sw->wnd);
3463                            break;
3464                    case SEAMLESSRDP_MINIMIZED:
3465                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3466                               the Window Manager should probably just ignore the request, since
3467                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3468                               such as minimization, rather than an independent state." Besides,
3469                               XIconifyWindow is easier. */
3470                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3471                            {
3472                                    XWMHints *hints;
3473                                    hints = XAllocWMHints();
3474                                    hints->flags = StateHint;
3475                                    hints->initial_state = IconicState;
3476                                    XSetWMHints(g_display, sw->wnd, hints);
3477                                    XFree(hints);
3478                                    XMapWindow(g_display, sw->wnd);
3479                            }
3480                            else
3481                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3482                            break;
3483                    default:
3484                            warning("SeamlessRDP: Invalid state %d\n", state);
3485                            break;
3486            }
3487    
3488            sw->state = state;
3489    }
3490    
3491    
3492    void
3493    ui_seamless_syncbegin(unsigned long flags)
3494    {
3495            if (!g_seamless_active)
3496                    return;
3497    
3498            /* Destroy all seamless windows */
3499            while (g_seamless_windows)
3500            {
3501                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3502                    sw_remove_window(g_seamless_windows);
3503            }
3504    }
3505    
3506    
3507    void
3508    ui_seamless_ack(unsigned int serial)
3509    {
3510            seamless_window *sw;
3511            for (sw = g_seamless_windows; sw; sw = sw->next)
3512            {
3513                    if (sw->outpos_serial == serial)
3514                    {
3515                            sw->xoffset = sw->outpos_xoffset;
3516                            sw->yoffset = sw->outpos_yoffset;
3517                            sw->width = sw->outpos_width;
3518                            sw->height = sw->outpos_height;
3519                            sw->outstanding_position = False;
3520                            break;
3521                    }
3522            }
3523    
3524            return;
3525    }

Legend:
Removed from v.519  
changed lines
  Added in v.1170

  ViewVC Help
Powered by ViewVC 1.1.26