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

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

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

revision 643 by jsorg71, Wed Mar 24 18:16:58 2004 UTC revision 1306 by astrand, Fri Oct 27 12:59:38 2006 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 28  Line 28 
28  #include "rdesktop.h"  #include "rdesktop.h"
29  #include "xproto.h"  #include "xproto.h"
30    
31    /* We can't include Xproto.h because of conflicting defines for BOOL */
32    #define X_ConfigureWindow              12
33    
34  extern int g_width;  extern int g_width;
35  extern int g_height;  extern int g_height;
36    extern int g_xpos;
37    extern int g_ypos;
38    extern int g_pos;
39  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
40  extern BOOL g_fullscreen;  extern BOOL g_fullscreen;
41  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
42  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
43  extern char g_title[];  extern char g_title[];
44  extern int g_server_bpp;  /* Color depth of the RDP session.
45       As of RDP 5.1, it may be 8, 15, 16 or 24. */
46    extern int g_server_depth;
47  extern int g_win_button_size;  extern int g_win_button_size;
48    
49  Display *g_display;  Display *g_display;
# Line 43  Time g_last_gesturetime; Line 51  Time g_last_gesturetime;
51  static int g_x_socket;  static int g_x_socket;
52  static Screen *g_screen;  static Screen *g_screen;
53  Window g_wnd;  Window g_wnd;
54  uint32 g_embed_wnd;  
55    /* SeamlessRDP support */
56    typedef struct _seamless_group
57    {
58            Window wnd;
59            unsigned long id;
60            unsigned int refcnt;
61    } seamless_group;
62    typedef struct _seamless_window
63    {
64            Window wnd;
65            unsigned long id;
66            unsigned long behind;
67            seamless_group *group;
68            int xoffset, yoffset;
69            int width, height;
70            int state;              /* normal/minimized/maximized. */
71            unsigned int desktop;
72            struct timeval *position_timer;
73    
74            BOOL outstanding_position;
75            unsigned int outpos_serial;
76            int outpos_xoffset, outpos_yoffset;
77            int outpos_width, outpos_height;
78    
79            struct _seamless_window *next;
80    } seamless_window;
81    static seamless_window *g_seamless_windows = NULL;
82    static unsigned long g_seamless_focused = 0;
83    static BOOL g_seamless_started = False; /* Server end is up and running */
84    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
85    static BOOL g_seamless_hidden = False;  /* Desktop is hidden on server */
86    extern BOOL g_seamless_rdp;
87    
88    extern uint32 g_embed_wnd;
89  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
90    BOOL g_Unobscured;              /* used for screenblt */
91  static GC g_gc = NULL;  static GC g_gc = NULL;
92    static GC g_create_bitmap_gc = NULL;
93    static GC g_create_glyph_gc = NULL;
94    static XRectangle g_clip_rectangle;
95  static Visual *g_visual;  static Visual *g_visual;
96    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
97       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
98       as far as we're concerned. */
99  static int g_depth;  static int g_depth;
100    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
101       This may be larger than g_depth, in which case some of the bits would
102       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
103  static int g_bpp;  static int g_bpp;
104  static XIM g_IM;  static XIM g_IM;
105  static XIC g_IC;  static XIC g_IC;
# Line 55  static XModifierKeymap *g_mod_map; Line 107  static XModifierKeymap *g_mod_map;
107  static Cursor g_current_cursor;  static Cursor g_current_cursor;
108  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
109  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
110    extern Atom g_net_wm_state_atom;
111    extern Atom g_net_wm_desktop_atom;
112  static BOOL g_focused;  static BOOL g_focused;
113  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
114    /* Indicates that:
115       1) visual has 15, 16 or 24 depth and the same color channel masks
116          as its RDP equivalent (implies X server is LE),
117       2) host is LE
118       This will trigger an optimization whose real value is questionable.
119    */
120    static BOOL g_compatible_arch;
121    /* Indicates whether RDP's bitmaps and our XImages have the same
122       binary format. If so, we can avoid an expensive translation.
123       Note that this can be true when g_compatible_arch is false,
124       e.g.:
125      
126         RDP(LE) <-> host(BE) <-> X-Server(LE)
127        
128       ('host' is the machine running rdesktop; the host simply memcpy's
129        so its endianess doesn't matter)
130     */
131    static BOOL g_no_translate_image = False;
132    
133  /* endianness */  /* endianness */
134  static BOOL g_host_be;  static BOOL g_host_be;
# Line 65  static int g_red_shift_r, g_blue_shift_r Line 137  static int g_red_shift_r, g_blue_shift_r
137  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;  static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
138    
139  /* software backing store */  /* software backing store */
140  BOOL g_ownbackstore = True;     /* We can't rely on external BackingStore */  extern BOOL g_ownbackstore;
141  static Pixmap g_backstore = 0;  static Pixmap g_backstore = 0;
142    
143  /* Moving in single app mode */  /* Moving in single app mode */
144  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
145  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
146  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
147    static BOOL g_using_full_workarea = False;
148    
149  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
150  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 84  extern BOOL g_rdpsnd; Line 157  extern BOOL g_rdpsnd;
157  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
158  typedef struct  typedef struct
159  {  {
160          uint32 flags;          unsigned long flags;
161          uint32 functions;          unsigned long functions;
162          uint32 decorations;          unsigned long decorations;
163          sint32 inputMode;          long inputMode;
164          uint32 status;          unsigned long status;
165  }  }
166  PropMotifWmHints;  PropMotifWmHints;
167    
# Line 100  typedef struct Line 173  typedef struct
173  }  }
174  PixelColour;  PixelColour;
175    
176    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
177            do { \
178                    seamless_window *sw; \
179                    XRectangle rect; \
180                    if (!g_seamless_windows) break; \
181                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
182                        rect.x = g_clip_rectangle.x - sw->xoffset; \
183                        rect.y = g_clip_rectangle.y - sw->yoffset; \
184                        rect.width = g_clip_rectangle.width; \
185                        rect.height = g_clip_rectangle.height; \
186                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
187                        func args; \
188                    } \
189                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
190            } while (0)
191    
192    static void
193    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
194    {
195            points[0].x -= xoffset;
196            points[0].y -= yoffset;
197            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
198            points[0].x += xoffset;
199            points[0].y += yoffset;
200    }
201    
202    static void
203    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
204    {
205            points[0].x -= xoffset;
206            points[0].y -= yoffset;
207            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
208            points[0].x += xoffset;
209            points[0].y += yoffset;
210    }
211    
212  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
213  { \  { \
214          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
215            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
216          if (g_ownbackstore) \          if (g_ownbackstore) \
217                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
218  }  }
# Line 113  PixelColour; Line 222  PixelColour;
222          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); \
223  }  }
224    
225    #define FILL_POLYGON(p,np)\
226    { \
227            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
228            if (g_ownbackstore) \
229                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
230            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
231    }
232    
233    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
234    { \
235            switch (m) \
236            { \
237                    case 0: /* Outline */ \
238                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
239                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
240                            if (g_ownbackstore) \
241                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
242                            break; \
243                    case 1: /* Filled */ \
244                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
245                            ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
246                            if (g_ownbackstore) \
247                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
248                            break; \
249            } \
250    }
251    
252  /* colour maps */  /* colour maps */
253  BOOL g_owncolmap = False;  extern BOOL g_owncolmap;
254  static Colormap g_xcolmap;  static Colormap g_xcolmap;
255  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
256    
257  #define TRANSLATE(col)          ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )  #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
258  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
259  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
260    
# Line 144  static int rop2_map[] = { Line 280  static int rop2_map[] = {
280  #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]); }
281  #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); }
282    
283    static seamless_window *
284    sw_get_window_by_id(unsigned long id)
285    {
286            seamless_window *sw;
287            for (sw = g_seamless_windows; sw; sw = sw->next)
288            {
289                    if (sw->id == id)
290                            return sw;
291            }
292            return NULL;
293    }
294    
295    
296    static seamless_window *
297    sw_get_window_by_wnd(Window wnd)
298    {
299            seamless_window *sw;
300            for (sw = g_seamless_windows; sw; sw = sw->next)
301            {
302                    if (sw->wnd == wnd)
303                            return sw;
304            }
305            return NULL;
306    }
307    
308    
309    static void
310    sw_remove_window(seamless_window * win)
311    {
312            seamless_window *sw, **prevnext = &g_seamless_windows;
313            for (sw = g_seamless_windows; sw; sw = sw->next)
314            {
315                    if (sw == win)
316                    {
317                            *prevnext = sw->next;
318                            sw->group->refcnt--;
319                            if (sw->group->refcnt == 0)
320                            {
321                                    XDestroyWindow(g_display, sw->group->wnd);
322                                    xfree(sw->group);
323                            }
324                            xfree(sw->position_timer);
325                            xfree(sw);
326                            return;
327                    }
328                    prevnext = &sw->next;
329            }
330            return;
331    }
332    
333    
334    /* Move all windows except wnd to new desktop */
335    static void
336    sw_all_to_desktop(Window wnd, unsigned int desktop)
337    {
338            seamless_window *sw;
339            for (sw = g_seamless_windows; sw; sw = sw->next)
340            {
341                    if (sw->wnd == wnd)
342                            continue;
343                    if (sw->desktop != desktop)
344                    {
345                            ewmh_move_to_desktop(sw->wnd, desktop);
346                            sw->desktop = desktop;
347                    }
348            }
349    }
350    
351    
352    /* Send our position */
353  static void  static void
354  mwm_hide_decorations(void)  sw_update_position(seamless_window * sw)
355    {
356            XWindowAttributes wa;
357            int x, y;
358            Window child_return;
359            unsigned int serial;
360    
361            XGetWindowAttributes(g_display, sw->wnd, &wa);
362            XTranslateCoordinates(g_display, sw->wnd, wa.root,
363                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
364    
365            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
366    
367            sw->outstanding_position = True;
368            sw->outpos_serial = serial;
369    
370            sw->outpos_xoffset = x;
371            sw->outpos_yoffset = y;
372            sw->outpos_width = wa.width;
373            sw->outpos_height = wa.height;
374    }
375    
376    
377    /* Check if it's time to send our position */
378    static void
379    sw_check_timers()
380    {
381            seamless_window *sw;
382            struct timeval now;
383    
384            gettimeofday(&now, NULL);
385            for (sw = g_seamless_windows; sw; sw = sw->next)
386            {
387                    if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
388                    {
389                            timerclear(sw->position_timer);
390                            sw_update_position(sw);
391                    }
392            }
393    }
394    
395    
396    static void
397    sw_restack_window(seamless_window * sw, unsigned long behind)
398    {
399            seamless_window *sw_above;
400    
401            /* Remove window from stack */
402            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
403            {
404                    if (sw_above->behind == sw->id)
405                            break;
406            }
407    
408            if (sw_above)
409                    sw_above->behind = sw->behind;
410    
411            /* And then add it at the new position */
412            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
413            {
414                    if (sw_above->behind == behind)
415                            break;
416            }
417    
418            if (sw_above)
419                    sw_above->behind = sw->id;
420    
421            sw->behind = behind;
422    }
423    
424    
425    static void
426    sw_handle_restack(seamless_window * sw)
427    {
428            Status status;
429            Window root, parent, *children;
430            unsigned int nchildren, i;
431            seamless_window *sw_below;
432    
433            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
434                                &root, &parent, &children, &nchildren);
435            if (!status || !nchildren)
436                    return;
437    
438            sw_below = NULL;
439    
440            i = 0;
441            while (children[i] != sw->wnd)
442            {
443                    i++;
444                    if (i >= nchildren)
445                            goto end;
446            }
447    
448            for (i++; i < nchildren; i++)
449            {
450                    sw_below = sw_get_window_by_wnd(children[i]);
451                    if (sw_below)
452                            break;
453            }
454    
455            if (!sw_below && !sw->behind)
456                    goto end;
457            if (sw_below && (sw_below->id == sw->behind))
458                    goto end;
459    
460            if (sw_below)
461            {
462                    seamless_send_zchange(sw->id, sw_below->id, 0);
463                    sw_restack_window(sw, sw_below->id);
464            }
465            else
466            {
467                    seamless_send_zchange(sw->id, 0, 0);
468                    sw_restack_window(sw, 0);
469            }
470    
471          end:
472            XFree(children);
473    }
474    
475    
476    static seamless_group *
477    sw_find_group(unsigned long id, BOOL dont_create)
478    {
479            seamless_window *sw;
480            seamless_group *sg;
481            XSetWindowAttributes attribs;
482    
483            for (sw = g_seamless_windows; sw; sw = sw->next)
484            {
485                    if (sw->group->id == id)
486                            return sw->group;
487            }
488    
489            if (dont_create)
490                    return NULL;
491    
492            sg = xmalloc(sizeof(seamless_group));
493    
494            sg->wnd =
495                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
496                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
497    
498            sg->id = id;
499            sg->refcnt = 0;
500    
501            return sg;
502    }
503    
504    
505    static void
506    mwm_hide_decorations(Window wnd)
507  {  {
508          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
509          Atom hintsatom;          Atom hintsatom;
# Line 162  mwm_hide_decorations(void) Line 520  mwm_hide_decorations(void)
520                  return;                  return;
521          }          }
522    
523          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
524                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
525    
526  }  }
527    
528  static PixelColour  #define SPLITCOLOUR15(colour, rv) \
529  split_colour15(uint32 colour)  { \
530  {          rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
531          PixelColour rv;          rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
532          rv.red = (colour & 0x7c00) >> 7;          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
         rv.green = (colour & 0x03e0) >> 2;  
         rv.blue = (colour & 0x001f) << 3;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour16(uint32 colour)  
 {  
         PixelColour rv;  
         rv.red = (colour & 0xf800) >> 8;  
         rv.green = (colour & 0x07e0) >> 3;  
         rv.blue = (colour & 0x001f) << 3;  
         return rv;  
 }  
   
 static PixelColour  
 split_colour24(uint32 colour)  
 {  
         PixelColour rv;  
         rv.blue = (colour & 0xff0000) >> 16;  
         rv.green = (colour & 0x00ff00) >> 8;  
         rv.red = (colour & 0x0000ff);  
         return rv;  
533  }  }
534    
535  static uint32  #define SPLITCOLOUR16(colour, rv) \
536  make_colour(PixelColour pc)  { \
537  {          rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
538          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
539                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
540                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));  } \
541    
542    #define SPLITCOLOUR24(colour, rv) \
543    { \
544            rv.blue = (colour & 0xff0000) >> 16; \
545            rv.green = (colour & 0x00ff00) >> 8; \
546            rv.red = (colour & 0x0000ff); \
547  }  }
548    
549    #define MAKECOLOUR(pc) \
550            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
551                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
552                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
553    
554  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
555  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
556  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
557                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
558    
559    /* The following macros output the same octet sequences
560       on both BE and LE hosts: */
561    
562    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
563    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
564    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
565    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
566    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
567    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
568    
569  static uint32  static uint32
570  translate_colour(uint32 colour)  translate_colour(uint32 colour)
571  {  {
572          PixelColour pc;          PixelColour pc;
573          switch (g_server_bpp)          switch (g_server_depth)
574          {          {
575                  case 15:                  case 15:
576                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
577                          break;                          break;
578                  case 16:                  case 16:
579                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
580                          break;                          break;
581                  case 24:                  case 24:
582                          pc = split_colour24(colour);                          SPLITCOLOUR24(colour, pc);
583                            break;
584                    default:
585                            /* Avoid warning */
586                            pc.red = 0;
587                            pc.green = 0;
588                            pc.blue = 0;
589                          break;                          break;
590          }          }
591          return make_colour(pc);          return MAKECOLOUR(pc);
592  }  }
593    
594    /* indent is confused by UNROLL8 */
595    /* *INDENT-OFF* */
596    
597    /* repeat and unroll, similar to bitmap.c */
598    /* potentialy any of the following translate */
599    /* functions can use repeat but just doing */
600    /* the most common ones */
601    
602    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
603    /* 2 byte output repeat */
604    #define REPEAT2(stm) \
605    { \
606            while (out <= end - 8 * 2) \
607                    UNROLL8(stm) \
608            while (out < end) \
609                    { stm } \
610    }
611    /* 3 byte output repeat */
612    #define REPEAT3(stm) \
613    { \
614            while (out <= end - 8 * 3) \
615                    UNROLL8(stm) \
616            while (out < end) \
617                    { stm } \
618    }
619    /* 4 byte output repeat */
620    #define REPEAT4(stm) \
621    { \
622            while (out <= end - 8 * 4) \
623                    UNROLL8(stm) \
624            while (out < end) \
625                    { stm } \
626    }
627    /* *INDENT-ON* */
628    
629  static void  static void
630  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
631  {  {
632          while (out < end)          while (out < end)
633                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
634  }  }
635    
636  static void  static void
637  translate8to16(uint8 * data, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
638  {  {
639          uint16 value;          uint16 value;
640    
641          if (g_xserver_be)          if (g_compatible_arch)
642            {
643                    /* *INDENT-OFF* */
644                    REPEAT2
645                    (
646                            *((uint16 *) out) = g_colmap[*(data++)];
647                            out += 2;
648                    )
649                    /* *INDENT-ON* */
650            }
651            else if (g_xserver_be)
652          {          {
653                  while (out < end)                  while (out < end)
654                  {                  {
655                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
656                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
657                  }                  }
658          }          }
659          else          else
# Line 254  translate8to16(uint8 * data, uint8 * out Line 661  translate8to16(uint8 * data, uint8 * out
661                  while (out < end)                  while (out < end)
662                  {                  {
663                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
664                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
665                  }                  }
666          }          }
667  }  }
668    
669  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
670  static void  static void
671  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
672  {  {
673          uint32 value;          uint32 value;
674    
675          if (g_xserver_be)          if (g_compatible_arch)
676          {          {
677                  while (out < end)                  while (out < end)
678                  {                  {
679                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
680                          *(out++) = value >> 16;                          BOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
681                  }                  }
682          }          }
683          else          else
# Line 281  translate8to24(uint8 * data, uint8 * out Line 685  translate8to24(uint8 * data, uint8 * out
685                  while (out < end)                  while (out < end)
686                  {                  {
687                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
688                          *(out++) = value;                          LOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
689                  }                  }
690          }          }
691  }  }
692    
693  static void  static void
694  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
695  {  {
696          uint32 value;          uint32 value;
697    
698          if (g_xserver_be)          if (g_compatible_arch)
699            {
700                    /* *INDENT-OFF* */
701                    REPEAT4
702                    (
703                            *((uint32 *) out) = g_colmap[*(data++)];
704                            out += 4;
705                    )
706                    /* *INDENT-ON* */
707            }
708            else if (g_xserver_be)
709          {          {
710                  while (out < end)                  while (out < end)
711                  {                  {
712                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
713                          *(out++) = value >> 24;                          BOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 8;  
                         *(out++) = value;  
714                  }                  }
715          }          }
716          else          else
# Line 309  translate8to32(uint8 * data, uint8 * out Line 718  translate8to32(uint8 * data, uint8 * out
718                  while (out < end)                  while (out < end)
719                  {                  {
720                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
721                          *(out++) = value;                          LOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
722                  }                  }
723          }          }
724  }  }
725    
726  static void  static void
727  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
728  {  {
729          uint16 pixel;          uint16 pixel;
730          uint16 value;          uint16 value;
731            PixelColour pc;
732    
733          while (out < end)          if (g_xserver_be)
734          {          {
735                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                         BSWAP16(pixel);  
                 }  
   
                 value = make_colour(split_colour15(pixel));  
   
                 if (g_xserver_be)  
736                  {                  {
737                          *(out++) = value >> 8;                          pixel = *(data++);
738                          *(out++) = value;                          if (g_host_be)
739                            {
740                                    BSWAP16(pixel);
741                            }
742                            SPLITCOLOUR15(pixel, pc);
743                            value = MAKECOLOUR(pc);
744                            BOUT16(out, value);
745                  }                  }
746                  else          }
747            else
748            {
749                    while (out < end)
750                  {                  {
751                          *(out++) = value;                          pixel = *(data++);
752                          *(out++) = value >> 8;                          if (g_host_be)
753                            {
754                                    BSWAP16(pixel);
755                            }
756                            SPLITCOLOUR15(pixel, pc);
757                            value = MAKECOLOUR(pc);
758                            LOUT16(out, value);
759                  }                  }
760          }          }
761  }  }
762    
763  static void  static void
764  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
765  {  {
766          uint32 value;          uint32 value;
767          uint16 pixel;          uint16 pixel;
768            PixelColour pc;
769    
770          while (out < end)          if (g_compatible_arch)
771          {          {
772                  pixel = *(data++);                  /* *INDENT-OFF* */
773                    REPEAT3
774                  if (g_host_be)                  (
775                  {                          pixel = *(data++);
776                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
777                  }                          *(out++) = pc.blue;
778                            *(out++) = pc.green;
779                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
780                  if (g_xserver_be)                  )
781                    /* *INDENT-ON* */
782            }
783            else if (g_xserver_be)
784            {
785                    while (out < end)
786                  {                  {
787                          *(out++) = value >> 16;                          pixel = *(data++);
788                          *(out++) = value >> 8;                          if (g_host_be)
789                          *(out++) = value;                          {
790                                    BSWAP16(pixel);
791                            }
792                            SPLITCOLOUR15(pixel, pc);
793                            value = MAKECOLOUR(pc);
794                            BOUT24(out, value);
795                  }                  }
796                  else          }
797            else
798            {
799                    while (out < end)
800                  {                  {
801                          *(out++) = value;                          pixel = *(data++);
802                          *(out++) = value >> 8;                          if (g_host_be)
803                          *(out++) = value >> 16;                          {
804                                    BSWAP16(pixel);
805                            }
806                            SPLITCOLOUR15(pixel, pc);
807                            value = MAKECOLOUR(pc);
808                            LOUT24(out, value);
809                  }                  }
810          }          }
811  }  }
812    
813  static void  static void
814  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
815  {  {
816          uint16 pixel;          uint16 pixel;
817          uint32 value;          uint32 value;
818            PixelColour pc;
819    
820          while (out < end)          if (g_compatible_arch)
821          {          {
822                  pixel = *(data++);                  /* *INDENT-OFF* */
823                    REPEAT4
824                  if (g_host_be)                  (
825                  {                          pixel = *(data++);
826                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
827                  }                          *(out++) = pc.blue;
828                            *(out++) = pc.green;
829                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
830                            *(out++) = 0;
831                  if (g_xserver_be)                  )
832                    /* *INDENT-ON* */
833            }
834            else if (g_xserver_be)
835            {
836                    while (out < end)
837                  {                  {
838                          *(out++) = value >> 24;                          pixel = *(data++);
839                          *(out++) = value >> 16;                          if (g_host_be)
840                          *(out++) = value >> 8;                          {
841                          *(out++) = value;                                  BSWAP16(pixel);
842                            }
843                            SPLITCOLOUR15(pixel, pc);
844                            value = MAKECOLOUR(pc);
845                            BOUT32(out, value);
846                  }                  }
847                  else          }
848            else
849            {
850                    while (out < end)
851                  {                  {
852                          *(out++) = value;                          pixel = *(data++);
853                          *(out++) = value >> 8;                          if (g_host_be)
854                          *(out++) = value >> 16;                          {
855                          *(out++) = value >> 24;                                  BSWAP16(pixel);
856                            }
857                            SPLITCOLOUR15(pixel, pc);
858                            value = MAKECOLOUR(pc);
859                            LOUT32(out, value);
860                  }                  }
861          }          }
862  }  }
863    
864  static void  static void
865  translate16to16(uint16 * data, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
866  {  {
867          uint16 pixel;          uint16 pixel;
868          uint16 value;          uint16 value;
869            PixelColour pc;
870    
871          while (out < end)          if (g_xserver_be)
872          {          {
                 pixel = *(data++);  
   
873                  if (g_host_be)                  if (g_host_be)
874                  {                  {
875                          BSWAP16(pixel);                          while (out < end)
876                            {
877                                    pixel = *(data++);
878                                    BSWAP16(pixel);
879                                    SPLITCOLOUR16(pixel, pc);
880                                    value = MAKECOLOUR(pc);
881                                    BOUT16(out, value);
882                            }
883                  }                  }
884                    else
885                  value = make_colour(split_colour16(pixel));                  {
886                            while (out < end)
887                  if (g_xserver_be)                          {
888                                    pixel = *(data++);
889                                    SPLITCOLOUR16(pixel, pc);
890                                    value = MAKECOLOUR(pc);
891                                    BOUT16(out, value);
892                            }
893                    }
894            }
895            else
896            {
897                    if (g_host_be)
898                  {                  {
899                          *(out++) = value >> 8;                          while (out < end)
900                          *(out++) = value;                          {
901                                    pixel = *(data++);
902                                    BSWAP16(pixel);
903                                    SPLITCOLOUR16(pixel, pc);
904                                    value = MAKECOLOUR(pc);
905                                    LOUT16(out, value);
906                            }
907                  }                  }
908                  else                  else
909                  {                  {
910                          *(out++) = value;                          while (out < end)
911                          *(out++) = value >> 8;                          {
912                                    pixel = *(data++);
913                                    SPLITCOLOUR16(pixel, pc);
914                                    value = MAKECOLOUR(pc);
915                                    LOUT16(out, value);
916                            }
917                  }                  }
918          }          }
919  }  }
920    
921  static void  static void
922  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
923  {  {
924          uint32 value;          uint32 value;
925          uint16 pixel;          uint16 pixel;
926            PixelColour pc;
927    
928          while (out < end)          if (g_compatible_arch)
929            {
930                    /* *INDENT-OFF* */
931                    REPEAT3
932                    (
933                            pixel = *(data++);
934                            SPLITCOLOUR16(pixel, pc);
935                            *(out++) = pc.blue;
936                            *(out++) = pc.green;
937                            *(out++) = pc.red;
938                    )
939                    /* *INDENT-ON* */
940            }
941            else if (g_xserver_be)
942          {          {
                 pixel = *(data++);  
   
943                  if (g_host_be)                  if (g_host_be)
944                  {                  {
945                          BSWAP16(pixel);                          while (out < end)
946                            {
947                                    pixel = *(data++);
948                                    BSWAP16(pixel);
949                                    SPLITCOLOUR16(pixel, pc);
950                                    value = MAKECOLOUR(pc);
951                                    BOUT24(out, value);
952                            }
953                  }                  }
954                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
955                  {                  {
956                          *(out++) = value >> 16;                          while (out < end)
957                          *(out++) = value >> 8;                          {
958                          *(out++) = value;                                  pixel = *(data++);
959                                    SPLITCOLOUR16(pixel, pc);
960                                    value = MAKECOLOUR(pc);
961                                    BOUT24(out, value);
962                            }
963                    }
964            }
965            else
966            {
967                    if (g_host_be)
968                    {
969                            while (out < end)
970                            {
971                                    pixel = *(data++);
972                                    BSWAP16(pixel);
973                                    SPLITCOLOUR16(pixel, pc);
974                                    value = MAKECOLOUR(pc);
975                                    LOUT24(out, value);
976                            }
977                  }                  }
978                  else                  else
979                  {                  {
980                          *(out++) = value;                          while (out < end)
981                          *(out++) = value >> 8;                          {
982                          *(out++) = value >> 16;                                  pixel = *(data++);
983                                    SPLITCOLOUR16(pixel, pc);
984                                    value = MAKECOLOUR(pc);
985                                    LOUT24(out, value);
986                            }
987                  }                  }
988          }          }
989  }  }
990    
991  static void  static void
992  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
993  {  {
994          uint16 pixel;          uint16 pixel;
995          uint32 value;          uint32 value;
996            PixelColour pc;
997    
998          while (out < end)          if (g_compatible_arch)
999            {
1000                    /* *INDENT-OFF* */
1001                    REPEAT4
1002                    (
1003                            pixel = *(data++);
1004                            SPLITCOLOUR16(pixel, pc);
1005                            *(out++) = pc.blue;
1006                            *(out++) = pc.green;
1007                            *(out++) = pc.red;
1008                            *(out++) = 0;
1009                    )
1010                    /* *INDENT-ON* */
1011            }
1012            else if (g_xserver_be)
1013          {          {
                 pixel = *(data++);  
   
1014                  if (g_host_be)                  if (g_host_be)
1015                  {                  {
1016                          BSWAP16(pixel);                          while (out < end)
1017                            {
1018                                    pixel = *(data++);
1019                                    BSWAP16(pixel);
1020                                    SPLITCOLOUR16(pixel, pc);
1021                                    value = MAKECOLOUR(pc);
1022                                    BOUT32(out, value);
1023                            }
1024                  }                  }
1025                    else
1026                  value = make_colour(split_colour16(pixel));                  {
1027                            while (out < end)
1028                  if (g_xserver_be)                          {
1029                                    pixel = *(data++);
1030                                    SPLITCOLOUR16(pixel, pc);
1031                                    value = MAKECOLOUR(pc);
1032                                    BOUT32(out, value);
1033                            }
1034                    }
1035            }
1036            else
1037            {
1038                    if (g_host_be)
1039                  {                  {
1040                          *(out++) = value >> 24;                          while (out < end)
1041                          *(out++) = value >> 16;                          {
1042                          *(out++) = value >> 8;                                  pixel = *(data++);
1043                          *(out++) = value;                                  BSWAP16(pixel);
1044                                    SPLITCOLOUR16(pixel, pc);
1045                                    value = MAKECOLOUR(pc);
1046                                    LOUT32(out, value);
1047                            }
1048                  }                  }
1049                  else                  else
1050                  {                  {
1051                          *(out++) = value;                          while (out < end)
1052                          *(out++) = value >> 8;                          {
1053                          *(out++) = value >> 16;                                  pixel = *(data++);
1054                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
1055                                    value = MAKECOLOUR(pc);
1056                                    LOUT32(out, value);
1057                            }
1058                  }                  }
1059          }          }
1060  }  }
1061    
1062  static void  static void
1063  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1064  {  {
1065          uint32 pixel = 0;          uint32 pixel = 0;
1066          uint16 value;          uint16 value;
1067            PixelColour pc;
1068    
1069          while (out < end)          while (out < end)
1070          {          {
1071                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
1072                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
1073                  pixel |= *(data++);                  pixel |= *(data++);
1074                    SPLITCOLOUR24(pixel, pc);
1075                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
1076                  if (g_xserver_be)                  if (g_xserver_be)
1077                  {                  {
1078                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
1079                  }                  }
1080                  else                  else
1081                  {                  {
1082                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
1083                  }                  }
1084          }          }
1085  }  }
1086    
1087  static void  static void
1088  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1089  {  {
1090          uint32 pixel;          uint32 pixel;
1091          uint32 value;          uint32 value;
1092            PixelColour pc;
1093    
1094          while (out < end)          if (g_xserver_be)
1095          {          {
1096                  pixel = *(data++) << 16;                  while (out < end)
                 pixel |= *(data++) << 8;  
                 pixel |= *(data++);  
   
                 value = make_colour(split_colour24(pixel));  
   
                 if (g_xserver_be)  
1097                  {                  {
1098                          *(out++) = value >> 16;                          pixel = *(data++) << 16;
1099                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1100                          *(out++) = value;                          pixel |= *(data++);
1101                            SPLITCOLOUR24(pixel, pc);
1102                            value = MAKECOLOUR(pc);
1103                            BOUT24(out, value);
1104                  }                  }
1105                  else          }
1106            else
1107            {
1108                    while (out < end)
1109                  {                  {
1110                          *(out++) = value;                          pixel = *(data++) << 16;
1111                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1112                          *(out++) = value >> 16;                          pixel |= *(data++);
1113                            SPLITCOLOUR24(pixel, pc);
1114                            value = MAKECOLOUR(pc);
1115                            LOUT24(out, value);
1116                  }                  }
1117          }          }
1118  }  }
1119    
1120  static void  static void
1121  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1122  {  {
1123          uint32 pixel;          uint32 pixel;
1124          uint32 value;          uint32 value;
1125            PixelColour pc;
1126    
1127          while (out < end)          if (g_compatible_arch)
1128          {          {
1129                  pixel = *(data++) << 16;                  /* *INDENT-OFF* */
1130                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
1131                  pixel |= *(data++);                  REPEAT4
1132                    (
1133                  value = make_colour(split_colour24(pixel));                          *(out++) = *(data++);
1134                            *(out++) = *(data++);
1135                  if (g_xserver_be)                          *(out++) = *(data++);
1136                            *(out++) = 0;
1137                    )
1138    #else
1139                    REPEAT4
1140                    (
1141                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1142                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1143                     out += 4;
1144                     data += 3;
1145                    )
1146    #endif
1147                    /* *INDENT-ON* */
1148            }
1149            else if (g_xserver_be)
1150            {
1151                    while (out < end)
1152                  {                  {
1153                          *(out++) = value >> 24;                          pixel = *(data++) << 16;
1154                          *(out++) = value >> 16;                          pixel |= *(data++) << 8;
1155                          *(out++) = value >> 8;                          pixel |= *(data++);
1156                          *(out++) = value;                          SPLITCOLOUR24(pixel, pc);
1157                            value = MAKECOLOUR(pc);
1158                            BOUT32(out, value);
1159                  }                  }
1160                  else          }
1161            else
1162            {
1163                    while (out < end)
1164                  {                  {
1165                          *(out++) = value;                          pixel = *(data++) << 16;
1166                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1167                          *(out++) = value >> 16;                          pixel |= *(data++);
1168                          *(out++) = value >> 24;                          SPLITCOLOUR24(pixel, pc);
1169                            value = MAKECOLOUR(pc);
1170                            LOUT32(out, value);
1171                  }                  }
1172          }          }
1173  }  }
# Line 597  translate24to32(uint8 * data, uint8 * ou Line 1175  translate24to32(uint8 * data, uint8 * ou
1175  static uint8 *  static uint8 *
1176  translate_image(int width, int height, uint8 * data)  translate_image(int width, int height, uint8 * data)
1177  {  {
1178          int size = width * height * g_bpp / 8;          int size;
1179          uint8 *out = (uint8 *) xmalloc(size);          uint8 *out;
1180          uint8 *end = out + size;          uint8 *end;
1181    
1182            /*
1183               If RDP depth and X Visual depths match,
1184               and arch(endian) matches, no need to translate:
1185               just return data.
1186               Note: select_visual should've already ensured g_no_translate
1187               is only set for compatible depths, but the RDP depth might've
1188               changed during connection negotiations.
1189             */
1190            if (g_no_translate_image)
1191            {
1192                    if ((g_depth == 15 && g_server_depth == 15) ||
1193                        (g_depth == 16 && g_server_depth == 16) ||
1194                        (g_depth == 24 && g_server_depth == 24))
1195                            return data;
1196            }
1197    
1198            size = width * height * (g_bpp / 8);
1199            out = (uint8 *) xmalloc(size);
1200            end = out + size;
1201    
1202          switch (g_server_bpp)          switch (g_server_depth)
1203          {          {
1204                  case 24:                  case 24:
1205                          switch (g_bpp)                          switch (g_bpp)
# Line 699  calculate_shifts(uint32 mask, int *shift Line 1297  calculate_shifts(uint32 mask, int *shift
1297          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1298  }  }
1299    
1300  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1301  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1302     */
1303    static unsigned
1304    calculate_mask_weight(uint32 mask)
1305    {
1306            unsigned weight = 0;
1307            do
1308            {
1309                    weight += (mask & 1);
1310            }
1311            while (mask >>= 1);
1312            return weight;
1313    }
1314    
1315    static BOOL
1316    select_visual(int screen_num)
1317  {  {
         XVisualInfo vi;  
1318          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1319          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1320          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1321          XVisualInfo template;          XVisualInfo template;
1322          Bool TrueColorVisual = False;          int i;
1323            unsigned red_weight, blue_weight, green_weight;
1324    
1325          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1326          if (g_display == NULL)  
1327            if (g_server_depth == -1)
1328          {          {
1329                  error("Failed to open display: %s\n", XDisplayName(NULL));                  g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
                 return False;  
1330          }          }
1331    
1332          screen_num = DefaultScreen(g_display);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1333          g_x_socket = ConnectionNumber(g_display);          if (pfm == NULL)
1334          g_screen = ScreenOfDisplay(g_display, screen_num);          {
1335          g_depth = DefaultDepthOfScreen(g_screen);                  error("Unable to get list of pixmap formats from display.\n");
1336                    XCloseDisplay(g_display);
1337                    return False;
1338            }
1339    
1340          /* Search for best TrueColor depth */          /* Search for best TrueColor visual */
1341          template.class = TrueColor;          template.class = TrueColor;
1342          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          template.screen = screen_num;
1343            vmatches =
1344                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1345                                   &visuals_count);
1346            g_visual = NULL;
1347            g_no_translate_image = False;
1348            g_compatible_arch = False;
1349            if (vmatches != NULL)
1350            {
1351                    for (i = 0; i < visuals_count; ++i)
1352                    {
1353                            XVisualInfo *visual_info = &vmatches[i];
1354                            BOOL can_translate_to_bpp = False;
1355                            int j;
1356    
1357                            /* Try to find a no-translation visual that'll
1358                               allow us to use RDP bitmaps directly as ZPixmaps. */
1359                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1360                                                   /* R5G5B5 */
1361                                                   (visual_info->red_mask == 0x7c00) &&
1362                                                   (visual_info->green_mask == 0x3e0) &&
1363                                                   (visual_info->blue_mask == 0x1f)) ||
1364                                                  ((visual_info->depth == 16) &&
1365                                                   /* R5G6B5 */
1366                                                   (visual_info->red_mask == 0xf800) &&
1367                                                   (visual_info->green_mask == 0x7e0) &&
1368                                                   (visual_info->blue_mask == 0x1f)) ||
1369                                                  ((visual_info->depth == 24) &&
1370                                                   /* R8G8B8 */
1371                                                   (visual_info->red_mask == 0xff0000) &&
1372                                                   (visual_info->green_mask == 0xff00) &&
1373                                                   (visual_info->blue_mask == 0xff))))
1374                            {
1375                                    g_visual = visual_info->visual;
1376                                    g_depth = visual_info->depth;
1377                                    g_compatible_arch = !g_host_be;
1378                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1379                                    if (g_no_translate_image)
1380                                            /* We found the best visual */
1381                                            break;
1382                            }
1383                            else
1384                            {
1385                                    g_compatible_arch = False;
1386                            }
1387    
1388          nvisuals--;                          if (visual_info->depth > 24)
1389          while (nvisuals >= 0)                          {
1390          {                                  /* Avoid 32-bit visuals and likes like the plague.
1391                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1392                  {                                     (e.g. nvidia's Composite 32-bit visual).
1393                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1394                                    continue;
1395                            }
1396    
1397                            /* Only care for visuals, for whose BPPs (not depths!)
1398                               we have a translateXtoY function. */
1399                            for (j = 0; j < pixmap_formats_count; ++j)
1400                            {
1401                                    if (pfm[j].depth == visual_info->depth)
1402                                    {
1403                                            if ((pfm[j].bits_per_pixel == 16) ||
1404                                                (pfm[j].bits_per_pixel == 24) ||
1405                                                (pfm[j].bits_per_pixel == 32))
1406                                            {
1407                                                    can_translate_to_bpp = True;
1408                                            }
1409                                            break;
1410                                    }
1411                            }
1412    
1413                            /* Prefer formats which have the most colour depth.
1414                               We're being truly aristocratic here, minding each
1415                               weight on its own. */
1416                            if (can_translate_to_bpp)
1417                            {
1418                                    unsigned vis_red_weight =
1419                                            calculate_mask_weight(visual_info->red_mask);
1420                                    unsigned vis_green_weight =
1421                                            calculate_mask_weight(visual_info->green_mask);
1422                                    unsigned vis_blue_weight =
1423                                            calculate_mask_weight(visual_info->blue_mask);
1424                                    if ((vis_red_weight >= red_weight)
1425                                        && (vis_green_weight >= green_weight)
1426                                        && (vis_blue_weight >= blue_weight))
1427                                    {
1428                                            red_weight = vis_red_weight;
1429                                            green_weight = vis_green_weight;
1430                                            blue_weight = vis_blue_weight;
1431                                            g_visual = visual_info->visual;
1432                                            g_depth = visual_info->depth;
1433                                    }
1434                            }
1435                  }                  }
1436                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1437          }          }
1438    
1439          if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))          if (g_visual != NULL)
1440          {          {
1441                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1442                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1443                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1444                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
                 /* Do not allocate colours on a TrueColor visual */  
                 if (g_visual->class == TrueColor)  
                 {  
                         g_owncolmap = False;  
                 }  
1445          }          }
1446          else          else
1447          {          {
1448                  /* need a truecolour visual */                  template.class = PseudoColor;
1449                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1450                  {                  template.colormap_size = 256;
1451                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1452                            XGetVisualInfo(g_display,
1453                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1454                                           &template, &visuals_count);
1455                    if (vmatches == NULL)
1456                    {
1457                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1458                            XCloseDisplay(g_display);
1459                            XFree(pfm);
1460                          return False;                          return False;
1461                  }                  }
1462    
1463                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1464                  g_owncolmap = False;                  g_owncolmap = True;
1465                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1466                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
                 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);  
1467          }          }
1468    
1469          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1470          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1471          {          {
1472                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1473                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1474                  {                  {
1475                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1476    
1477                            if (g_no_translate_image)
1478                          {                          {
1479                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1480                                    {
1481                                            case 15:
1482                                            case 16:
1483                                                    if (g_bpp != 16)
1484                                                            g_no_translate_image = False;
1485                                                    break;
1486                                            case 24:
1487                                                    /* Yes, this will force image translation
1488                                                       on most modern servers which use 32 bits
1489                                                       for R8G8B8. */
1490                                                    if (g_bpp != 24)
1491                                                            g_no_translate_image = False;
1492                                                    break;
1493                                            default:
1494                                                    g_no_translate_image = False;
1495                                                    break;
1496                                    }
1497                          }                          }
1498    
1499                            /* Pixmap formats list is a depth-to-bpp mapping --
1500                               there's just a single entry for every depth,
1501                               so we can safely break here */
1502                            break;
1503                  }                  }
                 XFree(pfm);  
1504          }          }
1505            XFree(pfm);
1506            pfm = NULL;
1507            return True;
1508    }
1509    
1510          if (g_bpp < 8)  static XErrorHandler g_old_error_handler;
1511    
1512    static int
1513    error_handler(Display * dpy, XErrorEvent * eev)
1514    {
1515            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1516          {          {
1517                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1518                  XCloseDisplay(g_display);                  fprintf(stderr,
1519                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1520                    return 0;
1521            }
1522    
1523            return g_old_error_handler(dpy, eev);
1524    }
1525    
1526    BOOL
1527    ui_init(void)
1528    {
1529            int screen_num;
1530    
1531            g_display = XOpenDisplay(NULL);
1532            if (g_display == NULL)
1533            {
1534                    error("Failed to open display: %s\n", XDisplayName(NULL));
1535                    return False;
1536            }
1537    
1538            {
1539                    uint16 endianess_test = 1;
1540                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1541            }
1542    
1543            g_old_error_handler = XSetErrorHandler(error_handler);
1544            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1545            screen_num = DefaultScreen(g_display);
1546            g_x_socket = ConnectionNumber(g_display);
1547            g_screen = ScreenOfDisplay(g_display, screen_num);
1548            g_depth = DefaultDepthOfScreen(g_screen);
1549    
1550            if (!select_visual(screen_num))
1551                  return False;                  return False;
1552    
1553            if (g_no_translate_image)
1554            {
1555                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1556          }          }
1557    
1558            if (g_server_depth > g_bpp)
1559            {
1560                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1561                            g_server_depth, g_bpp);
1562            }
1563    
1564            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1565                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1566    
1567          if (!g_owncolmap)          if (!g_owncolmap)
1568          {          {
1569                  g_xcolmap =                  g_xcolmap =
1570                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1571                                          AllocNone);                                          AllocNone);
1572                  if (g_depth <= 8)                  if (g_depth <= 8)
1573                          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);
1574          }          }
1575    
1576          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1577          {          {
1578                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1579                  g_ownbackstore = True;                  g_ownbackstore = True;
1580          }          }
1581    
         test = 1;  
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
1582          /*          /*
1583           * Determine desktop size           * Determine desktop size
1584           */           */
# Line 813  ui_init(void) Line 1586  ui_init(void)
1586          {          {
1587                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1588                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1589                    g_using_full_workarea = True;
1590          }          }
1591          else if (g_width < 0)          else if (g_width < 0)
1592          {          {
1593                  /* Percent of screen */                  /* Percent of screen */
1594                    if (-g_width >= 100)
1595                            g_using_full_workarea = True;
1596                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1597                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1598          }          }
# Line 824  ui_init(void) Line 1600  ui_init(void)
1600          {          {
1601                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1602                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1603                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1604                  {                  {
1605                          g_width = cx;                          g_width = cx;
1606                          g_height = cy;                          g_height = cy;
1607                            g_using_full_workarea = True;
1608                  }                  }
1609                  else                  else
1610                  {                  {
1611                          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");
1612                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1613                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1614                  }                  }
1615          }          }
1616    
# Line 849  ui_init(void) Line 1625  ui_init(void)
1625                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1626    
1627          xclip_init();          xclip_init();
1628            ewmh_init();
1629            if (g_seamless_rdp)
1630                    seamless_init();
1631    
1632          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));
1633    
1634          return True;          return True;
1635  }  }
# Line 858  ui_init(void) Line 1637  ui_init(void)
1637  void  void
1638  ui_deinit(void)  ui_deinit(void)
1639  {  {
1640            while (g_seamless_windows)
1641            {
1642                    XDestroyWindow(g_display, g_seamless_windows->wnd);
1643                    sw_remove_window(g_seamless_windows);
1644            }
1645    
1646            xclip_deinit();
1647    
1648          if (g_IM != NULL)          if (g_IM != NULL)
1649                  XCloseIM(g_IM);                  XCloseIM(g_IM);
1650    
# Line 874  ui_deinit(void) Line 1661  ui_deinit(void)
1661          g_display = NULL;          g_display = NULL;
1662  }  }
1663    
1664    
1665    static void
1666    get_window_attribs(XSetWindowAttributes * attribs)
1667    {
1668            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1669            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1670            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1671            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1672            attribs->override_redirect = g_fullscreen;
1673            attribs->colormap = g_xcolmap;
1674    }
1675    
1676    static void
1677    get_input_mask(long *input_mask)
1678    {
1679            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1680                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1681    
1682            if (g_sendmotion)
1683                    *input_mask |= PointerMotionMask;
1684            if (g_ownbackstore)
1685                    *input_mask |= ExposureMask;
1686            if (g_fullscreen || g_grab_keyboard)
1687                    *input_mask |= EnterWindowMask;
1688            if (g_grab_keyboard)
1689                    *input_mask |= LeaveWindowMask;
1690    }
1691    
1692  BOOL  BOOL
1693  ui_create_window(void)  ui_create_window(void)
1694  {  {
1695          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1696          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1697    
1698          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1699          XClassHint *classhints;          XClassHint *classhints;
1700          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 889  ui_create_window(void) Line 1705  ui_create_window(void)
1705          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1706          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1707    
1708          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1709          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1710          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1711          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1712          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1713    
1714          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,          get_window_attribs(&attribs);
1715                                0, g_depth, InputOutput, g_visual,  
1716                                CWBackPixel | CWBackingStore | CWOverrideRedirect |          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1717                                CWColormap | CWBorderPixel, &attribs);                                wndheight, 0, g_depth, InputOutput, g_visual,
1718                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1719                                  CWBorderPixel, &attribs);
1720    
1721          if (g_gc == NULL)          if (g_gc == NULL)
1722            {
1723                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1724                    ui_reset_clip();
1725            }
1726    
1727            if (g_create_bitmap_gc == NULL)
1728                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1729    
1730          if ((g_ownbackstore) && (g_backstore == 0))          if ((g_ownbackstore) && (g_backstore == 0))
1731          {          {
# Line 915  ui_create_window(void) Line 1739  ui_create_window(void)
1739          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1740    
1741          if (g_hide_decorations)          if (g_hide_decorations)
1742                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1743    
1744          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1745          if (classhints != NULL)          if (classhints != NULL)
# Line 929  ui_create_window(void) Line 1753  ui_create_window(void)
1753          if (sizehints)          if (sizehints)
1754          {          {
1755                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1756                    if (g_pos)
1757                            sizehints->flags |= PPosition;
1758                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1759                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1760                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
1761                  XFree(sizehints);                  XFree(sizehints);
1762          }          }
1763    
1764          if ( g_embed_wnd )          if (g_embed_wnd)
1765          {          {
1766                  XReparentWindow(g_display, g_wnd, (Window)g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1767          }          }
   
         input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |  
                 VisibilityChangeMask | FocusChangeMask;  
1768    
1769          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;  
1770    
1771          if (g_IM != NULL)          if (g_IM != NULL)
1772          {          {
# Line 971  ui_create_window(void) Line 1787  ui_create_window(void)
1787                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1788          }          }
1789          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1790            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1791    
1792          g_focused = False;          g_focused = False;
1793          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 988  ui_create_window(void) Line 1805  ui_create_window(void)
1805  }  }
1806    
1807  void  void
1808    ui_resize_window()
1809    {
1810            XSizeHints *sizehints;
1811            Pixmap bs;
1812    
1813            sizehints = XAllocSizeHints();
1814            if (sizehints)
1815            {
1816                    sizehints->flags = PMinSize | PMaxSize;
1817                    sizehints->min_width = sizehints->max_width = g_width;
1818                    sizehints->min_height = sizehints->max_height = g_height;
1819                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1820                    XFree(sizehints);
1821            }
1822    
1823            if (!(g_fullscreen || g_embed_wnd))
1824            {
1825                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1826            }
1827    
1828            /* create new backstore pixmap */
1829            if (g_backstore != 0)
1830            {
1831                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1832                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1833                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1834                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1835                    XFreePixmap(g_display, g_backstore);
1836                    g_backstore = bs;
1837            }
1838    }
1839    
1840    void
1841  ui_destroy_window(void)  ui_destroy_window(void)
1842  {  {
1843          if (g_IC != NULL)          if (g_IC != NULL)
# Line 1001  xwin_toggle_fullscreen(void) Line 1851  xwin_toggle_fullscreen(void)
1851  {  {
1852          Pixmap contents = 0;          Pixmap contents = 0;
1853    
1854            if (g_seamless_active)
1855                    /* Turn off SeamlessRDP mode */
1856                    ui_seamless_toggle();
1857    
1858          if (!g_ownbackstore)          if (!g_ownbackstore)
1859          {          {
1860                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1021  xwin_toggle_fullscreen(void) Line 1875  xwin_toggle_fullscreen(void)
1875          }          }
1876  }  }
1877    
1878  /* Process all events in Xlib queue  static void
1879    handle_button_event(XEvent xevent, BOOL down)
1880    {
1881            uint16 button, flags = 0;
1882            g_last_gesturetime = xevent.xbutton.time;
1883            button = xkeymap_translate_button(xevent.xbutton.button);
1884            if (button == 0)
1885                    return;
1886    
1887            if (down)
1888                    flags = MOUSE_FLAG_DOWN;
1889    
1890            /* Stop moving window when button is released, regardless of cursor position */
1891            if (g_moving_wnd && (xevent.type == ButtonRelease))
1892                    g_moving_wnd = False;
1893    
1894            /* If win_button_size is nonzero, enable single app mode */
1895            if (xevent.xbutton.y < g_win_button_size)
1896            {
1897                    /*  Check from right to left: */
1898                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1899                    {
1900                            /* The close button, continue */
1901                            ;
1902                    }
1903                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1904                    {
1905                            /* The maximize/restore button. Do not send to
1906                               server.  It might be a good idea to change the
1907                               cursor or give some other visible indication
1908                               that rdesktop inhibited this click */
1909                            if (xevent.type == ButtonPress)
1910                                    return;
1911                    }
1912                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1913                    {
1914                            /* The minimize button. Iconify window. */
1915                            if (xevent.type == ButtonRelease)
1916                            {
1917                                    /* Release the mouse button outside the minimize button, to prevent the
1918                                       actual minimazation to happen */
1919                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1920                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1921                                    return;
1922                            }
1923                    }
1924                    else if (xevent.xbutton.x <= g_win_button_size)
1925                    {
1926                            /* The system menu. Ignore. */
1927                            if (xevent.type == ButtonPress)
1928                                    return;
1929                    }
1930                    else
1931                    {
1932                            /* The title bar. */
1933                            if (xevent.type == ButtonPress)
1934                            {
1935                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1936                                    {
1937                                            g_moving_wnd = True;
1938                                            g_move_x_offset = xevent.xbutton.x;
1939                                            g_move_y_offset = xevent.xbutton.y;
1940                                    }
1941                                    return;
1942                            }
1943                    }
1944            }
1945    
1946            if (xevent.xmotion.window == g_wnd)
1947            {
1948                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1949                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1950            }
1951            else
1952            {
1953                    /* SeamlessRDP */
1954                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1955                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1956            }
1957    }
1958    
1959    
1960    /* Process events in Xlib queue
1961     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1962  static int  static int
1963  xwin_process_events(void)  xwin_process_events(void)
1964  {  {
1965          XEvent xevent;          XEvent xevent;
1966          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1967          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1968          char str[256];          char str[256];
1969          Status status;          Status status;
1970            int events = 0;
1971            seamless_window *sw;
1972    
1973          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1974          {          {
1975                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1976    
# Line 1044  xwin_process_events(void) Line 1980  xwin_process_events(void)
1980                          continue;                          continue;
1981                  }                  }
1982    
                 flags = 0;  
   
1983                  switch (xevent.type)                  switch (xevent.type)
1984                  {                  {
1985                            case VisibilityNotify:
1986                                    if (xevent.xvisibility.window == g_wnd)
1987                                            g_Unobscured =
1988                                                    xevent.xvisibility.state == VisibilityUnobscured;
1989    
1990                                    break;
1991                          case ClientMessage:                          case ClientMessage:
1992                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
1993                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 1079  xwin_process_events(void) Line 2019  xwin_process_events(void)
2019                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
2020                                  }                                  }
2021    
2022                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2023                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2024    
2025                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2026                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2027                                          break;                                          break;
2028    
2029                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2030                                                             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);  
   
2031                                  break;                                  break;
2032    
2033                          case KeyRelease:                          case KeyRelease:
# Line 1104  xwin_process_events(void) Line 2035  xwin_process_events(void)
2035                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
2036                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
2037    
2038                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2039                                             get_ksname(keysym)));                                             get_ksname(keysym)));
2040    
2041                                  ev_time = time(NULL);                                  ev_time = time(NULL);
2042                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2043                                          break;                                          break;
2044    
2045                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2046                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
2047                                  break;                                  break;
2048    
2049                          case ButtonPress:                          case ButtonPress:
2050                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
2051                                  /* fall through */                                  break;
2052    
2053                          case ButtonRelease:                          case ButtonRelease:
2054                                  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);  
2055                                  break;                                  break;
2056    
2057                          case MotionNotify:                          case MotionNotify:
# Line 1197  xwin_process_events(void) Line 2066  xwin_process_events(void)
2066                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
2067                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2068                                                         CurrentTime);                                                         CurrentTime);
2069                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
2070                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
2071                                    {
2072                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2073                                                           xevent.xmotion.x, xevent.xmotion.y);
2074                                    }
2075                                    else
2076                                    {
2077                                            /* SeamlessRDP */
2078                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2079                                                           xevent.xmotion.x_root,
2080                                                           xevent.xmotion.y_root);
2081                                    }
2082                                  break;                                  break;
2083    
2084                          case FocusIn:                          case FocusIn:
# Line 1209  xwin_process_events(void) Line 2089  xwin_process_events(void)
2089                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
2090                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
2091                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
2092    
2093                                    sw = sw_get_window_by_wnd(xevent.xfocus.window);
2094                                    if (!sw)
2095                                            break;
2096    
2097                                    if (sw->id != g_seamless_focused)
2098                                    {
2099                                            seamless_send_focus(sw->id, 0);
2100                                            g_seamless_focused = sw->id;
2101                                    }
2102                                  break;                                  break;
2103    
2104                          case FocusOut:                          case FocusOut:
# Line 1241  xwin_process_events(void) Line 2131  xwin_process_events(void)
2131                                  break;                                  break;
2132    
2133                          case Expose:                          case Expose:
2134                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2135                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2136                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2137                                            xevent.xexpose.height,                                                    g_gc,
2138                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2139                                                      xevent.xexpose.width, xevent.xexpose.height,
2140                                                      xevent.xexpose.x, xevent.xexpose.y);
2141                                    }
2142                                    else
2143                                    {
2144                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2145                                            if (!sw)
2146                                                    break;
2147                                            XCopyArea(g_display, g_backstore,
2148                                                      xevent.xexpose.window, g_gc,
2149                                                      xevent.xexpose.x + sw->xoffset,
2150                                                      xevent.xexpose.y + sw->yoffset,
2151                                                      xevent.xexpose.width,
2152                                                      xevent.xexpose.height, xevent.xexpose.x,
2153                                                      xevent.xexpose.y);
2154                                    }
2155    
2156                                  break;                                  break;
2157    
2158                          case MappingNotify:                          case MappingNotify:
# Line 1274  xwin_process_events(void) Line 2181  xwin_process_events(void)
2181                                  break;                                  break;
2182                          case PropertyNotify:                          case PropertyNotify:
2183                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2184                                    if (xevent.xproperty.window == g_wnd)
2185                                            break;
2186                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2187                                            break;
2188    
2189                                    /* seamless */
2190                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2191                                    if (!sw)
2192                                            break;
2193    
2194                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2195                                        && (xevent.xproperty.state == PropertyNewValue))
2196                                    {
2197                                            sw->state = ewmh_get_window_state(sw->wnd);
2198                                            seamless_send_state(sw->id, sw->state, 0);
2199                                    }
2200    
2201                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2202                                        && (xevent.xproperty.state == PropertyNewValue))
2203                                    {
2204                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2205                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2206                                    }
2207    
2208                                    break;
2209                            case MapNotify:
2210                                    if (!g_seamless_active)
2211                                            rdp_send_client_window_status(1);
2212                                    break;
2213                            case UnmapNotify:
2214                                    if (!g_seamless_active)
2215                                            rdp_send_client_window_status(0);
2216                                    break;
2217                            case ConfigureNotify:
2218                                    if (!g_seamless_active)
2219                                            break;
2220    
2221                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2222                                    if (!sw)
2223                                            break;
2224    
2225                                    gettimeofday(sw->position_timer, NULL);
2226                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2227                                        1000000)
2228                                    {
2229                                            sw->position_timer->tv_usec +=
2230                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2231                                            sw->position_timer->tv_sec += 1;
2232                                    }
2233                                    else
2234                                    {
2235                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2236                                    }
2237    
2238                                    sw_handle_restack(sw);
2239                                  break;                                  break;
2240                  }                  }
2241          }          }
# Line 1298  ui_select(int rdp_socket) Line 2260  ui_select(int rdp_socket)
2260                          /* User quit */                          /* User quit */
2261                          return 0;                          return 0;
2262    
2263                    if (g_seamless_active)
2264                            sw_check_timers();
2265    
2266                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2267                  FD_ZERO(&wfds);                  FD_ZERO(&wfds);
2268                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2269                  FD_SET(g_x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2270    
 #ifdef WITH_RDPSND  
                 /* FIXME: there should be an API for registering fds */  
                 if (g_dsp_busy)  
                 {  
                         FD_SET(g_dsp_fd, &wfds);  
                         n = (g_dsp_fd > n) ? g_dsp_fd : n;  
                 }  
 #endif  
2271                  /* default timeout */                  /* default timeout */
2272                  tv.tv_sec = 60;                  tv.tv_sec = 60;
2273                  tv.tv_usec = 0;                  tv.tv_usec = 0;
2274    
2275    #ifdef WITH_RDPSND
2276                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2277    #endif
2278    
2279                  /* add redirection handles */                  /* add redirection handles */
2280                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);                  rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2281                    seamless_select_timeout(&tv);
2282    
2283                  n++;                  n++;
2284    
# Line 1326  ui_select(int rdp_socket) Line 2288  ui_select(int rdp_socket)
2288                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2289    
2290                          case 0:                          case 0:
2291                                  /* TODO: if tv.tv_sec just times out  #ifdef WITH_RDPSND
2292                                   * we will segfault.                                  rdpsnd_check_fds(&rfds, &wfds);
2293                                   * FIXME:  #endif
2294                                   */  
2295                                  //s_timeout = True;                                  /* Abort serial read calls */
2296                                  //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);                                  if (s_timeout)
2297                                            rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2298                                  continue;                                  continue;
2299                  }                  }
2300    
2301    #ifdef WITH_RDPSND
2302                    rdpsnd_check_fds(&rfds, &wfds);
2303    #endif
2304    
2305                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);                  rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2306    
2307                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2308                          return 1;                          return 1;
2309    
 #ifdef WITH_RDPSND  
                 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))  
                         wave_out_play();  
 #endif  
2310          }          }
2311  }  }
2312    
# Line 1361  ui_create_bitmap(int width, int height, Line 2324  ui_create_bitmap(int width, int height,
2324          uint8 *tdata;          uint8 *tdata;
2325          int bitmap_pad;          int bitmap_pad;
2326    
2327          if (g_server_bpp == 8)          if (g_server_depth == 8)
2328          {          {
2329                  bitmap_pad = 8;                  bitmap_pad = 8;
2330          }          }
# Line 1378  ui_create_bitmap(int width, int height, Line 2341  ui_create_bitmap(int width, int height,
2341          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2342                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2343    
2344          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);
2345    
2346          XFree(image);          XFree(image);
2347          if (!g_owncolmap)          if (tdata != data)
2348                  xfree(tdata);                  xfree(tdata);
2349          return (HBITMAP) bitmap;          return (HBITMAP) bitmap;
2350  }  }
# Line 1393  ui_paint_bitmap(int x, int y, int cx, in Line 2356  ui_paint_bitmap(int x, int y, int cx, in
2356          uint8 *tdata;          uint8 *tdata;
2357          int bitmap_pad;          int bitmap_pad;
2358    
2359          if (g_server_bpp == 8)          if (g_server_depth == 8)
2360          {          {
2361                  bitmap_pad = 8;                  bitmap_pad = 8;
2362          }          }
# Line 1413  ui_paint_bitmap(int x, int y, int cx, in Line 2376  ui_paint_bitmap(int x, int y, int cx, in
2376          {          {
2377                  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);
2378                  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);
2379                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2380                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2381                                             x - sw->xoffset, y - sw->yoffset));
2382          }          }
2383          else          else
2384          {          {
2385                  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);
2386                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2387                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2388                                             x - sw->xoffset, y - sw->yoffset));
2389          }          }
2390    
2391          XFree(image);          XFree(image);
2392          if (!g_owncolmap)          if (tdata != data)
2393                  xfree(tdata);                  xfree(tdata);
2394  }  }
2395    
# Line 1436  ui_create_glyph(int width, int height, u Line 2405  ui_create_glyph(int width, int height, u
2405          XImage *image;          XImage *image;
2406          Pixmap bitmap;          Pixmap bitmap;
2407          int scanline;          int scanline;
         GC gc;  
2408    
2409          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2410    
2411          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2412          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2413                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2414    
2415          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2416                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1449  ui_create_glyph(int width, int height, u Line 2418  ui_create_glyph(int width, int height, u
2418          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2419          XInitImage(image);          XInitImage(image);
2420    
2421          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);
2422    
2423          XFree(image);          XFree(image);
         XFreeGC(g_display, gc);  
2424          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2425  }  }
2426    
# Line 1538  ui_set_cursor(HCURSOR cursor) Line 2506  ui_set_cursor(HCURSOR cursor)
2506  {  {
2507          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2508          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2509            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2510  }  }
2511    
2512  void  void
# Line 1679  ui_set_colourmap(HCOLOURMAP map) Line 2648  ui_set_colourmap(HCOLOURMAP map)
2648                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2649          }          }
2650          else          else
2651            {
2652                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2653                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2654            }
2655  }  }
2656    
2657  void  void
2658  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2659  {  {
2660          XRectangle rect;          g_clip_rectangle.x = x;
2661            g_clip_rectangle.y = y;
2662          rect.x = x;          g_clip_rectangle.width = cx;
2663          rect.y = y;          g_clip_rectangle.height = cy;
2664          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);  
2665  }  }
2666    
2667  void  void
2668  ui_reset_clip(void)  ui_reset_clip(void)
2669  {  {
2670          XRectangle rect;          g_clip_rectangle.x = 0;
2671            g_clip_rectangle.y = 0;
2672          rect.x = 0;          g_clip_rectangle.width = g_width;
2673          rect.y = 0;          g_clip_rectangle.height = g_height;
2674          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);  
2675  }  }
2676    
2677  void  void
# Line 1744  ui_patblt(uint8 opcode, Line 2712  ui_patblt(uint8 opcode,
2712          {          {
2713                  case 0: /* Solid */                  case 0: /* Solid */
2714                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2715                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2716                          break;                          break;
2717    
2718                  case 2: /* Hatch */                  case 2: /* Hatch */
# Line 1755  ui_patblt(uint8 opcode, Line 2723  ui_patblt(uint8 opcode,
2723                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2724                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2725                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2726                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2727                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2728                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2729                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1765  ui_patblt(uint8 opcode, Line 2733  ui_patblt(uint8 opcode,
2733                          for (i = 0; i != 8; i++)                          for (i = 0; i != 8; i++)
2734                                  ipattern[7 - i] = brush->pattern[i];                                  ipattern[7 - i] = brush->pattern[i];
2735                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);                          fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
   
2736                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2737                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2738                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2739                          XSetStipple(g_display, g_gc, fill);                          XSetStipple(g_display, g_gc, fill);
2740                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2741                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
                         FILL_RECTANGLE(x, y, cx, cy);  
   
2742                          XSetFillStyle(g_display, g_gc, FillSolid);                          XSetFillStyle(g_display, g_gc, FillSolid);
2743                          XSetTSOrigin(g_display, g_gc, 0, 0);                          XSetTSOrigin(g_display, g_gc, 0, 0);
2744                          ui_destroy_glyph((HGLYPH) fill);                          ui_destroy_glyph((HGLYPH) fill);
# Line 1784  ui_patblt(uint8 opcode, Line 2749  ui_patblt(uint8 opcode,
2749          }          }
2750    
2751          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2752    
2753            if (g_ownbackstore)
2754                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2755            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2756                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2757                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2758  }  }
2759    
2760  void  void
# Line 1794  ui_screenblt(uint8 opcode, Line 2765  ui_screenblt(uint8 opcode,
2765          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2766          if (g_ownbackstore)          if (g_ownbackstore)
2767          {          {
2768                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2769                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2770                  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);
2771          }          }
2772          else          else
2773          {          {
2774                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2775          }          }
2776    
2777            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2778                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2779                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2780    
2781          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2782  }  }
2783    
# Line 1811  ui_memblt(uint8 opcode, Line 2788  ui_memblt(uint8 opcode,
2788  {  {
2789          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2790          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);
2791            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2792                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2793                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2794          if (g_ownbackstore)          if (g_ownbackstore)
2795                  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);
2796          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1857  ui_line(uint8 opcode, Line 2837  ui_line(uint8 opcode,
2837          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2838          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2839          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2840            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2841                                                startx - sw->xoffset, starty - sw->yoffset,
2842                                                endx - sw->xoffset, endy - sw->yoffset));
2843          if (g_ownbackstore)          if (g_ownbackstore)
2844                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2845          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1871  ui_rect( Line 2854  ui_rect(
2854          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2855  }  }
2856    
2857    void
2858    ui_polygon(uint8 opcode,
2859               /* mode */ uint8 fillmode,
2860               /* dest */ POINT * point, int npoints,
2861               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2862    {
2863            uint8 style, i, ipattern[8];
2864            Pixmap fill;
2865    
2866            SET_FUNCTION(opcode);
2867    
2868            switch (fillmode)
2869            {
2870                    case ALTERNATE:
2871                            XSetFillRule(g_display, g_gc, EvenOddRule);
2872                            break;
2873                    case WINDING:
2874                            XSetFillRule(g_display, g_gc, WindingRule);
2875                            break;
2876                    default:
2877                            unimpl("fill mode %d\n", fillmode);
2878            }
2879    
2880            if (brush)
2881                    style = brush->style;
2882            else
2883                    style = 0;
2884    
2885            switch (style)
2886            {
2887                    case 0: /* Solid */
2888                            SET_FOREGROUND(fgcolour);
2889                            FILL_POLYGON((XPoint *) point, npoints);
2890                            break;
2891    
2892                    case 2: /* Hatch */
2893                            fill = (Pixmap) ui_create_glyph(8, 8,
2894                                                            hatch_patterns + brush->pattern[0] * 8);
2895                            SET_FOREGROUND(fgcolour);
2896                            SET_BACKGROUND(bgcolour);
2897                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2898                            XSetStipple(g_display, g_gc, fill);
2899                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2900                            FILL_POLYGON((XPoint *) point, npoints);
2901                            XSetFillStyle(g_display, g_gc, FillSolid);
2902                            XSetTSOrigin(g_display, g_gc, 0, 0);
2903                            ui_destroy_glyph((HGLYPH) fill);
2904                            break;
2905    
2906                    case 3: /* Pattern */
2907                            for (i = 0; i != 8; i++)
2908                                    ipattern[7 - i] = brush->pattern[i];
2909                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2910                            SET_FOREGROUND(bgcolour);
2911                            SET_BACKGROUND(fgcolour);
2912                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2913                            XSetStipple(g_display, g_gc, fill);
2914                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2915                            FILL_POLYGON((XPoint *) point, npoints);
2916                            XSetFillStyle(g_display, g_gc, FillSolid);
2917                            XSetTSOrigin(g_display, g_gc, 0, 0);
2918                            ui_destroy_glyph((HGLYPH) fill);
2919                            break;
2920    
2921                    default:
2922                            unimpl("brush %d\n", brush->style);
2923            }
2924    
2925            RESET_FUNCTION(opcode);
2926    }
2927    
2928    void
2929    ui_polyline(uint8 opcode,
2930                /* dest */ POINT * points, int npoints,
2931                /* pen */ PEN * pen)
2932    {
2933            /* TODO: set join style */
2934            SET_FUNCTION(opcode);
2935            SET_FOREGROUND(pen->colour);
2936            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2937            if (g_ownbackstore)
2938                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2939                               CoordModePrevious);
2940    
2941            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2942                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2943    
2944            RESET_FUNCTION(opcode);
2945    }
2946    
2947    void
2948    ui_ellipse(uint8 opcode,
2949               /* mode */ uint8 fillmode,
2950               /* dest */ int x, int y, int cx, int cy,
2951               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2952    {
2953            uint8 style, i, ipattern[8];
2954            Pixmap fill;
2955    
2956            SET_FUNCTION(opcode);
2957    
2958            if (brush)
2959                    style = brush->style;
2960            else
2961                    style = 0;
2962    
2963            switch (style)
2964            {
2965                    case 0: /* Solid */
2966                            SET_FOREGROUND(fgcolour);
2967                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2968                            break;
2969    
2970                    case 2: /* Hatch */
2971                            fill = (Pixmap) ui_create_glyph(8, 8,
2972                                                            hatch_patterns + brush->pattern[0] * 8);
2973                            SET_FOREGROUND(fgcolour);
2974                            SET_BACKGROUND(bgcolour);
2975                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2976                            XSetStipple(g_display, g_gc, fill);
2977                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2978                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2979                            XSetFillStyle(g_display, g_gc, FillSolid);
2980                            XSetTSOrigin(g_display, g_gc, 0, 0);
2981                            ui_destroy_glyph((HGLYPH) fill);
2982                            break;
2983    
2984                    case 3: /* Pattern */
2985                            for (i = 0; i != 8; i++)
2986                                    ipattern[7 - i] = brush->pattern[i];
2987                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2988                            SET_FOREGROUND(bgcolour);
2989                            SET_BACKGROUND(fgcolour);
2990                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2991                            XSetStipple(g_display, g_gc, fill);
2992                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2993                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2994                            XSetFillStyle(g_display, g_gc, FillSolid);
2995                            XSetTSOrigin(g_display, g_gc, 0, 0);
2996                            ui_destroy_glyph((HGLYPH) fill);
2997                            break;
2998    
2999                    default:
3000                            unimpl("brush %d\n", brush->style);
3001            }
3002    
3003            RESET_FUNCTION(opcode);
3004    }
3005    
3006  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
3007  void  void
3008  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 1926  ui_draw_glyph(int mixmode, Line 3058  ui_draw_glyph(int mixmode,
3058  }  }
3059    
3060  void  void
3061  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,
3062               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
3063               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3064               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3065  {  {
3066            /* TODO: use brush appropriately */
3067    
3068          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3069          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
3070          DATABLOB *entry;          DATABLOB *entry;
# Line 1962  ui_draw_text(uint8 font, uint8 flags, in Line 3096  ui_draw_text(uint8 font, uint8 flags, in
3096                  switch (text[i])                  switch (text[i])
3097                  {                  {
3098                          case 0xff:                          case 0xff:
3099                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
3100                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
3101                                  {                                  {
3102                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
3103                                          exit(1);                                          for (j = 0; j < length; j++)
3104                                                    fprintf(stderr, "%02x ", text[j]);
3105                                            fprintf(stderr, "\n");
3106                                            i = length = 0;
3107                                            break;
3108                                  }                                  }
3109                                    cache_put_text(text[i + 1], text, text[i + 2]);
3110                                    i += 3;
3111                                    length -= i;
3112                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
3113                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
3114                                  i = 0;                                  i = 0;
3115                                  break;                                  break;
3116    
3117                          case 0xfe:                          case 0xfe:
3118                                    /* At least one byte needs to follow */
3119                                    if (i + 2 > length)
3120                                    {
3121                                            warning("Skipping short 0xfe command:");
3122                                            for (j = 0; j < length; j++)
3123                                                    fprintf(stderr, "%02x ", text[j]);
3124                                            fprintf(stderr, "\n");
3125                                            i = length = 0;
3126                                            break;
3127                                    }
3128                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
3129                                  if (entry != NULL)                                  if (entry->data != NULL)
3130                                  {                                  {
3131                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
3132                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3133                                          {                                          {
3134                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
3135                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2012  ui_draw_text(uint8 font, uint8 flags, in Line 3161  ui_draw_text(uint8 font, uint8 flags, in
3161          if (g_ownbackstore)          if (g_ownbackstore)
3162          {          {
3163                  if (boxcx > 1)                  if (boxcx > 1)
3164                    {
3165                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3166                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3167                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3168                                                    (g_display, g_backstore, sw->wnd, g_gc,
3169                                                     boxx, boxy,
3170                                                     boxcx, boxcy,
3171                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3172                    }
3173                  else                  else
3174                    {
3175                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3176                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3177                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3178                                                    (g_display, g_backstore, sw->wnd, g_gc,
3179                                                     clipx, clipy,
3180                                                     clipcx, clipcy, clipx - sw->xoffset,
3181                                                     clipy - sw->yoffset));
3182                    }
3183          }          }
3184  }  }
3185    
# Line 2029  ui_desktop_save(uint32 offset, int x, in Line 3192  ui_desktop_save(uint32 offset, int x, in
3192          if (g_ownbackstore)          if (g_ownbackstore)
3193          {          {
3194                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3195                    exit_if_null(image);
3196          }          }
3197          else          else
3198          {          {
3199                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3200                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3201                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3202                    exit_if_null(image);
3203                  XFreePixmap(g_display, pix);                  XFreePixmap(g_display, pix);
3204          }          }
3205    
# Line 2062  ui_desktop_restore(uint32 offset, int x, Line 3227  ui_desktop_restore(uint32 offset, int x,
3227          {          {
3228                  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);
3229                  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);
3230                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3231                                            (g_display, g_backstore, sw->wnd, g_gc,
3232                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3233          }          }
3234          else          else
3235          {          {
3236                  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);
3237                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3238                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3239                                             x - sw->xoffset, y - sw->yoffset));
3240          }          }
3241    
3242          XFree(image);          XFree(image);
3243  }  }
3244    
3245    /* these do nothing here but are used in uiports */
3246    void
3247    ui_begin_update(void)
3248    {
3249    }
3250    
3251    void
3252    ui_end_update(void)
3253    {
3254    }
3255    
3256    
3257    void
3258    ui_seamless_begin(BOOL hidden)
3259    {
3260            if (!g_seamless_rdp)
3261                    return;
3262    
3263            if (g_seamless_started)
3264                    return;
3265    
3266            g_seamless_started = True;
3267            g_seamless_hidden = hidden;
3268    
3269            if (!hidden)
3270                    ui_seamless_toggle();
3271    }
3272    
3273    
3274    void
3275    ui_seamless_hide_desktop()
3276    {
3277            if (!g_seamless_rdp)
3278                    return;
3279    
3280            if (!g_seamless_started)
3281                    return;
3282    
3283            if (g_seamless_active)
3284                    ui_seamless_toggle();
3285    
3286            g_seamless_hidden = True;
3287    }
3288    
3289    
3290    void
3291    ui_seamless_unhide_desktop()
3292    {
3293            if (!g_seamless_rdp)
3294                    return;
3295    
3296            if (!g_seamless_started)
3297                    return;
3298    
3299            g_seamless_hidden = False;
3300    
3301            ui_seamless_toggle();
3302    }
3303    
3304    
3305    void
3306    ui_seamless_toggle()
3307    {
3308            if (!g_seamless_rdp)
3309                    return;
3310    
3311            if (!g_seamless_started)
3312                    return;
3313    
3314            if (g_seamless_hidden)
3315                    return;
3316    
3317            if (g_seamless_active)
3318            {
3319                    /* Deactivate */
3320                    while (g_seamless_windows)
3321                    {
3322                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3323                            sw_remove_window(g_seamless_windows);
3324                    }
3325                    XMapWindow(g_display, g_wnd);
3326            }
3327            else
3328            {
3329                    /* Activate */
3330                    XUnmapWindow(g_display, g_wnd);
3331                    seamless_send_sync();
3332            }
3333    
3334            g_seamless_active = !g_seamless_active;
3335    }
3336    
3337    
3338    void
3339    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3340                              unsigned long flags)
3341    {
3342            Window wnd;
3343            XSetWindowAttributes attribs;
3344            XClassHint *classhints;
3345            XSizeHints *sizehints;
3346            XWMHints *wmhints;
3347            long input_mask;
3348            seamless_window *sw, *sw_parent;
3349    
3350            if (!g_seamless_active)
3351                    return;
3352    
3353            /* Ignore CREATEs for existing windows */
3354            sw = sw_get_window_by_id(id);
3355            if (sw)
3356                    return;
3357    
3358            get_window_attribs(&attribs);
3359            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3360                                InputOutput, g_visual,
3361                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3362    
3363            XStoreName(g_display, wnd, "SeamlessRDP");
3364            ewmh_set_wm_name(wnd, "SeamlessRDP");
3365    
3366            mwm_hide_decorations(wnd);
3367    
3368            classhints = XAllocClassHint();
3369            if (classhints != NULL)
3370            {
3371                    classhints->res_name = "rdesktop";
3372                    classhints->res_class = "SeamlessRDP";
3373                    XSetClassHint(g_display, wnd, classhints);
3374                    XFree(classhints);
3375            }
3376    
3377            /* WM_NORMAL_HINTS */
3378            sizehints = XAllocSizeHints();
3379            if (sizehints != NULL)
3380            {
3381                    sizehints->flags = USPosition;
3382                    XSetWMNormalHints(g_display, wnd, sizehints);
3383                    XFree(sizehints);
3384            }
3385    
3386            /* Parent-less transient windows */
3387            if (parent == 0xFFFFFFFF)
3388            {
3389                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3390                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3391                       using some other hints. */
3392                    ewmh_set_window_popup(wnd);
3393            }
3394            /* Normal transient windows */
3395            else if (parent != 0x00000000)
3396            {
3397                    sw_parent = sw_get_window_by_id(parent);
3398                    if (sw_parent)
3399                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3400                    else
3401                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3402            }
3403    
3404            if (flags & SEAMLESSRDP_CREATE_MODAL)
3405            {
3406                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3407                       somewhat at least */
3408                    if (parent == 0x00000000)
3409                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3410                    ewmh_set_window_modal(wnd);
3411            }
3412    
3413            /* FIXME: Support for Input Context:s */
3414    
3415            get_input_mask(&input_mask);
3416            input_mask |= PropertyChangeMask;
3417    
3418            XSelectInput(g_display, wnd, input_mask);
3419    
3420            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3421               seamless window, we could try to close the window on the
3422               serverside, instead of terminating rdesktop */
3423            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3424    
3425            sw = xmalloc(sizeof(seamless_window));
3426            sw->wnd = wnd;
3427            sw->id = id;
3428            sw->behind = 0;
3429            sw->group = sw_find_group(group, False);
3430            sw->group->refcnt++;
3431            sw->xoffset = 0;
3432            sw->yoffset = 0;
3433            sw->width = 0;
3434            sw->height = 0;
3435            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3436            sw->desktop = 0;
3437            sw->position_timer = xmalloc(sizeof(struct timeval));
3438            timerclear(sw->position_timer);
3439    
3440            sw->outstanding_position = False;
3441            sw->outpos_serial = 0;
3442            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3443            sw->outpos_width = sw->outpos_height = 0;
3444    
3445            sw->next = g_seamless_windows;
3446            g_seamless_windows = sw;
3447    
3448            /* WM_HINTS */
3449            wmhints = XAllocWMHints();
3450            if (wmhints)
3451            {
3452                    wmhints->flags = WindowGroupHint;
3453                    wmhints->window_group = sw->group->wnd;
3454                    XSetWMHints(g_display, sw->wnd, wmhints);
3455                    XFree(wmhints);
3456            }
3457    }
3458    
3459    
3460    void
3461    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3462    {
3463            seamless_window *sw;
3464    
3465            if (!g_seamless_active)
3466                    return;
3467    
3468            sw = sw_get_window_by_id(id);
3469            if (!sw)
3470            {
3471                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3472                    return;
3473            }
3474    
3475            XDestroyWindow(g_display, sw->wnd);
3476            sw_remove_window(sw);
3477    }
3478    
3479    
3480    void
3481    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3482    {
3483            seamless_window *sw, *sw_next;
3484    
3485            if (!g_seamless_active)
3486                    return;
3487    
3488            for (sw = g_seamless_windows; sw; sw = sw_next)
3489            {
3490                    sw_next = sw->next;
3491    
3492                    if (sw->group->id == id)
3493                    {
3494                            XDestroyWindow(g_display, sw->wnd);
3495                            sw_remove_window(sw);
3496                    }
3497            }
3498    }
3499    
3500    
3501    void
3502    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3503    {
3504            seamless_window *sw;
3505    
3506            if (!g_seamless_active)
3507                    return;
3508    
3509            sw = sw_get_window_by_id(id);
3510            if (!sw)
3511            {
3512                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3513                    return;
3514            }
3515    
3516            /* We ignore server updates until it has handled our request. */
3517            if (sw->outstanding_position)
3518                    return;
3519    
3520            if (!width || !height)
3521                    /* X11 windows must be at least 1x1 */
3522                    return;
3523    
3524            sw->xoffset = x;
3525            sw->yoffset = y;
3526            sw->width = width;
3527            sw->height = height;
3528    
3529            /* If we move the window in a maximized state, then KDE won't
3530               accept restoration */
3531            switch (sw->state)
3532            {
3533                    case SEAMLESSRDP_MINIMIZED:
3534                    case SEAMLESSRDP_MAXIMIZED:
3535                            return;
3536            }
3537    
3538            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3539            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3540    }
3541    
3542    
3543    void
3544    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3545    {
3546            seamless_window *sw;
3547    
3548            if (!g_seamless_active)
3549                    return;
3550    
3551            sw = sw_get_window_by_id(id);
3552            if (!sw)
3553            {
3554                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3555                    return;
3556            }
3557    
3558            if (behind)
3559            {
3560                    seamless_window *sw_behind;
3561                    Window wnds[2];
3562    
3563                    sw_behind = sw_get_window_by_id(behind);
3564                    if (!sw_behind)
3565                    {
3566                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3567                                    behind);
3568                            return;
3569                    }
3570    
3571                    wnds[1] = sw_behind->wnd;
3572                    wnds[0] = sw->wnd;
3573    
3574                    XRestackWindows(g_display, wnds, 2);
3575            }
3576            else
3577            {
3578                    XRaiseWindow(g_display, sw->wnd);
3579            }
3580    
3581            sw_restack_window(sw, behind);
3582    }
3583    
3584    
3585    void
3586    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3587    {
3588            seamless_window *sw;
3589    
3590            if (!g_seamless_active)
3591                    return;
3592    
3593            sw = sw_get_window_by_id(id);
3594            if (!sw)
3595            {
3596                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3597                    return;
3598            }
3599    
3600            /* FIXME: Might want to convert the name for non-EWMH WMs */
3601            XStoreName(g_display, sw->wnd, title);
3602            ewmh_set_wm_name(sw->wnd, title);
3603    }
3604    
3605    
3606    void
3607    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3608    {
3609            seamless_window *sw;
3610    
3611            if (!g_seamless_active)
3612                    return;
3613    
3614            sw = sw_get_window_by_id(id);
3615            if (!sw)
3616            {
3617                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3618                    return;
3619            }
3620    
3621            switch (state)
3622            {
3623                    case SEAMLESSRDP_NORMAL:
3624                    case SEAMLESSRDP_MAXIMIZED:
3625                            ewmh_change_state(sw->wnd, state);
3626                            XMapWindow(g_display, sw->wnd);
3627                            break;
3628                    case SEAMLESSRDP_MINIMIZED:
3629                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3630                               the Window Manager should probably just ignore the request, since
3631                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3632                               such as minimization, rather than an independent state." Besides,
3633                               XIconifyWindow is easier. */
3634                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3635                            {
3636                                    XWMHints *hints;
3637                                    hints = XGetWMHints(g_display, sw->wnd);
3638                                    if (hints)
3639                                    {
3640                                            hints->flags |= StateHint;
3641                                            hints->initial_state = IconicState;
3642                                            XSetWMHints(g_display, sw->wnd, hints);
3643                                            XFree(hints);
3644                                    }
3645                                    XMapWindow(g_display, sw->wnd);
3646                            }
3647                            else
3648                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3649                            break;
3650                    default:
3651                            warning("SeamlessRDP: Invalid state %d\n", state);
3652                            break;
3653            }
3654    
3655            sw->state = state;
3656    }
3657    
3658    
3659    void
3660    ui_seamless_syncbegin(unsigned long flags)
3661    {
3662            if (!g_seamless_active)
3663                    return;
3664    
3665            /* Destroy all seamless windows */
3666            while (g_seamless_windows)
3667            {
3668                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3669                    sw_remove_window(g_seamless_windows);
3670            }
3671    }
3672    
3673    
3674    void
3675    ui_seamless_ack(unsigned int serial)
3676    {
3677            seamless_window *sw;
3678            for (sw = g_seamless_windows; sw; sw = sw->next)
3679            {
3680                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3681                    {
3682                            sw->xoffset = sw->outpos_xoffset;
3683                            sw->yoffset = sw->outpos_yoffset;
3684                            sw->width = sw->outpos_width;
3685                            sw->height = sw->outpos_height;
3686                            sw->outstanding_position = False;
3687    
3688                            /* Do a complete redraw of the window as part of the
3689                               completion of the move. This is to remove any
3690                               artifacts caused by our lack of synchronization. */
3691                            XCopyArea(g_display, g_backstore,
3692                                      sw->wnd, g_gc,
3693                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3694    
3695                            break;
3696                    }
3697            }
3698    }

Legend:
Removed from v.643  
changed lines
  Added in v.1306

  ViewVC Help
Powered by ViewVC 1.1.26