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

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

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

sourceforge.net/trunk/rdesktop/xwin.c revision 680 by jsorg71, Mon Apr 26 23:14:07 2004 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1155 by ossman_, Fri Mar 17 10:48:11 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 30  Line 30 
30    
31  extern int g_width;  extern int g_width;
32  extern int g_height;  extern int g_height;
33    extern int g_xpos;
34    extern int g_ypos;
35    extern int g_pos;
36  extern BOOL g_sendmotion;  extern BOOL g_sendmotion;
37  extern BOOL g_fullscreen;  extern BOOL g_fullscreen;
38  extern BOOL g_grab_keyboard;  extern BOOL g_grab_keyboard;
39  extern BOOL g_hide_decorations;  extern BOOL g_hide_decorations;
40  extern char g_title[];  extern char g_title[];
41  extern int g_server_bpp;  /* Color depth of the RDP session.
42       As of RDP 5.1, it may be 8, 15, 16 or 24. */
43    extern int g_server_depth;
44  extern int g_win_button_size;  extern int g_win_button_size;
45    
46  Display *g_display;  Display *g_display;
# Line 43  Time g_last_gesturetime; Line 48  Time g_last_gesturetime;
48  static int g_x_socket;  static int g_x_socket;
49  static Screen *g_screen;  static Screen *g_screen;
50  Window g_wnd;  Window g_wnd;
51    
52    /* SeamlessRDP support */
53    typedef struct _seamless_window
54    {
55            Window wnd;
56            unsigned long id;
57            unsigned long parent;
58            unsigned long behind;
59            int xoffset, yoffset;
60            int width, height;
61            int state;              /* normal/minimized/maximized. */
62            unsigned int desktop;
63            struct _seamless_window *next;
64    } seamless_window;
65    static seamless_window *g_seamless_windows = NULL;
66    static unsigned long g_seamless_focused = 0;
67    static BOOL g_seamless_started = False; /* Server end is up and running */
68    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
69    extern BOOL g_seamless_rdp;
70    
71  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
72  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
73    BOOL g_Unobscured;              /* used for screenblt */
74  static GC g_gc = NULL;  static GC g_gc = NULL;
75    static GC g_create_bitmap_gc = NULL;
76    static GC g_create_glyph_gc = NULL;
77    static XRectangle g_clip_rectangle;
78  static Visual *g_visual;  static Visual *g_visual;
79    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
80       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
81       as far as we're concerned. */
82  static int g_depth;  static int g_depth;
83    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
84       This may be larger than g_depth, in which case some of the bits would
85       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
86  static int g_bpp;  static int g_bpp;
87  static XIM g_IM;  static XIM g_IM;
88  static XIC g_IC;  static XIC g_IC;
# Line 55  static XModifierKeymap *g_mod_map; Line 90  static XModifierKeymap *g_mod_map;
90  static Cursor g_current_cursor;  static Cursor g_current_cursor;
91  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
92  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
93    extern Atom g_net_wm_state_atom;
94    extern Atom g_net_wm_desktop_atom;
95  static BOOL g_focused;  static BOOL g_focused;
96  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
97  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
98       1) visual has 15, 16 or 24 depth and the same color channel masks
99          as its RDP equivalent (implies X server is LE),
100       2) host is LE
101       This will trigger an optimization whose real value is questionable.
102    */
103    static BOOL g_compatible_arch;
104    /* Indicates whether RDP's bitmaps and our XImages have the same
105       binary format. If so, we can avoid an expensive translation.
106       Note that this can be true when g_compatible_arch is false,
107       e.g.:
108      
109         RDP(LE) <-> host(BE) <-> X-Server(LE)
110        
111       ('host' is the machine running rdesktop; the host simply memcpy's
112        so its endianess doesn't matter)
113     */
114    static BOOL g_no_translate_image = False;
115    
116  /* endianness */  /* endianness */
117  static BOOL g_host_be;  static BOOL g_host_be;
# Line 73  static Pixmap g_backstore = 0; Line 127  static Pixmap g_backstore = 0;
127  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
128  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
129  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
130    static BOOL g_using_full_workarea = False;
131    
132  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
133  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 85  extern BOOL g_rdpsnd; Line 140  extern BOOL g_rdpsnd;
140  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
141  typedef struct  typedef struct
142  {  {
143          uint32 flags;          unsigned long flags;
144          uint32 functions;          unsigned long functions;
145          uint32 decorations;          unsigned long decorations;
146          sint32 inputMode;          long inputMode;
147          uint32 status;          unsigned long status;
148  }  }
149  PropMotifWmHints;  PropMotifWmHints;
150    
# Line 101  typedef struct Line 156  typedef struct
156  }  }
157  PixelColour;  PixelColour;
158    
159    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
160            do { \
161                    seamless_window *sw; \
162                    XRectangle rect; \
163                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
164                        rect.x = g_clip_rectangle.x - sw->xoffset; \
165                        rect.y = g_clip_rectangle.y - sw->yoffset; \
166                        rect.width = g_clip_rectangle.width; \
167                        rect.height = g_clip_rectangle.height; \
168                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
169                        func args; \
170                    } \
171                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
172            } while (0)
173    
174    static void
175    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
176    {
177            points[0].x -= xoffset;
178            points[0].y -= yoffset;
179            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
180            points[0].x += xoffset;
181            points[0].y += yoffset;
182    }
183    
184    static void
185    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
186    {
187            points[0].x -= xoffset;
188            points[0].y -= yoffset;
189            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
190            points[0].x += xoffset;
191            points[0].y += yoffset;
192    }
193    
194  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
195  { \  { \
196          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
197            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
198          if (g_ownbackstore) \          if (g_ownbackstore) \
199                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
200  }  }
# Line 114  PixelColour; Line 204  PixelColour;
204          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); \
205  }  }
206    
207    #define FILL_POLYGON(p,np)\
208    { \
209            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
210            if (g_ownbackstore) \
211                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
212            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
213    }
214    
215    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
216    { \
217            switch (m) \
218            { \
219                    case 0: /* Outline */ \
220                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
221                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
222                            if (g_ownbackstore) \
223                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
224                            break; \
225                    case 1: /* Filled */ \
226                            XFillArc(g_display, g_wnd, g_gc, x, y, \
227                                     cx, cy, 0, 360*64); \
228                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea, (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc, x, y, cx, cy, x-sw->xoffset, y-sw->yoffset)); \
229                            if (g_ownbackstore) \
230                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
231                            break; \
232            } \
233    }
234    
235  /* colour maps */  /* colour maps */
236  extern BOOL g_owncolmap;  extern BOOL g_owncolmap;
237  static Colormap g_xcolmap;  static Colormap g_xcolmap;
238  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
239    
240  #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] )
241  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
242  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
243    
# Line 145  static int rop2_map[] = { Line 263  static int rop2_map[] = {
263  #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]); }
264  #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); }
265    
266    static seamless_window *
267    seamless_get_window_by_id(unsigned long id)
268    {
269            seamless_window *sw;
270            for (sw = g_seamless_windows; sw; sw = sw->next)
271            {
272                    if (sw->id == id)
273                            return sw;
274            }
275            return NULL;
276    }
277    
278    
279    static seamless_window *
280    seamless_get_window_by_wnd(Window wnd)
281    {
282            seamless_window *sw;
283            for (sw = g_seamless_windows; sw; sw = sw->next)
284            {
285                    if (sw->wnd == wnd)
286                            return sw;
287            }
288            return NULL;
289    }
290    
291    
292  static void  static void
293  mwm_hide_decorations(void)  seamless_remove_window(seamless_window * win)
294    {
295            seamless_window *sw, **prevnext = &g_seamless_windows;
296            for (sw = g_seamless_windows; sw; sw = sw->next)
297            {
298                    if (sw == win)
299                    {
300                            *prevnext = sw->next;
301                            xfree(sw);
302                            return;
303                    }
304                    prevnext = &sw->next;
305            }
306            return;
307    }
308    
309    
310    /* Move all windows except wnd to new desktop */
311    static void
312    seamless_all_to_desktop(Window wnd, unsigned int desktop)
313    {
314            seamless_window *sw;
315            for (sw = g_seamless_windows; sw; sw = sw->next)
316            {
317                    if (sw->wnd == wnd)
318                            continue;
319                    if (sw->desktop != desktop)
320                    {
321                            ewmh_move_to_desktop(sw->wnd, desktop);
322                            sw->desktop = desktop;
323                    }
324            }
325    }
326    
327    
328    static void
329    seamless_restack_window(seamless_window * sw, unsigned long behind)
330    {
331            seamless_window *sw_above;
332    
333            /* Remove window from stack */
334            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
335            {
336                    if (sw_above->behind == sw->id)
337                            break;
338            }
339    
340            if (sw_above)
341                    sw_above->behind = sw->behind;
342    
343            /* And then add it at the new position */
344    
345            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
346            {
347                    if (sw_above->behind == behind)
348                            break;
349            }
350    
351            if (sw_above)
352                    sw_above->behind = sw->id;
353    
354            sw->behind = behind;
355    }
356    
357    
358    static void
359    mwm_hide_decorations(Window wnd)
360  {  {
361          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
362          Atom hintsatom;          Atom hintsatom;
# Line 163  mwm_hide_decorations(void) Line 373  mwm_hide_decorations(void)
373                  return;                  return;
374          }          }
375    
376          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
377                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
378    
379  }  }
380    
381  static PixelColour  #define SPLITCOLOUR15(colour, rv) \
382  split_colour15(uint32 colour)  { \
383  {          rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
384          PixelColour rv;          rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
385          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;  
386  }  }
387    
388  static uint32  #define SPLITCOLOUR16(colour, rv) \
389  make_colour(PixelColour pc)  { \
390  {          rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
391          return (((pc.red >> g_red_shift_r) << g_red_shift_l)          rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
392                  | ((pc.green >> g_green_shift_r) << g_green_shift_l)          rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
393                  | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l));  } \
394    
395    #define SPLITCOLOUR24(colour, rv) \
396    { \
397            rv.blue = (colour & 0xff0000) >> 16; \
398            rv.green = (colour & 0x00ff00) >> 8; \
399            rv.red = (colour & 0x0000ff); \
400  }  }
401    
402    #define MAKECOLOUR(pc) \
403            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
404                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
405                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
406    
407  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
408  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
409  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
410                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
411    
412    /* The following macros output the same octet sequences
413       on both BE and LE hosts: */
414    
415    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
416    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
417    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
418    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
419    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
420    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
421    
422  static uint32  static uint32
423  translate_colour(uint32 colour)  translate_colour(uint32 colour)
424  {  {
425          PixelColour pc;          PixelColour pc;
426          switch (g_server_bpp)          switch (g_server_depth)
427          {          {
428                  case 15:                  case 15:
429                          pc = split_colour15(colour);                          SPLITCOLOUR15(colour, pc);
430                          break;                          break;
431                  case 16:                  case 16:
432                          pc = split_colour16(colour);                          SPLITCOLOUR16(colour, pc);
433                          break;                          break;
434                  case 24:                  case 24:
435                          pc = split_colour24(colour);                          SPLITCOLOUR24(colour, pc);
436                            break;
437                    default:
438                            /* Avoid warning */
439                            pc.red = 0;
440                            pc.green = 0;
441                            pc.blue = 0;
442                          break;                          break;
443          }          }
444          return make_colour(pc);          return MAKECOLOUR(pc);
445  }  }
446    
447    /* indent is confused by UNROLL8 */
448    /* *INDENT-OFF* */
449    
450    /* repeat and unroll, similar to bitmap.c */
451    /* potentialy any of the following translate */
452    /* functions can use repeat but just doing */
453    /* the most common ones */
454    
455  #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }  #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
456  #define REPEAT(stm) \  /* 2 byte output repeat */
457    #define REPEAT2(stm) \
458    { \
459            while (out <= end - 8 * 2) \
460                    UNROLL8(stm) \
461            while (out < end) \
462                    { stm } \
463    }
464    /* 3 byte output repeat */
465    #define REPEAT3(stm) \
466    { \
467            while (out <= end - 8 * 3) \
468                    UNROLL8(stm) \
469            while (out < end) \
470                    { stm } \
471    }
472    /* 4 byte output repeat */
473    #define REPEAT4(stm) \
474  { \  { \
475          while (out <= end - 8 * 4) \          while (out <= end - 8 * 4) \
476                  UNROLL8(stm) \                  UNROLL8(stm) \
477          while (out < end) \          while (out < end) \
478                  { stm } \                  { stm } \
479  }  }
480    /* *INDENT-ON* */
481    
482  static void  static void
483  translate8to8(uint8 * data, uint8 * out, uint8 * end)  translate8to8(const uint8 * data, uint8 * out, uint8 * end)
484  {  {
485          while (out < end)          while (out < end)
486                  *(out++) = (uint8) g_colmap[*(data++)];                  *(out++) = (uint8) g_colmap[*(data++)];
487  }  }
488    
489  static void  static void
490  translate8to16(uint8 * data, uint8 * out, uint8 * end)  translate8to16(const uint8 * data, uint8 * out, uint8 * end)
491  {  {
492          uint16 value;          uint16 value;
493    
494          if (g_arch_match)          if (g_compatible_arch)
495                  REPEAT(*(((uint16*)out)++) = g_colmap[*(data++)];)          {
496                    /* *INDENT-OFF* */
497                    REPEAT2
498                    (
499                            *((uint16 *) out) = g_colmap[*(data++)];
500                            out += 2;
501                    )
502                    /* *INDENT-ON* */
503            }
504          else if (g_xserver_be)          else if (g_xserver_be)
505          {          {
506                  while (out < end)                  while (out < end)
507                  {                  {
508                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
509                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
510                  }                  }
511          }          }
512          else          else
# Line 266  translate8to16(uint8 * data, uint8 * out Line 514  translate8to16(uint8 * data, uint8 * out
514                  while (out < end)                  while (out < end)
515                  {                  {
516                          value = (uint16) g_colmap[*(data++)];                          value = (uint16) g_colmap[*(data++)];
517                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
518                  }                  }
519          }          }
520  }  }
521    
522  /* little endian - conversion happens when colourmap is built */  /* little endian - conversion happens when colourmap is built */
523  static void  static void
524  translate8to24(uint8 * data, uint8 * out, uint8 * end)  translate8to24(const uint8 * data, uint8 * out, uint8 * end)
525  {  {
526          uint32 value;          uint32 value;
527    
528          if (g_xserver_be)          if (g_compatible_arch)
529          {          {
530                  while (out < end)                  while (out < end)
531                  {                  {
532                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
533                          *(out++) = value >> 16;                          BOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value;  
534                  }                  }
535          }          }
536          else          else
# Line 293  translate8to24(uint8 * data, uint8 * out Line 538  translate8to24(uint8 * data, uint8 * out
538                  while (out < end)                  while (out < end)
539                  {                  {
540                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
541                          *(out++) = value;                          LOUT24(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
542                  }                  }
543          }          }
544  }  }
545    
546  static void  static void
547  translate8to32(uint8 * data, uint8 * out, uint8 * end)  translate8to32(const uint8 * data, uint8 * out, uint8 * end)
548  {  {
549          uint32 value;          uint32 value;
550    
551          if (g_arch_match)          if (g_compatible_arch)
552                  REPEAT(*(((uint32*)out)++) = g_colmap[*(data++)];)          {
553                    /* *INDENT-OFF* */
554                    REPEAT4
555                    (
556                            *((uint32 *) out) = g_colmap[*(data++)];
557                            out += 4;
558                    )
559                    /* *INDENT-ON* */
560            }
561          else if (g_xserver_be)          else if (g_xserver_be)
562          {          {
563                  while (out < end)                  while (out < end)
564                  {                  {
565                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
566                          *(out++) = value >> 24;                          BOUT32(out, value);
                         *(out++) = value >> 16;  
                         *(out++) = value >> 8;  
                         *(out++) = value;  
567                  }                  }
568          }          }
569          else          else
# Line 323  translate8to32(uint8 * data, uint8 * out Line 571  translate8to32(uint8 * data, uint8 * out
571                  while (out < end)                  while (out < end)
572                  {                  {
573                          value = g_colmap[*(data++)];                          value = g_colmap[*(data++)];
574                          *(out++) = value;                          LOUT32(out, value);
                         *(out++) = value >> 8;  
                         *(out++) = value >> 16;  
                         *(out++) = value >> 24;  
575                  }                  }
576          }          }
577  }  }
578    
579  static void  static void
580  translate15to16(uint16 * data, uint8 * out, uint8 * end)  translate15to16(const uint16 * data, uint8 * out, uint8 * end)
581  {  {
582          uint16 pixel;          uint16 pixel;
583          uint16 value;          uint16 value;
584            PixelColour pc;
585    
586          while (out < end)          if (g_xserver_be)
587          {          {
588                  pixel = *(data++);                  while (out < end)
   
                 if (g_host_be)  
                 {  
                         BSWAP16(pixel);  
                 }  
   
                 value = make_colour(split_colour15(pixel));  
   
                 if (g_xserver_be)  
589                  {                  {
590                          *(out++) = value >> 8;                          pixel = *(data++);
591                          *(out++) = value;                          if (g_host_be)
592                            {
593                                    BSWAP16(pixel);
594                            }
595                            SPLITCOLOUR15(pixel, pc);
596                            value = MAKECOLOUR(pc);
597                            BOUT16(out, value);
598                  }                  }
599                  else          }
600            else
601            {
602                    while (out < end)
603                  {                  {
604                          *(out++) = value;                          pixel = *(data++);
605                          *(out++) = value >> 8;                          if (g_host_be)
606                            {
607                                    BSWAP16(pixel);
608                            }
609                            SPLITCOLOUR15(pixel, pc);
610                            value = MAKECOLOUR(pc);
611                            LOUT16(out, value);
612                  }                  }
613          }          }
614  }  }
615    
616  static void  static void
617  translate15to24(uint16 * data, uint8 * out, uint8 * end)  translate15to24(const uint16 * data, uint8 * out, uint8 * end)
618  {  {
619          uint32 value;          uint32 value;
620          uint16 pixel;          uint16 pixel;
621            PixelColour pc;
622    
623          while (out < end)          if (g_compatible_arch)
624          {          {
625                  pixel = *(data++);                  /* *INDENT-OFF* */
626                    REPEAT3
627                  if (g_host_be)                  (
628                  {                          pixel = *(data++);
629                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
630                  }                          *(out++) = pc.blue;
631                            *(out++) = pc.green;
632                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
633                  if (g_xserver_be)                  )
634                    /* *INDENT-ON* */
635            }
636            else if (g_xserver_be)
637            {
638                    while (out < end)
639                  {                  {
640                          *(out++) = value >> 16;                          pixel = *(data++);
641                          *(out++) = value >> 8;                          if (g_host_be)
642                          *(out++) = value;                          {
643                                    BSWAP16(pixel);
644                            }
645                            SPLITCOLOUR15(pixel, pc);
646                            value = MAKECOLOUR(pc);
647                            BOUT24(out, value);
648                  }                  }
649                  else          }
650            else
651            {
652                    while (out < end)
653                  {                  {
654                          *(out++) = value;                          pixel = *(data++);
655                          *(out++) = value >> 8;                          if (g_host_be)
656                          *(out++) = value >> 16;                          {
657                                    BSWAP16(pixel);
658                            }
659                            SPLITCOLOUR15(pixel, pc);
660                            value = MAKECOLOUR(pc);
661                            LOUT24(out, value);
662                  }                  }
663          }          }
664  }  }
665    
666  static void  static void
667  translate15to32(uint16 * data, uint8 * out, uint8 * end)  translate15to32(const uint16 * data, uint8 * out, uint8 * end)
668  {  {
669          uint16 pixel;          uint16 pixel;
670          uint32 value;          uint32 value;
671            PixelColour pc;
672    
673          while (out < end)          if (g_compatible_arch)
674          {          {
675                  pixel = *(data++);                  /* *INDENT-OFF* */
676                    REPEAT4
677                  if (g_host_be)                  (
678                  {                          pixel = *(data++);
679                          BSWAP16(pixel);                          SPLITCOLOUR15(pixel, pc);
680                  }                          *(out++) = pc.blue;
681                            *(out++) = pc.green;
682                  value = make_colour(split_colour15(pixel));                          *(out++) = pc.red;
683                            *(out++) = 0;
684                  if (g_xserver_be)                  )
685                    /* *INDENT-ON* */
686            }
687            else if (g_xserver_be)
688            {
689                    while (out < end)
690                  {                  {
691                          *(out++) = value >> 24;                          pixel = *(data++);
692                          *(out++) = value >> 16;                          if (g_host_be)
693                          *(out++) = value >> 8;                          {
694                          *(out++) = value;                                  BSWAP16(pixel);
695                            }
696                            SPLITCOLOUR15(pixel, pc);
697                            value = MAKECOLOUR(pc);
698                            BOUT32(out, value);
699                  }                  }
700                  else          }
701            else
702            {
703                    while (out < end)
704                  {                  {
705                          *(out++) = value;                          pixel = *(data++);
706                          *(out++) = value >> 8;                          if (g_host_be)
707                          *(out++) = value >> 16;                          {
708                          *(out++) = value >> 24;                                  BSWAP16(pixel);
709                            }
710                            SPLITCOLOUR15(pixel, pc);
711                            value = MAKECOLOUR(pc);
712                            LOUT32(out, value);
713                  }                  }
714          }          }
715  }  }
716    
717  static void  static void
718  translate16to16(uint16 * data, uint8 * out, uint8 * end)  translate16to16(const uint16 * data, uint8 * out, uint8 * end)
719  {  {
720          uint16 pixel;          uint16 pixel;
721          uint16 value;          uint16 value;
722            PixelColour pc;
723    
724          while (out < end)          if (g_xserver_be)
725          {          {
                 pixel = *(data++);  
   
726                  if (g_host_be)                  if (g_host_be)
727                  {                  {
728                          BSWAP16(pixel);                          while (out < end)
729                            {
730                                    pixel = *(data++);
731                                    BSWAP16(pixel);
732                                    SPLITCOLOUR16(pixel, pc);
733                                    value = MAKECOLOUR(pc);
734                                    BOUT16(out, value);
735                            }
736                  }                  }
737                    else
738                  value = make_colour(split_colour16(pixel));                  {
739                            while (out < end)
740                  if (g_xserver_be)                          {
741                                    pixel = *(data++);
742                                    SPLITCOLOUR16(pixel, pc);
743                                    value = MAKECOLOUR(pc);
744                                    BOUT16(out, value);
745                            }
746                    }
747            }
748            else
749            {
750                    if (g_host_be)
751                  {                  {
752                          *(out++) = value >> 8;                          while (out < end)
753                          *(out++) = value;                          {
754                                    pixel = *(data++);
755                                    BSWAP16(pixel);
756                                    SPLITCOLOUR16(pixel, pc);
757                                    value = MAKECOLOUR(pc);
758                                    LOUT16(out, value);
759                            }
760                  }                  }
761                  else                  else
762                  {                  {
763                          *(out++) = value;                          while (out < end)
764                          *(out++) = value >> 8;                          {
765                                    pixel = *(data++);
766                                    SPLITCOLOUR16(pixel, pc);
767                                    value = MAKECOLOUR(pc);
768                                    LOUT16(out, value);
769                            }
770                  }                  }
771          }          }
772  }  }
773    
774  static void  static void
775  translate16to24(uint16 * data, uint8 * out, uint8 * end)  translate16to24(const uint16 * data, uint8 * out, uint8 * end)
776  {  {
777          uint32 value;          uint32 value;
778          uint16 pixel;          uint16 pixel;
779            PixelColour pc;
780    
781          while (out < end)          if (g_compatible_arch)
782            {
783                    /* *INDENT-OFF* */
784                    REPEAT3
785                    (
786                            pixel = *(data++);
787                            SPLITCOLOUR16(pixel, pc);
788                            *(out++) = pc.blue;
789                            *(out++) = pc.green;
790                            *(out++) = pc.red;
791                    )
792                    /* *INDENT-ON* */
793            }
794            else if (g_xserver_be)
795          {          {
                 pixel = *(data++);  
   
796                  if (g_host_be)                  if (g_host_be)
797                  {                  {
798                          BSWAP16(pixel);                          while (out < end)
799                            {
800                                    pixel = *(data++);
801                                    BSWAP16(pixel);
802                                    SPLITCOLOUR16(pixel, pc);
803                                    value = MAKECOLOUR(pc);
804                                    BOUT24(out, value);
805                            }
806                  }                  }
807                    else
808                  value = make_colour(split_colour16(pixel));                  {
809                            while (out < end)
810                  if (g_xserver_be)                          {
811                                    pixel = *(data++);
812                                    SPLITCOLOUR16(pixel, pc);
813                                    value = MAKECOLOUR(pc);
814                                    BOUT24(out, value);
815                            }
816                    }
817            }
818            else
819            {
820                    if (g_host_be)
821                  {                  {
822                          *(out++) = value >> 16;                          while (out < end)
823                          *(out++) = value >> 8;                          {
824                          *(out++) = value;                                  pixel = *(data++);
825                                    BSWAP16(pixel);
826                                    SPLITCOLOUR16(pixel, pc);
827                                    value = MAKECOLOUR(pc);
828                                    LOUT24(out, value);
829                            }
830                  }                  }
831                  else                  else
832                  {                  {
833                          *(out++) = value;                          while (out < end)
834                          *(out++) = value >> 8;                          {
835                          *(out++) = value >> 16;                                  pixel = *(data++);
836                                    SPLITCOLOUR16(pixel, pc);
837                                    value = MAKECOLOUR(pc);
838                                    LOUT24(out, value);
839                            }
840                  }                  }
841          }          }
842  }  }
843    
844  static void  static void
845  translate16to32(uint16 * data, uint8 * out, uint8 * end)  translate16to32(const uint16 * data, uint8 * out, uint8 * end)
846  {  {
847          uint16 pixel;          uint16 pixel;
848          uint32 value;          uint32 value;
849            PixelColour pc;
850    
851          while (out < end)          if (g_compatible_arch)
852            {
853                    /* *INDENT-OFF* */
854                    REPEAT4
855                    (
856                            pixel = *(data++);
857                            SPLITCOLOUR16(pixel, pc);
858                            *(out++) = pc.blue;
859                            *(out++) = pc.green;
860                            *(out++) = pc.red;
861                            *(out++) = 0;
862                    )
863                    /* *INDENT-ON* */
864            }
865            else if (g_xserver_be)
866          {          {
                 pixel = *(data++);  
   
867                  if (g_host_be)                  if (g_host_be)
868                  {                  {
869                          BSWAP16(pixel);                          while (out < end)
870                            {
871                                    pixel = *(data++);
872                                    BSWAP16(pixel);
873                                    SPLITCOLOUR16(pixel, pc);
874                                    value = MAKECOLOUR(pc);
875                                    BOUT32(out, value);
876                            }
877                  }                  }
878                    else
                 value = make_colour(split_colour16(pixel));  
   
                 if (g_xserver_be)  
879                  {                  {
880                          *(out++) = value >> 24;                          while (out < end)
881                          *(out++) = value >> 16;                          {
882                          *(out++) = value >> 8;                                  pixel = *(data++);
883                          *(out++) = value;                                  SPLITCOLOUR16(pixel, pc);
884                                    value = MAKECOLOUR(pc);
885                                    BOUT32(out, value);
886                            }
887                    }
888            }
889            else
890            {
891                    if (g_host_be)
892                    {
893                            while (out < end)
894                            {
895                                    pixel = *(data++);
896                                    BSWAP16(pixel);
897                                    SPLITCOLOUR16(pixel, pc);
898                                    value = MAKECOLOUR(pc);
899                                    LOUT32(out, value);
900                            }
901                  }                  }
902                  else                  else
903                  {                  {
904                          *(out++) = value;                          while (out < end)
905                          *(out++) = value >> 8;                          {
906                          *(out++) = value >> 16;                                  pixel = *(data++);
907                          *(out++) = value >> 24;                                  SPLITCOLOUR16(pixel, pc);
908                                    value = MAKECOLOUR(pc);
909                                    LOUT32(out, value);
910                            }
911                  }                  }
912          }          }
913  }  }
914    
915  static void  static void
916  translate24to16(uint8 * data, uint8 * out, uint8 * end)  translate24to16(const uint8 * data, uint8 * out, uint8 * end)
917  {  {
918          uint32 pixel = 0;          uint32 pixel = 0;
919          uint16 value;          uint16 value;
920            PixelColour pc;
921    
922          while (out < end)          while (out < end)
923          {          {
924                  pixel = *(data++) << 16;                  pixel = *(data++) << 16;
925                  pixel |= *(data++) << 8;                  pixel |= *(data++) << 8;
926                  pixel |= *(data++);                  pixel |= *(data++);
927                    SPLITCOLOUR24(pixel, pc);
928                  value = (uint16) make_colour(split_colour24(pixel));                  value = MAKECOLOUR(pc);
   
929                  if (g_xserver_be)                  if (g_xserver_be)
930                  {                  {
931                          *(out++) = value >> 8;                          BOUT16(out, value);
                         *(out++) = value;  
932                  }                  }
933                  else                  else
934                  {                  {
935                          *(out++) = value;                          LOUT16(out, value);
                         *(out++) = value >> 8;  
936                  }                  }
937          }          }
938  }  }
939    
940  static void  static void
941  translate24to24(uint8 * data, uint8 * out, uint8 * end)  translate24to24(const uint8 * data, uint8 * out, uint8 * end)
942  {  {
943          uint32 pixel;          uint32 pixel;
944          uint32 value;          uint32 value;
945            PixelColour pc;
946    
947          while (out < end)          if (g_xserver_be)
948          {          {
949                  pixel = *(data++) << 16;                  while (out < end)
                 pixel |= *(data++) << 8;  
                 pixel |= *(data++);  
   
                 value = make_colour(split_colour24(pixel));  
   
                 if (g_xserver_be)  
950                  {                  {
951                          *(out++) = value >> 16;                          pixel = *(data++) << 16;
952                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
953                          *(out++) = value;                          pixel |= *(data++);
954                            SPLITCOLOUR24(pixel, pc);
955                            value = MAKECOLOUR(pc);
956                            BOUT24(out, value);
957                  }                  }
958                  else          }
959            else
960            {
961                    while (out < end)
962                  {                  {
963                          *(out++) = value;                          pixel = *(data++) << 16;
964                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
965                          *(out++) = value >> 16;                          pixel |= *(data++);
966                            SPLITCOLOUR24(pixel, pc);
967                            value = MAKECOLOUR(pc);
968                            LOUT24(out, value);
969                  }                  }
970          }          }
971  }  }
972    
973  static void  static void
974  translate24to32(uint8 * data, uint8 * out, uint8 * end)  translate24to32(const uint8 * data, uint8 * out, uint8 * end)
975  {  {
976          uint32 pixel;          uint32 pixel;
977          uint32 value;          uint32 value;
978            PixelColour pc;
979    
980          while (out < end)          if (g_compatible_arch)
981          {          {
982                  pixel = *(data++) << 16;                  /* *INDENT-OFF* */
983                  pixel |= *(data++) << 8;  #ifdef NEED_ALIGN
984                  pixel |= *(data++);                  REPEAT4
985                    (
986                  value = make_colour(split_colour24(pixel));                          *(out++) = *(data++);
987                            *(out++) = *(data++);
988                  if (g_xserver_be)                          *(out++) = *(data++);
989                            *(out++) = 0;
990                    )
991    #else
992                    REPEAT4
993                    (
994                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
995                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
996                     out += 4;
997                     data += 3;
998                    )
999    #endif
1000                    /* *INDENT-ON* */
1001            }
1002            else if (g_xserver_be)
1003            {
1004                    while (out < end)
1005                  {                  {
1006                          *(out++) = value >> 24;                          pixel = *(data++) << 16;
1007                          *(out++) = value >> 16;                          pixel |= *(data++) << 8;
1008                          *(out++) = value >> 8;                          pixel |= *(data++);
1009                          *(out++) = value;                          SPLITCOLOUR24(pixel, pc);
1010                            value = MAKECOLOUR(pc);
1011                            BOUT32(out, value);
1012                  }                  }
1013                  else          }
1014            else
1015            {
1016                    while (out < end)
1017                  {                  {
1018                          *(out++) = value;                          pixel = *(data++) << 16;
1019                          *(out++) = value >> 8;                          pixel |= *(data++) << 8;
1020                          *(out++) = value >> 16;                          pixel |= *(data++);
1021                          *(out++) = value >> 24;                          SPLITCOLOUR24(pixel, pc);
1022                            value = MAKECOLOUR(pc);
1023                            LOUT32(out, value);
1024                  }                  }
1025          }          }
1026  }  }
# Line 615  translate_image(int width, int height, u Line 1032  translate_image(int width, int height, u
1032          uint8 *out;          uint8 *out;
1033          uint8 *end;          uint8 *end;
1034    
1035          /* if server and xserver bpp match, */          /*
1036          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1037          /* just return data */             and arch(endian) matches, no need to translate:
1038          if (g_arch_match)             just return data.
1039               Note: select_visual should've already ensured g_no_translate
1040               is only set for compatible depths, but the RDP depth might've
1041               changed during connection negotiations.
1042             */
1043            if (g_no_translate_image)
1044          {          {
1045                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1046                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1047                  if (g_depth == 16 && g_server_bpp == 16)                      (g_depth == 24 && g_server_depth == 24))
1048                          return data;                          return data;
1049          }          }
1050    
# Line 630  translate_image(int width, int height, u Line 1052  translate_image(int width, int height, u
1052          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1053          end = out + size;          end = out + size;
1054    
1055          switch (g_server_bpp)          switch (g_server_depth)
1056          {          {
1057                  case 24:                  case 24:
1058                          switch (g_bpp)                          switch (g_bpp)
# Line 728  calculate_shifts(uint32 mask, int *shift Line 1150  calculate_shifts(uint32 mask, int *shift
1150          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1151  }  }
1152    
1153  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1154  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1155     */
1156    static unsigned
1157    calculate_mask_weight(uint32 mask)
1158    {
1159            unsigned weight = 0;
1160            do
1161            {
1162                    weight += (mask & 1);
1163            }
1164            while (mask >>= 1);
1165            return weight;
1166    }
1167    
1168    static BOOL
1169    select_visual()
1170  {  {
         XVisualInfo vi;  
1171          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1172          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1173          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1174          XVisualInfo template;          XVisualInfo template;
1175          Bool TrueColorVisual = False;          int i;
1176            unsigned red_weight, blue_weight, green_weight;
1177    
1178          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1179          if (g_display == NULL)  
1180            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1181            if (pfm == NULL)
1182          {          {
1183                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1184                    XCloseDisplay(g_display);
1185                  return False;                  return False;
1186          }          }
1187    
1188          screen_num = DefaultScreen(g_display);          /* Search for best TrueColor visual */
         g_x_socket = ConnectionNumber(g_display);  
         g_screen = ScreenOfDisplay(g_display, screen_num);  
         g_depth = DefaultDepthOfScreen(g_screen);  
   
         /* Search for best TrueColor depth */  
1189          template.class = TrueColor;          template.class = TrueColor;
1190          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1191            g_visual = NULL;
1192            g_no_translate_image = False;
1193            g_compatible_arch = False;
1194            if (vmatches != NULL)
1195            {
1196                    for (i = 0; i < visuals_count; ++i)
1197                    {
1198                            XVisualInfo *visual_info = &vmatches[i];
1199    
1200                            /* Try to find a no-translation visual that'll
1201                               allow us to use RDP bitmaps directly as ZPixmaps. */
1202                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1203                                                   /* R5G5B5 */
1204                                                   (visual_info->red_mask == 0x7c00) &&
1205                                                   (visual_info->green_mask == 0x3e0) &&
1206                                                   (visual_info->blue_mask == 0x1f)) ||
1207                                                  ((visual_info->depth == 16) &&
1208                                                   /* R5G6B5 */
1209                                                   (visual_info->red_mask == 0xf800) &&
1210                                                   (visual_info->green_mask == 0x7e0) &&
1211                                                   (visual_info->blue_mask == 0x1f)) ||
1212                                                  ((visual_info->depth == 24) &&
1213                                                   /* R8G8B8 */
1214                                                   (visual_info->red_mask == 0xff0000) &&
1215                                                   (visual_info->green_mask == 0xff00) &&
1216                                                   (visual_info->blue_mask == 0xff))))
1217                            {
1218                                    g_visual = visual_info->visual;
1219                                    g_depth = visual_info->depth;
1220                                    g_compatible_arch = !g_host_be;
1221                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1222                                    if (g_no_translate_image)
1223                                            /* We found the best visual */
1224                                            break;
1225                            }
1226                            else
1227                            {
1228                                    g_compatible_arch = False;
1229                            }
1230    
1231          nvisuals--;                          if (visual_info->depth > 24)
1232          while (nvisuals >= 0)                          {
1233          {                                  /* Avoid 32-bit visuals and likes like the plague.
1234                  if ((vmatches + nvisuals)->depth > g_depth)                                     They're either untested or proven to work bad
1235                  {                                     (e.g. nvidia's Composite 32-bit visual).
1236                          g_depth = (vmatches + nvisuals)->depth;                                     Most implementation offer a 24-bit visual anyway. */
1237                                    continue;
1238                            }
1239    
1240                            /* Only care for visuals, for whose BPPs (not depths!)
1241                               we have a translateXtoY function. */
1242                            BOOL can_translate_to_bpp = False;
1243                            int j;
1244                            for (j = 0; j < pixmap_formats_count; ++j)
1245                            {
1246                                    if (pfm[j].depth == visual_info->depth)
1247                                    {
1248                                            if ((pfm[j].bits_per_pixel == 16) ||
1249                                                (pfm[j].bits_per_pixel == 24) ||
1250                                                (pfm[j].bits_per_pixel == 32))
1251                                            {
1252                                                    can_translate_to_bpp = True;
1253                                            }
1254                                            break;
1255                                    }
1256                            }
1257    
1258                            /* Prefer formats which have the most colour depth.
1259                               We're being truly aristocratic here, minding each
1260                               weight on its own. */
1261                            if (can_translate_to_bpp)
1262                            {
1263                                    unsigned vis_red_weight =
1264                                            calculate_mask_weight(visual_info->red_mask);
1265                                    unsigned vis_green_weight =
1266                                            calculate_mask_weight(visual_info->green_mask);
1267                                    unsigned vis_blue_weight =
1268                                            calculate_mask_weight(visual_info->blue_mask);
1269                                    if ((vis_red_weight >= red_weight)
1270                                        && (vis_green_weight >= green_weight)
1271                                        && (vis_blue_weight >= blue_weight))
1272                                    {
1273                                            red_weight = vis_red_weight;
1274                                            green_weight = vis_green_weight;
1275                                            blue_weight = vis_blue_weight;
1276                                            g_visual = visual_info->visual;
1277                                            g_depth = visual_info->depth;
1278                                    }
1279                            }
1280                  }                  }
1281                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1282          }          }
1283    
1284          test = 1;          if (g_visual != NULL)
         g_host_be = !(BOOL) (*(uint8 *) (&test));  
         g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);  
   
         if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))  
1285          {          {
1286                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1287                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1288                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1289                    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;  
                 }  
1290          }          }
1291          else          else
1292          {          {
1293                  /* need a truecolour visual */                  template.class = PseudoColor;
1294                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1295                  {                  template.colormap_size = 256;
1296                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1297                            XGetVisualInfo(g_display,
1298                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1299                                           &template, &visuals_count);
1300                    if (vmatches == NULL)
1301                    {
1302                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1303                            XCloseDisplay(g_display);
1304                            XFree(pfm);
1305                          return False;                          return False;
1306                  }                  }
1307    
1308                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1309                  g_owncolmap = False;                  g_owncolmap = True;
1310                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1311                  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);  
   
                 /* if RGB video and averything is little endian */  
                 if (vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask)  
                         if (!g_xserver_be && !g_host_be)  
                                 g_arch_match = True;  
1312          }          }
1313    
1314          pfm = XListPixmapFormats(g_display, &i);          g_bpp = 0;
1315          if (pfm != NULL)          for (i = 0; i < pixmap_formats_count; ++i)
1316          {          {
1317                  /* Use maximum bpp for this depth - this is generally                  XPixmapFormatValues *pf = &pfm[i];
1318                     desirable, e.g. 24 bits->32 bits. */                  if (pf->depth == g_depth)
                 while (i--)  
1319                  {                  {
1320                          if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))                          g_bpp = pf->bits_per_pixel;
1321    
1322                            if (g_no_translate_image)
1323                          {                          {
1324                                  g_bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1325                                    {
1326                                            case 15:
1327                                            case 16:
1328                                                    if (g_bpp != 16)
1329                                                            g_no_translate_image = False;
1330                                                    break;
1331                                            case 24:
1332                                                    /* Yes, this will force image translation
1333                                                       on most modern servers which use 32 bits
1334                                                       for R8G8B8. */
1335                                                    if (g_bpp != 24)
1336                                                            g_no_translate_image = False;
1337                                                    break;
1338                                            default:
1339                                                    g_no_translate_image = False;
1340                                                    break;
1341                                    }
1342                          }                          }
1343    
1344                            /* Pixmap formats list is a depth-to-bpp mapping --
1345                               there's just a single entry for every depth,
1346                               so we can safely break here */
1347                            break;
1348                  }                  }
                 XFree(pfm);  
1349          }          }
1350            XFree(pfm);
1351            pfm = NULL;
1352            return True;
1353    }
1354    
1355    BOOL
1356    ui_init(void)
1357    {
1358            int screen_num;
1359    
1360          if (g_bpp < 8)          g_display = XOpenDisplay(NULL);
1361            if (g_display == NULL)
1362          {          {
1363                  error("Less than 8 bpp not currently supported.\n");                  error("Failed to open display: %s\n", XDisplayName(NULL));
                 XCloseDisplay(g_display);  
1364                  return False;                  return False;
1365          }          }
1366    
1367            {
1368                    uint16 endianess_test = 1;
1369                    g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1370            }
1371    
1372            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1373            screen_num = DefaultScreen(g_display);
1374            g_x_socket = ConnectionNumber(g_display);
1375            g_screen = ScreenOfDisplay(g_display, screen_num);
1376            g_depth = DefaultDepthOfScreen(g_screen);
1377    
1378            if (!select_visual())
1379                    return False;
1380    
1381            if (g_no_translate_image)
1382            {
1383                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1384            }
1385    
1386            if (g_server_depth > g_bpp)
1387            {
1388                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1389                            g_server_depth, g_bpp);
1390            }
1391    
1392            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1393                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1394    
1395          if (!g_owncolmap)          if (!g_owncolmap)
1396          {          {
1397                  g_xcolmap =                  g_xcolmap =
1398                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1399                                          AllocNone);                                          AllocNone);
1400                  if (g_depth <= 8)                  if (g_depth <= 8)
1401                          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);
1402          }          }
1403    
1404          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1405          {          {
1406                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1407                  g_ownbackstore = True;                  g_ownbackstore = True;
1408          }          }
1409    
# Line 847  ui_init(void) Line 1414  ui_init(void)
1414          {          {
1415                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1416                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1417                    g_using_full_workarea = True;
1418          }          }
1419          else if (g_width < 0)          else if (g_width < 0)
1420          {          {
1421                  /* Percent of screen */                  /* Percent of screen */
1422                    if (-g_width >= 100)
1423                            g_using_full_workarea = True;
1424                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1425                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1426          }          }
# Line 858  ui_init(void) Line 1428  ui_init(void)
1428          {          {
1429                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1430                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1431                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1432                  {                  {
1433                          g_width = cx;                          g_width = cx;
1434                          g_height = cy;                          g_height = cy;
1435                            g_using_full_workarea = True;
1436                  }                  }
1437                  else                  else
1438                  {                  {
1439                          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");
1440                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1441                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1442                  }                  }
1443          }          }
1444    
# Line 883  ui_init(void) Line 1453  ui_init(void)
1453                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1454    
1455          xclip_init();          xclip_init();
1456            ewmh_init();
1457            if (g_seamless_rdp)
1458                    seamless_init();
1459    
1460          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));
1461    
1462          return True;          return True;
1463  }  }
# Line 908  ui_deinit(void) Line 1481  ui_deinit(void)
1481          g_display = NULL;          g_display = NULL;
1482  }  }
1483    
1484    
1485    static void
1486    get_window_attribs(XSetWindowAttributes * attribs)
1487    {
1488            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1489            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1490            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1491            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1492            attribs->override_redirect = g_fullscreen;
1493            attribs->colormap = g_xcolmap;
1494    }
1495    
1496    static void
1497    get_input_mask(long *input_mask)
1498    {
1499            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1500                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1501    
1502            if (g_sendmotion)
1503                    *input_mask |= PointerMotionMask;
1504            if (g_ownbackstore)
1505                    *input_mask |= ExposureMask;
1506            if (g_fullscreen || g_grab_keyboard)
1507                    *input_mask |= EnterWindowMask;
1508            if (g_grab_keyboard)
1509                    *input_mask |= LeaveWindowMask;
1510    }
1511    
1512  BOOL  BOOL
1513  ui_create_window(void)  ui_create_window(void)
1514  {  {
1515          uint8 null_pointer_mask[1] = { 0x80 };          uint8 null_pointer_mask[1] = { 0x80 };
1516          uint8 null_pointer_data[4] = { 0x00, 0x00, 0x00, 0x00 };          uint8 null_pointer_data[24] = { 0x00 };
1517    
1518          XSetWindowAttributes attribs;          XSetWindowAttributes attribs;
1519          XClassHint *classhints;          XClassHint *classhints;
1520          XSizeHints *sizehints;          XSizeHints *sizehints;
# Line 923  ui_create_window(void) Line 1525  ui_create_window(void)
1525          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1526          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1527    
1528          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1529          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1530          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1531          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1532          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1533    
1534          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,          get_window_attribs(&attribs);
1535                                0, g_depth, InputOutput, g_visual,  
1536                                CWBackPixel | CWBackingStore | CWOverrideRedirect |          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1537                                CWColormap | CWBorderPixel, &attribs);                                wndheight, 0, g_depth, InputOutput, g_visual,
1538                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1539                                  CWBorderPixel, &attribs);
1540    
1541          if (g_gc == NULL)          if (g_gc == NULL)
1542            {
1543                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1544                    ui_reset_clip();
1545            }
1546    
1547            if (g_create_bitmap_gc == NULL)
1548                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1549    
1550          if ((g_ownbackstore) && (g_backstore == 0))          if ((g_ownbackstore) && (g_backstore == 0))
1551          {          {
# Line 949  ui_create_window(void) Line 1559  ui_create_window(void)
1559          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1560    
1561          if (g_hide_decorations)          if (g_hide_decorations)
1562                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1563    
1564          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1565          if (classhints != NULL)          if (classhints != NULL)
# Line 963  ui_create_window(void) Line 1573  ui_create_window(void)
1573          if (sizehints)          if (sizehints)
1574          {          {
1575                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1576                    if (g_pos)
1577                            sizehints->flags |= PPosition;
1578                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1579                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1580                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 974  ui_create_window(void) Line 1586  ui_create_window(void)
1586                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1587          }          }
1588    
1589          input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |          get_input_mask(&input_mask);
                 VisibilityChangeMask | FocusChangeMask;  
   
         if (g_sendmotion)  
                 input_mask |= PointerMotionMask;  
         if (g_ownbackstore)  
                 input_mask |= ExposureMask;  
         if (g_fullscreen || g_grab_keyboard)  
                 input_mask |= EnterWindowMask;  
         if (g_grab_keyboard)  
                 input_mask |= LeaveWindowMask;  
1590    
1591          if (g_IM != NULL)          if (g_IM != NULL)
1592          {          {
# Line 997  ui_create_window(void) Line 1599  ui_create_window(void)
1599          }          }
1600    
1601          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1602    
1603            XMapWindow(g_display, g_wnd);
1604          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1605          do          do
1606          {          {
1607                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1608          }          }
1609          while (xevent.type != VisibilityNotify);          while (xevent.type != VisibilityNotify);
1610            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1611    
1612          g_focused = False;          g_focused = False;
1613          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 1025  void Line 1628  void
1628  ui_resize_window()  ui_resize_window()
1629  {  {
1630          XSizeHints *sizehints;          XSizeHints *sizehints;
1631            Pixmap bs;
1632    
1633          sizehints = XAllocSizeHints();          sizehints = XAllocSizeHints();
1634          if (sizehints)          if (sizehints)
# Line 1040  ui_resize_window() Line 1644  ui_resize_window()
1644          {          {
1645                  XResizeWindow(g_display, g_wnd, g_width, g_height);                  XResizeWindow(g_display, g_wnd, g_width, g_height);
1646          }          }
1647    
1648            /* create new backstore pixmap */
1649            if (g_backstore != 0)
1650            {
1651                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1652                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1653                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1654                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1655                    XFreePixmap(g_display, g_backstore);
1656                    g_backstore = bs;
1657            }
1658  }  }
1659    
1660  void  void
# Line 1056  xwin_toggle_fullscreen(void) Line 1671  xwin_toggle_fullscreen(void)
1671  {  {
1672          Pixmap contents = 0;          Pixmap contents = 0;
1673    
1674            if (g_seamless_active)
1675                    /* Turn off SeamlessRDP mode */
1676                    ui_seamless_toggle();
1677    
1678          if (!g_ownbackstore)          if (!g_ownbackstore)
1679          {          {
1680                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1076  xwin_toggle_fullscreen(void) Line 1695  xwin_toggle_fullscreen(void)
1695          }          }
1696  }  }
1697    
1698  /* Process all events in Xlib queue  static void
1699    handle_button_event(XEvent xevent, BOOL down)
1700    {
1701            uint16 button, flags = 0;
1702            g_last_gesturetime = xevent.xbutton.time;
1703            button = xkeymap_translate_button(xevent.xbutton.button);
1704            if (button == 0)
1705                    return;
1706    
1707            if (down)
1708                    flags = MOUSE_FLAG_DOWN;
1709    
1710            /* Stop moving window when button is released, regardless of cursor position */
1711            if (g_moving_wnd && (xevent.type == ButtonRelease))
1712                    g_moving_wnd = False;
1713    
1714            /* If win_button_size is nonzero, enable single app mode */
1715            if (xevent.xbutton.y < g_win_button_size)
1716            {
1717                    /*  Check from right to left: */
1718                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1719                    {
1720                            /* The close button, continue */
1721                            ;
1722                    }
1723                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1724                    {
1725                            /* The maximize/restore button. Do not send to
1726                               server.  It might be a good idea to change the
1727                               cursor or give some other visible indication
1728                               that rdesktop inhibited this click */
1729                            if (xevent.type == ButtonPress)
1730                                    return;
1731                    }
1732                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1733                    {
1734                            /* The minimize button. Iconify window. */
1735                            if (xevent.type == ButtonRelease)
1736                            {
1737                                    /* Release the mouse button outside the minimize button, to prevent the
1738                                       actual minimazation to happen */
1739                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1740                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1741                                    return;
1742                            }
1743                    }
1744                    else if (xevent.xbutton.x <= g_win_button_size)
1745                    {
1746                            /* The system menu. Ignore. */
1747                            if (xevent.type == ButtonPress)
1748                                    return;
1749                    }
1750                    else
1751                    {
1752                            /* The title bar. */
1753                            if (xevent.type == ButtonPress)
1754                            {
1755                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1756                                    {
1757                                            g_moving_wnd = True;
1758                                            g_move_x_offset = xevent.xbutton.x;
1759                                            g_move_y_offset = xevent.xbutton.y;
1760                                    }
1761                                    return;
1762                            }
1763                    }
1764            }
1765    
1766            if (xevent.xmotion.window == g_wnd)
1767            {
1768                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1769                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1770            }
1771            else
1772            {
1773                    /* SeamlessRDP */
1774                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1775                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1776            }
1777    }
1778    
1779    static void
1780    ui_seamless_handle_restack(seamless_window * sw)
1781    {
1782            Status status;
1783            Window root, parent, *children;
1784            unsigned int nchildren, i;
1785            seamless_window *sw_below;
1786    
1787            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1788                                &root, &parent, &children, &nchildren);
1789            if (!status || !nchildren)
1790                    return;
1791    
1792            sw_below = NULL;
1793    
1794            i = 0;
1795            while (children[i] != sw->wnd)
1796            {
1797                    i++;
1798                    if (i >= nchildren)
1799                            return;
1800            }
1801    
1802            for (i++; i < nchildren; i++)
1803            {
1804                    sw_below = seamless_get_window_by_wnd(children[i]);
1805                    if (sw_below)
1806                            break;
1807            }
1808    
1809            if (!sw_below && !sw->behind)
1810                    return;
1811            if (sw_below && (sw_below->id == sw->behind))
1812                    return;
1813    
1814            if (sw_below)
1815            {
1816                    seamless_send_zchange(sw->id, sw_below->id, 0);
1817                    seamless_restack_window(sw, sw_below->id);
1818            }
1819            else
1820            {
1821                    seamless_send_zchange(sw->id, 0, 0);
1822                    seamless_restack_window(sw, 0);
1823            }
1824    }
1825    
1826    /* Process events in Xlib queue
1827     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1828  static int  static int
1829  xwin_process_events(void)  xwin_process_events(void)
1830  {  {
1831          XEvent xevent;          XEvent xevent;
1832          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1833          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1834          char str[256];          char str[256];
1835          Status status;          Status status;
1836            int events = 0;
1837            seamless_window *sw;
1838    
1839          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1840          {          {
1841                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1842    
# Line 1099  xwin_process_events(void) Line 1846  xwin_process_events(void)
1846                          continue;                          continue;
1847                  }                  }
1848    
                 flags = 0;  
   
1849                  switch (xevent.type)                  switch (xevent.type)
1850                  {                  {
1851                            case VisibilityNotify:
1852                                    if (xevent.xvisibility.window == g_wnd)
1853                                            g_Unobscured =
1854                                                    xevent.xvisibility.state == VisibilityUnobscured;
1855    
1856                                    break;
1857                          case ClientMessage:                          case ClientMessage:
1858                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
1859                                  if ((xevent.xclient.message_type == g_protocol_atom)                                  if ((xevent.xclient.message_type == g_protocol_atom)
# Line 1134  xwin_process_events(void) Line 1885  xwin_process_events(void)
1885                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1886                                  }                                  }
1887    
1888                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1889                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1890    
1891                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1892                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1893                                          break;                                          break;
1894    
1895                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1896                                                             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);  
   
1897                                  break;                                  break;
1898    
1899                          case KeyRelease:                          case KeyRelease:
# Line 1159  xwin_process_events(void) Line 1901  xwin_process_events(void)
1901                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1902                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1903    
1904                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1905                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1906    
1907                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1908                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1909                                          break;                                          break;
1910    
1911                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1912                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1913                                  break;                                  break;
1914    
1915                          case ButtonPress:                          case ButtonPress:
1916                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1917                                  /* fall through */                                  break;
1918    
1919                          case ButtonRelease:                          case ButtonRelease:
1920                                  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);  
1921                                  break;                                  break;
1922    
1923                          case MotionNotify:                          case MotionNotify:
# Line 1252  xwin_process_events(void) Line 1932  xwin_process_events(void)
1932                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1933                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1934                                                         CurrentTime);                                                         CurrentTime);
1935                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1936                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1937                                    {
1938                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1939                                                           xevent.xmotion.x, xevent.xmotion.y);
1940                                    }
1941                                    else
1942                                    {
1943                                            /* SeamlessRDP */
1944                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1945                                                           xevent.xmotion.x_root,
1946                                                           xevent.xmotion.y_root);
1947                                    }
1948                                  break;                                  break;
1949    
1950                          case FocusIn:                          case FocusIn:
# Line 1264  xwin_process_events(void) Line 1955  xwin_process_events(void)
1955                                  if (g_grab_keyboard && g_mouse_in_wnd)                                  if (g_grab_keyboard && g_mouse_in_wnd)
1956                                          XGrabKeyboard(g_display, g_wnd, True,                                          XGrabKeyboard(g_display, g_wnd, True,
1957                                                        GrabModeAsync, GrabModeAsync, CurrentTime);                                                        GrabModeAsync, GrabModeAsync, CurrentTime);
1958    
1959                                    sw = seamless_get_window_by_wnd(xevent.xfocus.window);
1960                                    if (!sw)
1961                                            break;
1962    
1963                                    if (sw->id != g_seamless_focused)
1964                                    {
1965                                            seamless_send_focus(sw->id, 0);
1966                                            g_seamless_focused = sw->id;
1967                                    }
1968                                  break;                                  break;
1969    
1970                          case FocusOut:                          case FocusOut:
# Line 1296  xwin_process_events(void) Line 1997  xwin_process_events(void)
1997                                  break;                                  break;
1998    
1999                          case Expose:                          case Expose:
2000                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
2001                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
2002                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2003                                            xevent.xexpose.height,                                                    g_gc,
2004                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
2005                                                      xevent.xexpose.width, xevent.xexpose.height,
2006                                                      xevent.xexpose.x, xevent.xexpose.y);
2007                                    }
2008                                    else
2009                                    {
2010                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
2011                                            if (sw)
2012                                                    XCopyArea(g_display, g_backstore,
2013                                                              xevent.xexpose.window, g_gc,
2014                                                              xevent.xexpose.x + sw->xoffset,
2015                                                              xevent.xexpose.y + sw->yoffset,
2016                                                              xevent.xexpose.width,
2017                                                              xevent.xexpose.height, xevent.xexpose.x,
2018                                                              xevent.xexpose.y);
2019                                            else
2020                                            {
2021                                                    error("Expose for unknown window 0x%lx\n",
2022                                                          xevent.xexpose.window);
2023                                            }
2024                                    }
2025    
2026                                  break;                                  break;
2027    
2028                          case MappingNotify:                          case MappingNotify:
# Line 1329  xwin_process_events(void) Line 2051  xwin_process_events(void)
2051                                  break;                                  break;
2052                          case PropertyNotify:                          case PropertyNotify:
2053                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
2054                                    if (xevent.xproperty.window == g_wnd)
2055                                            break;
2056                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2057                                            break;
2058    
2059                                    /* seamless */
2060                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2061                                    if (!sw)
2062                                            break;
2063    
2064                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2065                                        && (xevent.xproperty.state == PropertyNewValue))
2066                                    {
2067                                            sw->state = ewmh_get_window_state(sw->wnd);
2068                                            seamless_send_state(sw->id, sw->state, 0);
2069                                    }
2070    
2071                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2072                                        && (xevent.xproperty.state == PropertyNewValue))
2073                                    {
2074                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2075                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
2076                                    }
2077    
2078                                    break;
2079                            case MapNotify:
2080                                    if (!g_seamless_active)
2081                                            rdp_send_client_window_status(1);
2082                                  break;                                  break;
2083                            case UnmapNotify:
2084                                    if (!g_seamless_active)
2085                                            rdp_send_client_window_status(0);
2086                                    break;
2087                            case ConfigureNotify:
2088                                    /* seamless */
2089                                    sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2090                                    if (!sw)
2091                                            break;
2092    
2093                                    ui_seamless_handle_restack(sw);
2094                  }                  }
2095          }          }
2096          /* Keep going */          /* Keep going */
# Line 1381  ui_select(int rdp_socket) Line 2142  ui_select(int rdp_socket)
2142                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2143    
2144                          case 0:                          case 0:
2145                                  /* TODO: if tv.tv_sec just times out                                  /* Abort serial read calls */
2146                                   * we will segfault.                                  if (s_timeout)
2147                                   * FIXME:                                          rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
                                  */  
                                 //s_timeout = True;  
                                 //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);  
2148                                  continue;                                  continue;
2149                  }                  }
2150    
# Line 1416  ui_create_bitmap(int width, int height, Line 2174  ui_create_bitmap(int width, int height,
2174          uint8 *tdata;          uint8 *tdata;
2175          int bitmap_pad;          int bitmap_pad;
2176    
2177          if (g_server_bpp == 8)          if (g_server_depth == 8)
2178          {          {
2179                  bitmap_pad = 8;                  bitmap_pad = 8;
2180          }          }
# Line 1433  ui_create_bitmap(int width, int height, Line 2191  ui_create_bitmap(int width, int height,
2191          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2192                               (char *) tdata, width, height, bitmap_pad, 0);                               (char *) tdata, width, height, bitmap_pad, 0);
2193    
2194          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);
2195    
2196          XFree(image);          XFree(image);
2197          if (tdata != data)          if (tdata != data)
# Line 1448  ui_paint_bitmap(int x, int y, int cx, in Line 2206  ui_paint_bitmap(int x, int y, int cx, in
2206          uint8 *tdata;          uint8 *tdata;
2207          int bitmap_pad;          int bitmap_pad;
2208    
2209          if (g_server_bpp == 8)          if (g_server_depth == 8)
2210          {          {
2211                  bitmap_pad = 8;                  bitmap_pad = 8;
2212          }          }
# Line 1468  ui_paint_bitmap(int x, int y, int cx, in Line 2226  ui_paint_bitmap(int x, int y, int cx, in
2226          {          {
2227                  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);
2228                  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);
2229                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2230                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2231                                             x - sw->xoffset, y - sw->yoffset));
2232          }          }
2233          else          else
2234          {          {
2235                  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);
2236                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2237                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2238                                             x - sw->xoffset, y - sw->yoffset));
2239          }          }
2240    
2241          XFree(image);          XFree(image);
# Line 1491  ui_create_glyph(int width, int height, u Line 2255  ui_create_glyph(int width, int height, u
2255          XImage *image;          XImage *image;
2256          Pixmap bitmap;          Pixmap bitmap;
2257          int scanline;          int scanline;
         GC gc;  
2258    
2259          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2260    
2261          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2262          gc = XCreateGC(g_display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2263                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2264    
2265          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2266                               width, height, 8, scanline);                               width, height, 8, scanline);
# Line 1504  ui_create_glyph(int width, int height, u Line 2268  ui_create_glyph(int width, int height, u
2268          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2269          XInitImage(image);          XInitImage(image);
2270    
2271          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);
2272    
2273          XFree(image);          XFree(image);
         XFreeGC(g_display, gc);  
2274          return (HGLYPH) bitmap;          return (HGLYPH) bitmap;
2275  }  }
2276    
# Line 1593  ui_set_cursor(HCURSOR cursor) Line 2356  ui_set_cursor(HCURSOR cursor)
2356  {  {
2357          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2358          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2359            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2360  }  }
2361    
2362  void  void
# Line 1734  ui_set_colourmap(HCOLOURMAP map) Line 2498  ui_set_colourmap(HCOLOURMAP map)
2498                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2499          }          }
2500          else          else
2501            {
2502                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2503                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2504            }
2505  }  }
2506    
2507  void  void
2508  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2509  {  {
2510          XRectangle rect;          g_clip_rectangle.x = x;
2511            g_clip_rectangle.y = y;
2512          rect.x = x;          g_clip_rectangle.width = cx;
2513          rect.y = y;          g_clip_rectangle.height = cy;
2514          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);  
2515  }  }
2516    
2517  void  void
2518  ui_reset_clip(void)  ui_reset_clip(void)
2519  {  {
2520          XRectangle rect;          g_clip_rectangle.x = 0;
2521            g_clip_rectangle.y = 0;
2522          rect.x = 0;          g_clip_rectangle.width = g_width;
2523          rect.y = 0;          g_clip_rectangle.height = g_height;
2524          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);  
2525  }  }
2526    
2527  void  void
# Line 1839  ui_patblt(uint8 opcode, Line 2602  ui_patblt(uint8 opcode,
2602    
2603          if (g_ownbackstore)          if (g_ownbackstore)
2604                  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);
2605            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2606                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2607                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2608  }  }
2609    
2610  void  void
# Line 1849  ui_screenblt(uint8 opcode, Line 2615  ui_screenblt(uint8 opcode,
2615          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2616          if (g_ownbackstore)          if (g_ownbackstore)
2617          {          {
2618                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2619                              g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2620                  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);
2621          }          }
2622          else          else
2623          {          {
2624                  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);
2625          }          }
2626    
2627            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2628                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2629                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2630    
2631          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2632  }  }
2633    
# Line 1866  ui_memblt(uint8 opcode, Line 2638  ui_memblt(uint8 opcode,
2638  {  {
2639          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2640          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);
2641            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2642                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2643                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2644          if (g_ownbackstore)          if (g_ownbackstore)
2645                  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);
2646          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1912  ui_line(uint8 opcode, Line 2687  ui_line(uint8 opcode,
2687          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2688          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2689          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2690            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2691                                                startx - sw->xoffset, starty - sw->yoffset,
2692                                                endx - sw->xoffset, endy - sw->yoffset));
2693          if (g_ownbackstore)          if (g_ownbackstore)
2694                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2695          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 1926  ui_rect( Line 2704  ui_rect(
2704          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2705  }  }
2706    
2707    void
2708    ui_polygon(uint8 opcode,
2709               /* mode */ uint8 fillmode,
2710               /* dest */ POINT * point, int npoints,
2711               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2712    {
2713            uint8 style, i, ipattern[8];
2714            Pixmap fill;
2715    
2716            SET_FUNCTION(opcode);
2717    
2718            switch (fillmode)
2719            {
2720                    case ALTERNATE:
2721                            XSetFillRule(g_display, g_gc, EvenOddRule);
2722                            break;
2723                    case WINDING:
2724                            XSetFillRule(g_display, g_gc, WindingRule);
2725                            break;
2726                    default:
2727                            unimpl("fill mode %d\n", fillmode);
2728            }
2729    
2730            if (brush)
2731                    style = brush->style;
2732            else
2733                    style = 0;
2734    
2735            switch (style)
2736            {
2737                    case 0: /* Solid */
2738                            SET_FOREGROUND(fgcolour);
2739                            FILL_POLYGON((XPoint *) point, npoints);
2740                            break;
2741    
2742                    case 2: /* Hatch */
2743                            fill = (Pixmap) ui_create_glyph(8, 8,
2744                                                            hatch_patterns + brush->pattern[0] * 8);
2745                            SET_FOREGROUND(fgcolour);
2746                            SET_BACKGROUND(bgcolour);
2747                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2748                            XSetStipple(g_display, g_gc, fill);
2749                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2750                            FILL_POLYGON((XPoint *) point, npoints);
2751                            XSetFillStyle(g_display, g_gc, FillSolid);
2752                            XSetTSOrigin(g_display, g_gc, 0, 0);
2753                            ui_destroy_glyph((HGLYPH) fill);
2754                            break;
2755    
2756                    case 3: /* Pattern */
2757                            for (i = 0; i != 8; i++)
2758                                    ipattern[7 - i] = brush->pattern[i];
2759                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2760                            SET_FOREGROUND(bgcolour);
2761                            SET_BACKGROUND(fgcolour);
2762                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2763                            XSetStipple(g_display, g_gc, fill);
2764                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2765                            FILL_POLYGON((XPoint *) point, npoints);
2766                            XSetFillStyle(g_display, g_gc, FillSolid);
2767                            XSetTSOrigin(g_display, g_gc, 0, 0);
2768                            ui_destroy_glyph((HGLYPH) fill);
2769                            break;
2770    
2771                    default:
2772                            unimpl("brush %d\n", brush->style);
2773            }
2774    
2775            RESET_FUNCTION(opcode);
2776    }
2777    
2778    void
2779    ui_polyline(uint8 opcode,
2780                /* dest */ POINT * points, int npoints,
2781                /* pen */ PEN * pen)
2782    {
2783            /* TODO: set join style */
2784            SET_FUNCTION(opcode);
2785            SET_FOREGROUND(pen->colour);
2786            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2787            if (g_ownbackstore)
2788                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2789                               CoordModePrevious);
2790    
2791            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2792                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2793    
2794            RESET_FUNCTION(opcode);
2795    }
2796    
2797    void
2798    ui_ellipse(uint8 opcode,
2799               /* mode */ uint8 fillmode,
2800               /* dest */ int x, int y, int cx, int cy,
2801               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2802    {
2803            uint8 style, i, ipattern[8];
2804            Pixmap fill;
2805    
2806            SET_FUNCTION(opcode);
2807    
2808            if (brush)
2809                    style = brush->style;
2810            else
2811                    style = 0;
2812    
2813            switch (style)
2814            {
2815                    case 0: /* Solid */
2816                            SET_FOREGROUND(fgcolour);
2817                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2818                            break;
2819    
2820                    case 2: /* Hatch */
2821                            fill = (Pixmap) ui_create_glyph(8, 8,
2822                                                            hatch_patterns + brush->pattern[0] * 8);
2823                            SET_FOREGROUND(fgcolour);
2824                            SET_BACKGROUND(bgcolour);
2825                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2826                            XSetStipple(g_display, g_gc, fill);
2827                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2828                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2829                            XSetFillStyle(g_display, g_gc, FillSolid);
2830                            XSetTSOrigin(g_display, g_gc, 0, 0);
2831                            ui_destroy_glyph((HGLYPH) fill);
2832                            break;
2833    
2834                    case 3: /* Pattern */
2835                            for (i = 0; i != 8; i++)
2836                                    ipattern[7 - i] = brush->pattern[i];
2837                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2838                            SET_FOREGROUND(bgcolour);
2839                            SET_BACKGROUND(fgcolour);
2840                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2841                            XSetStipple(g_display, g_gc, fill);
2842                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2843                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2844                            XSetFillStyle(g_display, g_gc, FillSolid);
2845                            XSetTSOrigin(g_display, g_gc, 0, 0);
2846                            ui_destroy_glyph((HGLYPH) fill);
2847                            break;
2848    
2849                    default:
2850                            unimpl("brush %d\n", brush->style);
2851            }
2852    
2853            RESET_FUNCTION(opcode);
2854    }
2855    
2856  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
2857  void  void
2858  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 1981  ui_draw_glyph(int mixmode, Line 2908  ui_draw_glyph(int mixmode,
2908  }  }
2909    
2910  void  void
2911  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,
2912               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2913               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2914               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2915  {  {
2916            /* TODO: use brush appropriately */
2917    
2918          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2919          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
2920          DATABLOB *entry;          DATABLOB *entry;
# Line 2017  ui_draw_text(uint8 font, uint8 flags, in Line 2946  ui_draw_text(uint8 font, uint8 flags, in
2946                  switch (text[i])                  switch (text[i])
2947                  {                  {
2948                          case 0xff:                          case 0xff:
2949                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2950                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
2951                                  {                                  {
2952                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2953                                          exit(1);                                          for (j = 0; j < length; j++)
2954                                                    fprintf(stderr, "%02x ", text[j]);
2955                                            fprintf(stderr, "\n");
2956                                            i = length = 0;
2957                                            break;
2958                                  }                                  }
2959                                    cache_put_text(text[i + 1], text, text[i + 2]);
2960                                    i += 3;
2961                                    length -= i;
2962                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2963                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2964                                  i = 0;                                  i = 0;
2965                                  break;                                  break;
2966    
2967                          case 0xfe:                          case 0xfe:
2968                                    /* At least one byte needs to follow */
2969                                    if (i + 2 > length)
2970                                    {
2971                                            warning("Skipping short 0xfe command:");
2972                                            for (j = 0; j < length; j++)
2973                                                    fprintf(stderr, "%02x ", text[j]);
2974                                            fprintf(stderr, "\n");
2975                                            i = length = 0;
2976                                            break;
2977                                    }
2978                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2979                                  if (entry != NULL)                                  if (entry->data != NULL)
2980                                  {                                  {
2981                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2982                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2983                                          {                                          {
2984                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2985                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2067  ui_draw_text(uint8 font, uint8 flags, in Line 3011  ui_draw_text(uint8 font, uint8 flags, in
3011          if (g_ownbackstore)          if (g_ownbackstore)
3012          {          {
3013                  if (boxcx > 1)                  if (boxcx > 1)
3014                    {
3015                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3016                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
3017                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3018                                                    (g_display, g_backstore, sw->wnd, g_gc,
3019                                                     boxx, boxy,
3020                                                     boxcx, boxcy,
3021                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3022                    }
3023                  else                  else
3024                    {
3025                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3026                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
3027                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3028                                                    (g_display, g_backstore, sw->wnd, g_gc,
3029                                                     clipx, clipy,
3030                                                     clipcx, clipcy, clipx - sw->xoffset,
3031                                                     clipy - sw->yoffset));
3032                    }
3033          }          }
3034  }  }
3035    
# Line 2117  ui_desktop_restore(uint32 offset, int x, Line 3075  ui_desktop_restore(uint32 offset, int x,
3075          {          {
3076                  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);
3077                  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);
3078                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3079                                            (g_display, g_backstore, sw->wnd, g_gc,
3080                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3081          }          }
3082          else          else
3083          {          {
3084                  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);
3085                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3086                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3087                                             x - sw->xoffset, y - sw->yoffset));
3088          }          }
3089    
3090          XFree(image);          XFree(image);
3091  }  }
3092    
3093    /* these do nothing here but are used in uiports */
3094    void
3095    ui_begin_update(void)
3096    {
3097    }
3098    
3099    void
3100    ui_end_update(void)
3101    {
3102    }
3103    
3104    void
3105    ui_seamless_begin()
3106    {
3107            if (!g_seamless_rdp)
3108                    return;
3109    
3110            if (g_seamless_started)
3111                    return;
3112    
3113            g_seamless_started = True;
3114    
3115            ui_seamless_toggle();
3116    }
3117    
3118    void
3119    ui_seamless_toggle()
3120    {
3121            if (!g_seamless_rdp)
3122                    return;
3123    
3124            if (!g_seamless_started)
3125                    return;
3126    
3127            if (g_seamless_active)
3128            {
3129                    /* Deactivate */
3130                    while (g_seamless_windows)
3131                    {
3132                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3133                            seamless_remove_window(g_seamless_windows);
3134                    }
3135                    XMapWindow(g_display, g_wnd);
3136            }
3137            else
3138            {
3139                    /* Activate */
3140                    XUnmapWindow(g_display, g_wnd);
3141                    seamless_send_sync();
3142            }
3143    
3144            g_seamless_active = !g_seamless_active;
3145    }
3146    
3147    void
3148    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3149    {
3150            Window wnd;
3151            XSetWindowAttributes attribs;
3152            XClassHint *classhints;
3153            XSizeHints *sizehints;
3154            long input_mask;
3155            seamless_window *sw, *sw_parent;
3156    
3157            if (!g_seamless_active)
3158                    return;
3159    
3160            /* Ignore CREATEs for existing windows */
3161            sw = seamless_get_window_by_id(id);
3162            if (sw)
3163                    return;
3164    
3165            get_window_attribs(&attribs);
3166            attribs.override_redirect = False;
3167    
3168            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3169                                InputOutput, g_visual,
3170                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3171                                CWBorderPixel, &attribs);
3172    
3173            XStoreName(g_display, wnd, "SeamlessRDP");
3174            ewmh_set_wm_name(wnd, "SeamlessRDP");
3175    
3176            mwm_hide_decorations(wnd);
3177    
3178            classhints = XAllocClassHint();
3179            if (classhints != NULL)
3180            {
3181                    classhints->res_name = "rdesktop";
3182                    classhints->res_class = "SeamlessRDP";
3183                    XSetClassHint(g_display, wnd, classhints);
3184                    XFree(classhints);
3185            }
3186    
3187            /* WM_NORMAL_HINTS */
3188            sizehints = XAllocSizeHints();
3189            if (sizehints != NULL)
3190            {
3191                    sizehints->flags = USPosition;
3192                    XSetWMNormalHints(g_display, wnd, sizehints);
3193                    XFree(sizehints);
3194            }
3195    
3196            /* Set WM_TRANSIENT_FOR, if necessary */
3197            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3198            {
3199                    sw_parent = seamless_get_window_by_id(parent);
3200                    if (sw_parent)
3201                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3202                    else
3203                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3204            }
3205    
3206    
3207            /* FIXME: Support for Input Context:s */
3208    
3209            get_input_mask(&input_mask);
3210            input_mask |= PropertyChangeMask;
3211    
3212            XSelectInput(g_display, wnd, input_mask);
3213    
3214            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3215               seamless window, we could try to close the window on the
3216               serverside, instead of terminating rdesktop */
3217            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3218    
3219            sw = malloc(sizeof(seamless_window));
3220            sw->wnd = wnd;
3221            sw->id = id;
3222            sw->parent = parent;
3223            sw->behind = 0;
3224            sw->xoffset = 0;
3225            sw->yoffset = 0;
3226            sw->width = 0;
3227            sw->height = 0;
3228            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3229            sw->desktop = 0;
3230            sw->next = g_seamless_windows;
3231            g_seamless_windows = sw;
3232    }
3233    
3234    
3235    void
3236    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3237    {
3238            seamless_window *sw;
3239    
3240            if (!g_seamless_active)
3241                    return;
3242    
3243            sw = seamless_get_window_by_id(id);
3244            if (!sw)
3245            {
3246                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3247                    return;
3248            }
3249    
3250            XDestroyWindow(g_display, sw->wnd);
3251            seamless_remove_window(sw);
3252    }
3253    
3254    
3255    void
3256    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3257    {
3258            seamless_window *sw;
3259    
3260            if (!g_seamless_active)
3261                    return;
3262    
3263            sw = seamless_get_window_by_id(id);
3264            if (!sw)
3265            {
3266                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3267                    return;
3268            }
3269    
3270            if (!width || !height)
3271                    /* X11 windows must be at least 1x1 */
3272                    return;
3273    
3274            /* About MAX and MIN: Windows allows moving a window outside
3275               the desktop. This happens, for example, when maximizing an
3276               application. In this case, the position is set to something
3277               like -4,-4,1288,1032. Many WMs does not allow windows
3278               outside the desktop, however. Therefore, clip the window
3279               ourselves. */
3280            sw->xoffset = MAX(0, x);
3281            sw->yoffset = MAX(0, y);
3282            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3283            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3284    
3285            /* If we move the window in a maximized state, then KDE won't
3286               accept restoration */
3287            switch (sw->state)
3288            {
3289                    case SEAMLESSRDP_MINIMIZED:
3290                    case SEAMLESSRDP_MAXIMIZED:
3291                            return;
3292            }
3293    
3294            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3295            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3296    }
3297    
3298    void
3299    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3300    {
3301            seamless_window *sw;
3302    
3303            if (!g_seamless_active)
3304                    return;
3305    
3306            sw = seamless_get_window_by_id(id);
3307            if (!sw)
3308            {
3309                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3310                    return;
3311            }
3312    
3313            if (behind)
3314            {
3315                    seamless_window *sw_behind;
3316                    Window wnds[2];
3317    
3318                    sw_behind = seamless_get_window_by_id(behind);
3319                    if (!sw_behind)
3320                    {
3321                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3322                                    behind);
3323                            return;
3324                    }
3325    
3326                    wnds[1] = sw_behind->wnd;
3327                    wnds[0] = sw->wnd;
3328    
3329                    XRestackWindows(g_display, wnds, 2);
3330            }
3331            else
3332            {
3333                    XRaiseWindow(g_display, sw->wnd);
3334            }
3335    
3336            seamless_restack_window(sw, behind);
3337    }
3338    
3339    void
3340    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3341    {
3342            seamless_window *sw;
3343    
3344            if (!g_seamless_active)
3345                    return;
3346    
3347            sw = seamless_get_window_by_id(id);
3348            if (!sw)
3349            {
3350                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3351                    return;
3352            }
3353    
3354            /* FIXME: Might want to convert the name for non-EWMH WMs */
3355            XStoreName(g_display, sw->wnd, title);
3356            ewmh_set_wm_name(sw->wnd, title);
3357    }
3358    
3359    
3360    void
3361    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3362    {
3363            seamless_window *sw;
3364    
3365            if (!g_seamless_active)
3366                    return;
3367    
3368            sw = seamless_get_window_by_id(id);
3369            if (!sw)
3370            {
3371                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3372                    return;
3373            }
3374    
3375            switch (state)
3376            {
3377                    case SEAMLESSRDP_NORMAL:
3378                    case SEAMLESSRDP_MAXIMIZED:
3379                            ewmh_change_state(sw->wnd, state);
3380                            XMapWindow(g_display, sw->wnd);
3381                            break;
3382                    case SEAMLESSRDP_MINIMIZED:
3383                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3384                               the Window Manager should probably just ignore the request, since
3385                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3386                               such as minimization, rather than an independent state." Besides,
3387                               XIconifyWindow is easier. */
3388                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3389                            {
3390                                    XWMHints *hints;
3391                                    hints = XAllocWMHints();
3392                                    hints->flags = StateHint;
3393                                    hints->initial_state = IconicState;
3394                                    XSetWMHints(g_display, sw->wnd, hints);
3395                                    XFree(hints);
3396                                    XMapWindow(g_display, sw->wnd);
3397                            }
3398                            else
3399                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3400                            break;
3401                    default:
3402                            warning("SeamlessRDP: Invalid state %d\n", state);
3403                            break;
3404            }
3405    
3406            /* Handle popups without parents through some ewm hints */
3407            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3408                    ewmh_set_window_popup(sw->wnd);
3409    
3410            sw->state = state;
3411    }
3412    
3413    
3414    void
3415    ui_seamless_syncbegin(unsigned long flags)
3416    {
3417            if (!g_seamless_active)
3418                    return;
3419    
3420            /* Destroy all seamless windows */
3421            while (g_seamless_windows)
3422            {
3423                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3424                    seamless_remove_window(g_seamless_windows);
3425            }
3426    }

Legend:
Removed from v.680  
changed lines
  Added in v.1155

  ViewVC Help
Powered by ViewVC 1.1.26