/[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 844 by jdmeijer, Thu Mar 10 22:48:15 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1149 by ossman_, Thu Mar 16 15:27:59 2006 UTC
# Line 32  extern int g_width; Line 32  extern int g_width;
32  extern int g_height;  extern int g_height;
33  extern int g_xpos;  extern int g_xpos;
34  extern int g_ypos;  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 45  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            int xoffset, yoffset;
59            int width, height;
60            int state;              /* normal/minimized/maximized. */
61            unsigned int desktop;
62            struct _seamless_window *next;
63    } seamless_window;
64    static seamless_window *g_seamless_windows = NULL;
65    static BOOL g_seamless_started = False; /* Server end is up and running */
66    static BOOL g_seamless_active = False;  /* We are currently in seamless mode */
67    extern BOOL g_seamless_rdp;
68    
69  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
70  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
71  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
72  static GC g_gc = NULL;  static GC g_gc = NULL;
73  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
74  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
75    static XRectangle g_clip_rectangle;
76  static Visual *g_visual;  static Visual *g_visual;
77    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
78       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
79       as far as we're concerned. */
80  static int g_depth;  static int g_depth;
81    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
82       This may be larger than g_depth, in which case some of the bits would
83       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
84  static int g_bpp;  static int g_bpp;
85  static XIM g_IM;  static XIM g_IM;
86  static XIC g_IC;  static XIC g_IC;
# Line 60  static XModifierKeymap *g_mod_map; Line 88  static XModifierKeymap *g_mod_map;
88  static Cursor g_current_cursor;  static Cursor g_current_cursor;
89  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
90  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
91    extern Atom g_net_wm_state_atom;
92    extern Atom g_net_wm_desktop_atom;
93  static BOOL g_focused;  static BOOL g_focused;
94  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
95  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
96       1) visual has 15, 16 or 24 depth and the same color channel masks
97          as its RDP equivalent (implies X server is LE),
98       2) host is LE
99       This will trigger an optimization whose real value is questionable.
100    */
101    static BOOL g_compatible_arch;
102    /* Indicates whether RDP's bitmaps and our XImages have the same
103       binary format. If so, we can avoid an expensive translation.
104       Note that this can be true when g_compatible_arch is false,
105       e.g.:
106      
107         RDP(LE) <-> host(BE) <-> X-Server(LE)
108        
109       ('host' is the machine running rdesktop; the host simply memcpy's
110        so its endianess doesn't matter)
111     */
112    static BOOL g_no_translate_image = False;
113    
114  /* endianness */  /* endianness */
115  static BOOL g_host_be;  static BOOL g_host_be;
# Line 78  static Pixmap g_backstore = 0; Line 125  static Pixmap g_backstore = 0;
125  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
126  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
127  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
128    static BOOL g_using_full_workarea = False;
129    
130  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
131  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 90  extern BOOL g_rdpsnd; Line 138  extern BOOL g_rdpsnd;
138  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
139  typedef struct  typedef struct
140  {  {
141          uint32 flags;          unsigned long flags;
142          uint32 functions;          unsigned long functions;
143          uint32 decorations;          unsigned long decorations;
144          sint32 inputMode;          long inputMode;
145          uint32 status;          unsigned long status;
146  }  }
147  PropMotifWmHints;  PropMotifWmHints;
148    
# Line 106  typedef struct Line 154  typedef struct
154  }  }
155  PixelColour;  PixelColour;
156    
157    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
158            do { \
159                    seamless_window *sw; \
160                    XRectangle rect; \
161                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
162                        rect.x = g_clip_rectangle.x - sw->xoffset; \
163                        rect.y = g_clip_rectangle.y - sw->yoffset; \
164                        rect.width = g_clip_rectangle.width; \
165                        rect.height = g_clip_rectangle.height; \
166                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
167                        func args; \
168                    } \
169                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
170            } while (0)
171    
172    static void
173    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
174    {
175            points[0].x -= xoffset;
176            points[0].y -= yoffset;
177            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
178            points[0].x += xoffset;
179            points[0].y += yoffset;
180    }
181    
182    static void
183    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
184    {
185            points[0].x -= xoffset;
186            points[0].y -= yoffset;
187            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
188            points[0].x += xoffset;
189            points[0].y += yoffset;
190    }
191    
192  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
193  { \  { \
194          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
195            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
196          if (g_ownbackstore) \          if (g_ownbackstore) \
197                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
198  }  }
# Line 124  PixelColour; Line 207  PixelColour;
207          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \          XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
208          if (g_ownbackstore) \          if (g_ownbackstore) \
209                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \                  XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
210            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
211  }  }
212    
213  #define DRAW_ELLIPSE(x,y,cx,cy,m)\  #define DRAW_ELLIPSE(x,y,cx,cy,m)\
# Line 132  PixelColour; Line 216  PixelColour;
216          { \          { \
217                  case 0: /* Outline */ \                  case 0: /* Outline */ \
218                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \                          XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
219                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
220                          if (g_ownbackstore) \                          if (g_ownbackstore) \
221                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \                                  XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
222                          break; \                          break; \
223                  case 1: /* Filled */ \                  case 1: /* Filled */ \
224                          XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \                          XFillArc(g_display, g_wnd, g_gc, x, y, \
225                                   cx, cy, 0, 360*64); \                                   cx, cy, 0, 360*64); \
226                            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)); \
227                          if (g_ownbackstore) \                          if (g_ownbackstore) \
228                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \                                  XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
229                          break; \                          break; \
230          } \          } \
231  }  }
# Line 149  extern BOOL g_owncolmap; Line 235  extern BOOL g_owncolmap;
235  static Colormap g_xcolmap;  static Colormap g_xcolmap;
236  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
237    
238  #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] )
239  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
240  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
241    
# Line 175  static int rop2_map[] = { Line 261  static int rop2_map[] = {
261  #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]); }
262  #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); }
263    
264    static seamless_window *
265    seamless_get_window_by_id(unsigned long id)
266    {
267            seamless_window *sw;
268            for (sw = g_seamless_windows; sw; sw = sw->next)
269            {
270                    if (sw->id == id)
271                            return sw;
272            }
273            return NULL;
274    }
275    
276    
277    static seamless_window *
278    seamless_get_window_by_wnd(Window wnd)
279    {
280            seamless_window *sw;
281            for (sw = g_seamless_windows; sw; sw = sw->next)
282            {
283                    if (sw->wnd == wnd)
284                            return sw;
285            }
286            return NULL;
287    }
288    
289    
290    static void
291    seamless_remove_window(seamless_window * win)
292    {
293            seamless_window *sw, **prevnext = &g_seamless_windows;
294            for (sw = g_seamless_windows; sw; sw = sw->next)
295            {
296                    if (sw == win)
297                    {
298                            *prevnext = sw->next;
299                            xfree(sw);
300                            return;
301                    }
302                    prevnext = &sw->next;
303            }
304            return;
305    }
306    
307    
308    /* Move all windows except wnd to new desktop */
309    static void
310    seamless_all_to_desktop(Window wnd, unsigned int desktop)
311    {
312            seamless_window *sw;
313            for (sw = g_seamless_windows; sw; sw = sw->next)
314            {
315                    if (sw->wnd == wnd)
316                            continue;
317                    if (sw->desktop != desktop)
318                    {
319                            ewmh_move_to_desktop(sw->wnd, desktop);
320                            sw->desktop = desktop;
321                    }
322            }
323    }
324    
325    
326  static void  static void
327  mwm_hide_decorations(void)  mwm_hide_decorations(Window wnd)
328  {  {
329          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
330          Atom hintsatom;          Atom hintsatom;
# Line 193  mwm_hide_decorations(void) Line 341  mwm_hide_decorations(void)
341                  return;                  return;
342          }          }
343    
344          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
345                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
346    
347  }  }
348    
349  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 228  mwm_hide_decorations(void) Line 377  mwm_hide_decorations(void)
377  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
378                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
379    
380    /* The following macros output the same octet sequences
381       on both BE and LE hosts: */
382    
383  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
384  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
385  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
# Line 239  static uint32 Line 391  static uint32
391  translate_colour(uint32 colour)  translate_colour(uint32 colour)
392  {  {
393          PixelColour pc;          PixelColour pc;
394          switch (g_server_bpp)          switch (g_server_depth)
395          {          {
396                  case 15:                  case 15:
397                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 250  translate_colour(uint32 colour) Line 402  translate_colour(uint32 colour)
402                  case 24:                  case 24:
403                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
404                          break;                          break;
405                    default:
406                            /* Avoid warning */
407                            pc.red = 0;
408                            pc.green = 0;
409                            pc.blue = 0;
410                            break;
411          }          }
412          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
413  }  }
# Line 301  translate8to16(const uint8 * data, uint8 Line 459  translate8to16(const uint8 * data, uint8
459  {  {
460          uint16 value;          uint16 value;
461    
462          if (g_arch_match)          if (g_compatible_arch)
463          {          {
464                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
465                  REPEAT2                  REPEAT2
# Line 335  translate8to24(const uint8 * data, uint8 Line 493  translate8to24(const uint8 * data, uint8
493  {  {
494          uint32 value;          uint32 value;
495    
496          if (g_xserver_be)          if (g_compatible_arch)
497          {          {
498                  while (out < end)                  while (out < end)
499                  {                  {
# Line 358  translate8to32(const uint8 * data, uint8 Line 516  translate8to32(const uint8 * data, uint8
516  {  {
517          uint32 value;          uint32 value;
518    
519          if (g_arch_match)          if (g_compatible_arch)
520          {          {
521                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
522                  REPEAT4                  REPEAT4
# Line 430  translate15to24(const uint16 * data, uin Line 588  translate15to24(const uint16 * data, uin
588          uint16 pixel;          uint16 pixel;
589          PixelColour pc;          PixelColour pc;
590    
591          if (g_arch_match)          if (g_compatible_arch)
592          {          {
593                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
594                  REPEAT3                  REPEAT3
# Line 480  translate15to32(const uint16 * data, uin Line 638  translate15to32(const uint16 * data, uin
638          uint32 value;          uint32 value;
639          PixelColour pc;          PixelColour pc;
640    
641          if (g_arch_match)          if (g_compatible_arch)
642          {          {
643                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
644                  REPEAT4                  REPEAT4
# Line 588  translate16to24(const uint16 * data, uin Line 746  translate16to24(const uint16 * data, uin
746          uint16 pixel;          uint16 pixel;
747          PixelColour pc;          PixelColour pc;
748    
749          if (g_arch_match)          if (g_compatible_arch)
750          {          {
751                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
752                  REPEAT3                  REPEAT3
# Line 658  translate16to32(const uint16 * data, uin Line 816  translate16to32(const uint16 * data, uin
816          uint32 value;          uint32 value;
817          PixelColour pc;          PixelColour pc;
818    
819          if (g_arch_match)          if (g_compatible_arch)
820          {          {
821                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
822                  REPEAT4                  REPEAT4
# Line 787  translate24to32(const uint8 * data, uint Line 945  translate24to32(const uint8 * data, uint
945          uint32 value;          uint32 value;
946          PixelColour pc;          PixelColour pc;
947    
948          if (g_arch_match)          if (g_compatible_arch)
949          {          {
950                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
951  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 801  translate24to32(const uint8 * data, uint Line 959  translate24to32(const uint8 * data, uint
959  #else  #else
960                  REPEAT4                  REPEAT4
961                  (                  (
962                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
963                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
964                          data += 3;                   out += 4;
965                     data += 3;
966                  )                  )
967  #endif  #endif
968                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 841  translate_image(int width, int height, u Line 1000  translate_image(int width, int height, u
1000          uint8 *out;          uint8 *out;
1001          uint8 *end;          uint8 *end;
1002    
1003          /* if server and xserver bpp match, */          /*
1004          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1005          /* just return data */             and arch(endian) matches, no need to translate:
1006          if (g_arch_match)             just return data.
1007               Note: select_visual should've already ensured g_no_translate
1008               is only set for compatible depths, but the RDP depth might've
1009               changed during connection negotiations.
1010             */
1011            if (g_no_translate_image)
1012          {          {
1013                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1014                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1015                  if (g_depth == 16 && g_server_bpp == 16)                      (g_depth == 24 && g_server_depth == 24))
                         return data;  
                 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)  
1016                          return data;                          return data;
1017          }          }
1018    
# Line 858  translate_image(int width, int height, u Line 1020  translate_image(int width, int height, u
1020          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1021          end = out + size;          end = out + size;
1022    
1023          switch (g_server_bpp)          switch (g_server_depth)
1024          {          {
1025                  case 24:                  case 24:
1026                          switch (g_bpp)                          switch (g_bpp)
# Line 956  calculate_shifts(uint32 mask, int *shift Line 1118  calculate_shifts(uint32 mask, int *shift
1118          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1119  }  }
1120    
1121  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1122  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1123     */
1124    static unsigned
1125    calculate_mask_weight(uint32 mask)
1126    {
1127            unsigned weight = 0;
1128            do
1129            {
1130                    weight += (mask & 1);
1131            }
1132            while (mask >>= 1);
1133            return weight;
1134    }
1135    
1136    static BOOL
1137    select_visual()
1138  {  {
         XVisualInfo vi;  
1139          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1140          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1141          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1142          XVisualInfo template;          XVisualInfo template;
1143          Bool TrueColorVisual = False;          int i;
1144            unsigned red_weight, blue_weight, green_weight;
1145    
1146          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1147          if (g_display == NULL)  
1148            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1149            if (pfm == NULL)
1150          {          {
1151                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1152                    XCloseDisplay(g_display);
1153                  return False;                  return False;
1154          }          }
1155    
1156          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 */  
1157          template.class = TrueColor;          template.class = TrueColor;
1158          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1159            g_visual = NULL;
1160            g_no_translate_image = False;
1161            g_compatible_arch = False;
1162            if (vmatches != NULL)
1163            {
1164                    for (i = 0; i < visuals_count; ++i)
1165                    {
1166                            XVisualInfo *visual_info = &vmatches[i];
1167    
1168                            /* Try to find a no-translation visual that'll
1169                               allow us to use RDP bitmaps directly as ZPixmaps. */
1170                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1171                                                   /* R5G5B5 */
1172                                                   (visual_info->red_mask == 0x7c00) &&
1173                                                   (visual_info->green_mask == 0x3e0) &&
1174                                                   (visual_info->blue_mask == 0x1f)) ||
1175                                                  ((visual_info->depth == 16) &&
1176                                                   /* R5G6B5 */
1177                                                   (visual_info->red_mask == 0xf800) &&
1178                                                   (visual_info->green_mask == 0x7e0) &&
1179                                                   (visual_info->blue_mask == 0x1f)) ||
1180                                                  ((visual_info->depth == 24) &&
1181                                                   /* R8G8B8 */
1182                                                   (visual_info->red_mask == 0xff0000) &&
1183                                                   (visual_info->green_mask == 0xff00) &&
1184                                                   (visual_info->blue_mask == 0xff))))
1185                            {
1186                                    g_visual = visual_info->visual;
1187                                    g_depth = visual_info->depth;
1188                                    g_compatible_arch = !g_host_be;
1189                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1190                                    if (g_no_translate_image)
1191                                            /* We found the best visual */
1192                                            break;
1193                            }
1194                            else
1195                            {
1196                                    g_compatible_arch = False;
1197                            }
1198    
1199                            if (visual_info->depth > 24)
1200                            {
1201                                    /* Avoid 32-bit visuals and likes like the plague.
1202                                       They're either untested or proven to work bad
1203                                       (e.g. nvidia's Composite 32-bit visual).
1204                                       Most implementation offer a 24-bit visual anyway. */
1205                                    continue;
1206                            }
1207    
1208          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1209          while (nvisuals >= 0)                             we have a translateXtoY function. */
1210          {                          BOOL can_translate_to_bpp = False;
1211                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1212                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1213                          g_depth = (vmatches + nvisuals)->depth;                          {
1214                                    if (pfm[j].depth == visual_info->depth)
1215                                    {
1216                                            if ((pfm[j].bits_per_pixel == 16) ||
1217                                                (pfm[j].bits_per_pixel == 24) ||
1218                                                (pfm[j].bits_per_pixel == 32))
1219                                            {
1220                                                    can_translate_to_bpp = True;
1221                                            }
1222                                            break;
1223                                    }
1224                            }
1225    
1226                            /* Prefer formats which have the most colour depth.
1227                               We're being truly aristocratic here, minding each
1228                               weight on its own. */
1229                            if (can_translate_to_bpp)
1230                            {
1231                                    unsigned vis_red_weight =
1232                                            calculate_mask_weight(visual_info->red_mask);
1233                                    unsigned vis_green_weight =
1234                                            calculate_mask_weight(visual_info->green_mask);
1235                                    unsigned vis_blue_weight =
1236                                            calculate_mask_weight(visual_info->blue_mask);
1237                                    if ((vis_red_weight >= red_weight)
1238                                        && (vis_green_weight >= green_weight)
1239                                        && (vis_blue_weight >= blue_weight))
1240                                    {
1241                                            red_weight = vis_red_weight;
1242                                            green_weight = vis_green_weight;
1243                                            blue_weight = vis_blue_weight;
1244                                            g_visual = visual_info->visual;
1245                                            g_depth = visual_info->depth;
1246                                    }
1247                            }
1248                  }                  }
1249                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1250          }          }
1251    
1252          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)))  
1253          {          {
1254                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1255                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1256                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1257                    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;  
                 }  
1258          }          }
1259          else          else
1260          {          {
1261                  /* need a truecolour visual */                  template.class = PseudoColor;
1262                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1263                  {                  template.colormap_size = 256;
1264                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1265                            XGetVisualInfo(g_display,
1266                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1267                                           &template, &visuals_count);
1268                    if (vmatches == NULL)
1269                    {
1270                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1271                            XCloseDisplay(g_display);
1272                            XFree(pfm);
1273                          return False;                          return False;
1274                  }                  }
1275    
1276                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1277                  g_owncolmap = False;                  g_owncolmap = True;
1278                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1279                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1280                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1281    
1282                  /* if RGB video and everything is little endian */          g_bpp = 0;
1283                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1284                      !g_xserver_be && !g_host_be)          {
1285                    XPixmapFormatValues *pf = &pfm[i];
1286                    if (pf->depth == g_depth)
1287                  {                  {
1288                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1289                                                g_blue_shift_l == 0))  
1290                            if (g_no_translate_image)
1291                          {                          {
1292                                  g_arch_match = True;                                  switch (g_server_depth)
1293                                    {
1294                                            case 15:
1295                                            case 16:
1296                                                    if (g_bpp != 16)
1297                                                            g_no_translate_image = False;
1298                                                    break;
1299                                            case 24:
1300                                                    /* Yes, this will force image translation
1301                                                       on most modern servers which use 32 bits
1302                                                       for R8G8B8. */
1303                                                    if (g_bpp != 24)
1304                                                            g_no_translate_image = False;
1305                                                    break;
1306                                            default:
1307                                                    g_no_translate_image = False;
1308                                                    break;
1309                                    }
1310                          }                          }
                 }  
1311    
1312                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1313                  {                             there's just a single entry for every depth,
1314                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1315                            break;
1316                  }                  }
1317          }          }
1318            XFree(pfm);
1319            pfm = NULL;
1320            return True;
1321    }
1322    
1323          pfm = XListPixmapFormats(g_display, &i);  BOOL
1324          if (pfm != NULL)  ui_init(void)
1325    {
1326            int screen_num;
1327    
1328            g_display = XOpenDisplay(NULL);
1329            if (g_display == NULL)
1330          {          {
1331                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1332                     desirable, e.g. 24 bits->32 bits. */                  return False;
                 while (i--)  
                 {  
                         if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))  
                         {  
                                 g_bpp = pfm[i].bits_per_pixel;  
                         }  
                 }  
                 XFree(pfm);  
1333          }          }
1334    
         if (g_bpp < 8)  
1335          {          {
1336                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1337                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1338            }
1339    
1340            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1341            screen_num = DefaultScreen(g_display);
1342            g_x_socket = ConnectionNumber(g_display);
1343            g_screen = ScreenOfDisplay(g_display, screen_num);
1344            g_depth = DefaultDepthOfScreen(g_screen);
1345    
1346            if (!select_visual())
1347                  return False;                  return False;
1348    
1349            if (g_no_translate_image)
1350            {
1351                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1352          }          }
1353    
1354            if (g_server_depth > g_bpp)
1355            {
1356                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1357                            g_server_depth, g_bpp);
1358            }
1359    
1360            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1361                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1362    
1363          if (!g_owncolmap)          if (!g_owncolmap)
1364          {          {
1365                  g_xcolmap =                  g_xcolmap =
1366                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1367                                          AllocNone);                                          AllocNone);
1368                  if (g_depth <= 8)                  if (g_depth <= 8)
1369                          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);
1370          }          }
1371    
1372          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1373          {          {
1374                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1375                  g_ownbackstore = True;                  g_ownbackstore = True;
1376          }          }
1377    
# Line 1086  ui_init(void) Line 1382  ui_init(void)
1382          {          {
1383                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1384                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1385                    g_using_full_workarea = True;
1386          }          }
1387          else if (g_width < 0)          else if (g_width < 0)
1388          {          {
1389                  /* Percent of screen */                  /* Percent of screen */
1390                    if (-g_width >= 100)
1391                            g_using_full_workarea = True;
1392                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1393                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1394          }          }
# Line 1097  ui_init(void) Line 1396  ui_init(void)
1396          {          {
1397                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1398                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1399                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1400                  {                  {
1401                          g_width = cx;                          g_width = cx;
1402                          g_height = cy;                          g_height = cy;
1403                            g_using_full_workarea = True;
1404                  }                  }
1405                  else                  else
1406                  {                  {
1407                          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");
1408                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1409                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1410                  }                  }
1411          }          }
1412    
# Line 1122  ui_init(void) Line 1421  ui_init(void)
1421                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1422    
1423          xclip_init();          xclip_init();
1424            ewmh_init();
1425            if (g_seamless_rdp)
1426                    seamless_init();
1427    
1428          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));
1429    
1430          return True;          return True;
1431  }  }
# Line 1147  ui_deinit(void) Line 1449  ui_deinit(void)
1449          g_display = NULL;          g_display = NULL;
1450  }  }
1451    
1452    
1453    static void
1454    get_window_attribs(XSetWindowAttributes * attribs)
1455    {
1456            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1457            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1458            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1459            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1460            attribs->override_redirect = g_fullscreen;
1461            attribs->colormap = g_xcolmap;
1462    }
1463    
1464    static void
1465    get_input_mask(long *input_mask)
1466    {
1467            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1468                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1469    
1470            if (g_sendmotion)
1471                    *input_mask |= PointerMotionMask;
1472            if (g_ownbackstore)
1473                    *input_mask |= ExposureMask;
1474            if (g_fullscreen || g_grab_keyboard)
1475                    *input_mask |= EnterWindowMask;
1476            if (g_grab_keyboard)
1477                    *input_mask |= LeaveWindowMask;
1478    }
1479    
1480  BOOL  BOOL
1481  ui_create_window(void)  ui_create_window(void)
1482  {  {
# Line 1163  ui_create_window(void) Line 1493  ui_create_window(void)
1493          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1494          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1495    
1496          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1497          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1498          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1499          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1500          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1501    
1502            get_window_attribs(&attribs);
1503    
1504          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,          g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1505                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1175  ui_create_window(void) Line 1507  ui_create_window(void)
1507                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1508    
1509          if (g_gc == NULL)          if (g_gc == NULL)
1510            {
1511                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1512                    ui_reset_clip();
1513            }
1514    
1515          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1516                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1192  ui_create_window(void) Line 1527  ui_create_window(void)
1527          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1528    
1529          if (g_hide_decorations)          if (g_hide_decorations)
1530                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1531    
1532          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1533          if (classhints != NULL)          if (classhints != NULL)
# Line 1206  ui_create_window(void) Line 1541  ui_create_window(void)
1541          if (sizehints)          if (sizehints)
1542          {          {
1543                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1544                    if (g_pos)
1545                            sizehints->flags |= PPosition;
1546                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1547                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1548                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 1217  ui_create_window(void) Line 1554  ui_create_window(void)
1554                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1555          }          }
1556    
1557          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;  
1558    
1559          if (g_IM != NULL)          if (g_IM != NULL)
1560          {          {
# Line 1240  ui_create_window(void) Line 1567  ui_create_window(void)
1567          }          }
1568    
1569          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
         XMapWindow(g_display, g_wnd);  
1570    
1571            XMapWindow(g_display, g_wnd);
1572          /* wait for VisibilityNotify */          /* wait for VisibilityNotify */
1573          do          do
1574          {          {
# Line 1312  xwin_toggle_fullscreen(void) Line 1639  xwin_toggle_fullscreen(void)
1639  {  {
1640          Pixmap contents = 0;          Pixmap contents = 0;
1641    
1642            if (g_seamless_active)
1643                    /* Turn off SeamlessRDP mode */
1644                    ui_seamless_toggle();
1645    
1646          if (!g_ownbackstore)          if (!g_ownbackstore)
1647          {          {
1648                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1332  xwin_toggle_fullscreen(void) Line 1663  xwin_toggle_fullscreen(void)
1663          }          }
1664  }  }
1665    
1666  /* Process all events in Xlib queue  static void
1667    handle_button_event(XEvent xevent, BOOL down)
1668    {
1669            uint16 button, flags = 0;
1670            g_last_gesturetime = xevent.xbutton.time;
1671            button = xkeymap_translate_button(xevent.xbutton.button);
1672            if (button == 0)
1673                    return;
1674    
1675            if (down)
1676                    flags = MOUSE_FLAG_DOWN;
1677    
1678            /* Stop moving window when button is released, regardless of cursor position */
1679            if (g_moving_wnd && (xevent.type == ButtonRelease))
1680                    g_moving_wnd = False;
1681    
1682            /* If win_button_size is nonzero, enable single app mode */
1683            if (xevent.xbutton.y < g_win_button_size)
1684            {
1685                    /*  Check from right to left: */
1686                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1687                    {
1688                            /* The close button, continue */
1689                            ;
1690                    }
1691                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1692                    {
1693                            /* The maximize/restore button. Do not send to
1694                               server.  It might be a good idea to change the
1695                               cursor or give some other visible indication
1696                               that rdesktop inhibited this click */
1697                            if (xevent.type == ButtonPress)
1698                                    return;
1699                    }
1700                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1701                    {
1702                            /* The minimize button. Iconify window. */
1703                            if (xevent.type == ButtonRelease)
1704                            {
1705                                    /* Release the mouse button outside the minimize button, to prevent the
1706                                       actual minimazation to happen */
1707                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1708                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1709                                    return;
1710                            }
1711                    }
1712                    else if (xevent.xbutton.x <= g_win_button_size)
1713                    {
1714                            /* The system menu. Ignore. */
1715                            if (xevent.type == ButtonPress)
1716                                    return;
1717                    }
1718                    else
1719                    {
1720                            /* The title bar. */
1721                            if (xevent.type == ButtonPress)
1722                            {
1723                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1724                                    {
1725                                            g_moving_wnd = True;
1726                                            g_move_x_offset = xevent.xbutton.x;
1727                                            g_move_y_offset = xevent.xbutton.y;
1728                                    }
1729                                    return;
1730                            }
1731                    }
1732            }
1733    
1734            if (xevent.xmotion.window == g_wnd)
1735            {
1736                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1737                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1738            }
1739            else
1740            {
1741                    /* SeamlessRDP */
1742                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1743                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1744            }
1745    }
1746    
1747    /* Process events in Xlib queue
1748     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1749  static int  static int
1750  xwin_process_events(void)  xwin_process_events(void)
1751  {  {
1752          XEvent xevent;          XEvent xevent;
1753          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1754          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1755          char str[256];          char str[256];
1756          Status status;          Status status;
1757            int events = 0;
1758            seamless_window *sw;
1759    
1760          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1761          {          {
1762                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1763    
# Line 1355  xwin_process_events(void) Line 1767  xwin_process_events(void)
1767                          continue;                          continue;
1768                  }                  }
1769    
                 flags = 0;  
   
1770                  switch (xevent.type)                  switch (xevent.type)
1771                  {                  {
1772                          case VisibilityNotify:                          case VisibilityNotify:
1773                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1774                                            g_Unobscured =
1775                                                    xevent.xvisibility.state == VisibilityUnobscured;
1776    
1777                                  break;                                  break;
1778                          case ClientMessage:                          case ClientMessage:
1779                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1393  xwin_process_events(void) Line 1806  xwin_process_events(void)
1806                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1807                                  }                                  }
1808    
1809                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1810                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1811    
1812                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1813                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1814                                          break;                                          break;
1815    
1816                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1817                                                             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);  
   
1818                                  break;                                  break;
1819    
1820                          case KeyRelease:                          case KeyRelease:
# Line 1418  xwin_process_events(void) Line 1822  xwin_process_events(void)
1822                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1823                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1824    
1825                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1826                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1827    
1828                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1829                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1830                                          break;                                          break;
1831    
1832                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1833                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1834                                  break;                                  break;
1835    
1836                          case ButtonPress:                          case ButtonPress:
1837                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1838                                  /* fall through */                                  break;
1839    
1840                          case ButtonRelease:                          case ButtonRelease:
1841                                  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);  
1842                                  break;                                  break;
1843    
1844                          case MotionNotify:                          case MotionNotify:
# Line 1511  xwin_process_events(void) Line 1853  xwin_process_events(void)
1853                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1854                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1855                                                         CurrentTime);                                                         CurrentTime);
1856                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1857                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1858                                    {
1859                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1860                                                           xevent.xmotion.x, xevent.xmotion.y);
1861                                    }
1862                                    else
1863                                    {
1864                                            /* SeamlessRDP */
1865                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1866                                                           xevent.xmotion.x_root,
1867                                                           xevent.xmotion.y_root);
1868                                    }
1869                                  break;                                  break;
1870    
1871                          case FocusIn:                          case FocusIn:
# Line 1555  xwin_process_events(void) Line 1908  xwin_process_events(void)
1908                                  break;                                  break;
1909    
1910                          case Expose:                          case Expose:
1911                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
1912                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
1913                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1914                                            xevent.xexpose.height,                                                    g_gc,
1915                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
1916                                                      xevent.xexpose.width, xevent.xexpose.height,
1917                                                      xevent.xexpose.x, xevent.xexpose.y);
1918                                    }
1919                                    else
1920                                    {
1921                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1922                                            if (sw)
1923                                                    XCopyArea(g_display, g_backstore,
1924                                                              xevent.xexpose.window, g_gc,
1925                                                              xevent.xexpose.x + sw->xoffset,
1926                                                              xevent.xexpose.y + sw->yoffset,
1927                                                              xevent.xexpose.width,
1928                                                              xevent.xexpose.height, xevent.xexpose.x,
1929                                                              xevent.xexpose.y);
1930                                            else
1931                                            {
1932                                                    error("Expose for unknown window 0x%lx\n",
1933                                                          xevent.xexpose.window);
1934                                            }
1935                                    }
1936    
1937                                  break;                                  break;
1938    
1939                          case MappingNotify:                          case MappingNotify:
# Line 1588  xwin_process_events(void) Line 1962  xwin_process_events(void)
1962                                  break;                                  break;
1963                          case PropertyNotify:                          case PropertyNotify:
1964                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
1965                                    if (xevent.xproperty.window == g_wnd)
1966                                            break;
1967                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
1968                                            break;
1969    
1970                                    /* seamless */
1971                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
1972                                    if (!sw)
1973                                            break;
1974    
1975                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
1976                                        && (xevent.xproperty.state == PropertyNewValue))
1977                                    {
1978                                            sw->state = ewmh_get_window_state(sw->wnd);
1979                                            seamless_send_state(sw->id, sw->state, 0);
1980                                    }
1981    
1982                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
1983                                        && (xevent.xproperty.state == PropertyNewValue))
1984                                    {
1985                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
1986                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
1987                                    }
1988    
1989                                    break;
1990                            case MapNotify:
1991                                    if (!g_seamless_active)
1992                                            rdp_send_client_window_status(1);
1993                                    break;
1994                            case UnmapNotify:
1995                                    if (!g_seamless_active)
1996                                            rdp_send_client_window_status(0);
1997                                  break;                                  break;
1998                  }                  }
1999          }          }
# Line 1672  ui_create_bitmap(int width, int height, Line 2078  ui_create_bitmap(int width, int height,
2078          uint8 *tdata;          uint8 *tdata;
2079          int bitmap_pad;          int bitmap_pad;
2080    
2081          if (g_server_bpp == 8)          if (g_server_depth == 8)
2082          {          {
2083                  bitmap_pad = 8;                  bitmap_pad = 8;
2084          }          }
# Line 1704  ui_paint_bitmap(int x, int y, int cx, in Line 2110  ui_paint_bitmap(int x, int y, int cx, in
2110          uint8 *tdata;          uint8 *tdata;
2111          int bitmap_pad;          int bitmap_pad;
2112    
2113          if (g_server_bpp == 8)          if (g_server_depth == 8)
2114          {          {
2115                  bitmap_pad = 8;                  bitmap_pad = 8;
2116          }          }
# Line 1724  ui_paint_bitmap(int x, int y, int cx, in Line 2130  ui_paint_bitmap(int x, int y, int cx, in
2130          {          {
2131                  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);
2132                  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);
2133                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2134                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2135                                             x - sw->xoffset, y - sw->yoffset));
2136          }          }
2137          else          else
2138          {          {
2139                  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);
2140                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2141                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2142                                             x - sw->xoffset, y - sw->yoffset));
2143          }          }
2144    
2145          XFree(image);          XFree(image);
# Line 1848  ui_set_cursor(HCURSOR cursor) Line 2260  ui_set_cursor(HCURSOR cursor)
2260  {  {
2261          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2262          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2263            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2264  }  }
2265    
2266  void  void
# Line 1989  ui_set_colourmap(HCOLOURMAP map) Line 2402  ui_set_colourmap(HCOLOURMAP map)
2402                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2403          }          }
2404          else          else
2405            {
2406                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2407                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2408            }
2409  }  }
2410    
2411  void  void
2412  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2413  {  {
2414          XRectangle rect;          g_clip_rectangle.x = x;
2415            g_clip_rectangle.y = y;
2416          rect.x = x;          g_clip_rectangle.width = cx;
2417          rect.y = y;          g_clip_rectangle.height = cy;
2418          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);  
2419  }  }
2420    
2421  void  void
2422  ui_reset_clip(void)  ui_reset_clip(void)
2423  {  {
2424          XRectangle rect;          g_clip_rectangle.x = 0;
2425            g_clip_rectangle.y = 0;
2426          rect.x = 0;          g_clip_rectangle.width = g_width;
2427          rect.y = 0;          g_clip_rectangle.height = g_height;
2428          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);  
2429  }  }
2430    
2431  void  void
# Line 2094  ui_patblt(uint8 opcode, Line 2506  ui_patblt(uint8 opcode,
2506    
2507          if (g_ownbackstore)          if (g_ownbackstore)
2508                  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);
2509            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2510                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2511                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2512  }  }
2513    
2514  void  void
# Line 2104  ui_screenblt(uint8 opcode, Line 2519  ui_screenblt(uint8 opcode,
2519          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2520          if (g_ownbackstore)          if (g_ownbackstore)
2521          {          {
2522                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2523                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2524                          XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
                         XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,  
                                   y);  
                 }  
                 else  
                 {  
                         XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);  
                         XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,  
                                   y);  
                 }  
2525          }          }
2526          else          else
2527          {          {
2528                  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);
2529          }          }
2530    
2531            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2532                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2533                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2534    
2535          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2536  }  }
2537    
# Line 2131  ui_memblt(uint8 opcode, Line 2542  ui_memblt(uint8 opcode,
2542  {  {
2543          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2544          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);
2545            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2546                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2547                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2548          if (g_ownbackstore)          if (g_ownbackstore)
2549                  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);
2550          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2177  ui_line(uint8 opcode, Line 2591  ui_line(uint8 opcode,
2591          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2592          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2593          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2594            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2595                                                startx - sw->xoffset, starty - sw->yoffset,
2596                                                endx - sw->xoffset, endy - sw->yoffset));
2597          if (g_ownbackstore)          if (g_ownbackstore)
2598                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2599          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2274  ui_polyline(uint8 opcode, Line 2691  ui_polyline(uint8 opcode,
2691          if (g_ownbackstore)          if (g_ownbackstore)
2692                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,                  XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2693                             CoordModePrevious);                             CoordModePrevious);
2694    
2695            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2696                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2697    
2698          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2699  }  }
2700    
# Line 2429  ui_draw_text(uint8 font, uint8 flags, ui Line 2850  ui_draw_text(uint8 font, uint8 flags, ui
2850                  switch (text[i])                  switch (text[i])
2851                  {                  {
2852                          case 0xff:                          case 0xff:
2853                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2854                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
2855                                  {                                  {
2856                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2857                                          exit(1);                                          for (j = 0; j < length; j++)
2858                                                    fprintf(stderr, "%02x ", text[j]);
2859                                            fprintf(stderr, "\n");
2860                                            i = length = 0;
2861                                            break;
2862                                  }                                  }
2863                                    cache_put_text(text[i + 1], text, text[i + 2]);
2864                                    i += 3;
2865                                    length -= i;
2866                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2867                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2868                                  i = 0;                                  i = 0;
2869                                  break;                                  break;
2870    
2871                          case 0xfe:                          case 0xfe:
2872                                    /* At least one byte needs to follow */
2873                                    if (i + 2 > length)
2874                                    {
2875                                            warning("Skipping short 0xfe command:");
2876                                            for (j = 0; j < length; j++)
2877                                                    fprintf(stderr, "%02x ", text[j]);
2878                                            fprintf(stderr, "\n");
2879                                            i = length = 0;
2880                                            break;
2881                                    }
2882                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2883                                  if (entry != NULL)                                  if (entry->data != NULL)
2884                                  {                                  {
2885                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2886                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2887                                          {                                          {
2888                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2889                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2479  ui_draw_text(uint8 font, uint8 flags, ui Line 2915  ui_draw_text(uint8 font, uint8 flags, ui
2915          if (g_ownbackstore)          if (g_ownbackstore)
2916          {          {
2917                  if (boxcx > 1)                  if (boxcx > 1)
2918                    {
2919                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2920                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
2921                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2922                                                    (g_display, g_backstore, sw->wnd, g_gc,
2923                                                     boxx, boxy,
2924                                                     boxcx, boxcy,
2925                                                     boxx - sw->xoffset, boxy - sw->yoffset));
2926                    }
2927                  else                  else
2928                    {
2929                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2930                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
2931                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2932                                                    (g_display, g_backstore, sw->wnd, g_gc,
2933                                                     clipx, clipy,
2934                                                     clipcx, clipcy, clipx - sw->xoffset,
2935                                                     clipy - sw->yoffset));
2936                    }
2937          }          }
2938  }  }
2939    
# Line 2529  ui_desktop_restore(uint32 offset, int x, Line 2979  ui_desktop_restore(uint32 offset, int x,
2979          {          {
2980                  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);
2981                  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);
2982                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2983                                            (g_display, g_backstore, sw->wnd, g_gc,
2984                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2985          }          }
2986          else          else
2987          {          {
2988                  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);
2989                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2990                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2991                                             x - sw->xoffset, y - sw->yoffset));
2992          }          }
2993    
2994          XFree(image);          XFree(image);
# Line 2548  void Line 3004  void
3004  ui_end_update(void)  ui_end_update(void)
3005  {  {
3006  }  }
3007    
3008    void
3009    ui_seamless_begin()
3010    {
3011            if (!g_seamless_rdp)
3012                    return;
3013    
3014            if (g_seamless_started)
3015                    return;
3016    
3017            g_seamless_started = True;
3018    
3019            ui_seamless_toggle();
3020    }
3021    
3022    void
3023    ui_seamless_toggle()
3024    {
3025            if (!g_seamless_rdp)
3026                    return;
3027    
3028            if (!g_seamless_started)
3029                    return;
3030    
3031            if (g_seamless_active)
3032            {
3033                    /* Deactivate */
3034                    while (g_seamless_windows)
3035                    {
3036                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3037                            seamless_remove_window(g_seamless_windows);
3038                    }
3039                    XMapWindow(g_display, g_wnd);
3040            }
3041            else
3042            {
3043                    /* Activate */
3044                    XUnmapWindow(g_display, g_wnd);
3045                    seamless_send_sync();
3046            }
3047    
3048            g_seamless_active = !g_seamless_active;
3049    }
3050    
3051    void
3052    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3053    {
3054            Window wnd;
3055            XSetWindowAttributes attribs;
3056            XClassHint *classhints;
3057            XSizeHints *sizehints;
3058            long input_mask;
3059            seamless_window *sw, *sw_parent;
3060    
3061            if (!g_seamless_active)
3062                    return;
3063    
3064            /* Ignore CREATEs for existing windows */
3065            sw = seamless_get_window_by_id(id);
3066            if (sw)
3067                    return;
3068    
3069            get_window_attribs(&attribs);
3070            attribs.override_redirect = False;
3071    
3072            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3073                                InputOutput, g_visual,
3074                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3075                                CWBorderPixel, &attribs);
3076    
3077            XStoreName(g_display, wnd, "SeamlessRDP");
3078            ewmh_set_wm_name(wnd, "SeamlessRDP");
3079    
3080            mwm_hide_decorations(wnd);
3081    
3082            classhints = XAllocClassHint();
3083            if (classhints != NULL)
3084            {
3085                    classhints->res_name = "rdesktop";
3086                    classhints->res_class = "SeamlessRDP";
3087                    XSetClassHint(g_display, wnd, classhints);
3088                    XFree(classhints);
3089            }
3090    
3091            /* WM_NORMAL_HINTS */
3092            sizehints = XAllocSizeHints();
3093            if (sizehints != NULL)
3094            {
3095                    sizehints->flags = USPosition;
3096                    XSetWMNormalHints(g_display, wnd, sizehints);
3097                    XFree(sizehints);
3098            }
3099    
3100            /* Set WM_TRANSIENT_FOR, if necessary */
3101            if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3102            {
3103                    sw_parent = seamless_get_window_by_id(parent);
3104                    if (sw_parent)
3105                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3106                    else
3107                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3108            }
3109    
3110    
3111            /* FIXME: Support for Input Context:s */
3112    
3113            get_input_mask(&input_mask);
3114            input_mask |= PropertyChangeMask;
3115    
3116            XSelectInput(g_display, wnd, input_mask);
3117    
3118            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3119               seamless window, we could try to close the window on the
3120               serverside, instead of terminating rdesktop */
3121            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3122    
3123            sw = malloc(sizeof(seamless_window));
3124            sw->wnd = wnd;
3125            sw->id = id;
3126            sw->parent = parent;
3127            sw->xoffset = 0;
3128            sw->yoffset = 0;
3129            sw->width = 0;
3130            sw->height = 0;
3131            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3132            sw->desktop = 0;
3133            sw->next = g_seamless_windows;
3134            g_seamless_windows = sw;
3135    }
3136    
3137    
3138    void
3139    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3140    {
3141            seamless_window *sw;
3142    
3143            if (!g_seamless_active)
3144                    return;
3145    
3146            sw = seamless_get_window_by_id(id);
3147            if (!sw)
3148            {
3149                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3150                    return;
3151            }
3152    
3153            XDestroyWindow(g_display, sw->wnd);
3154            seamless_remove_window(sw);
3155    }
3156    
3157    
3158    void
3159    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3160    {
3161            seamless_window *sw;
3162    
3163            if (!g_seamless_active)
3164                    return;
3165    
3166            sw = seamless_get_window_by_id(id);
3167            if (!sw)
3168            {
3169                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3170                    return;
3171            }
3172    
3173            if (!width || !height)
3174                    /* X11 windows must be at least 1x1 */
3175                    return;
3176    
3177            /* About MAX and MIN: Windows allows moving a window outside
3178               the desktop. This happens, for example, when maximizing an
3179               application. In this case, the position is set to something
3180               like -4,-4,1288,1032. Many WMs does not allow windows
3181               outside the desktop, however. Therefore, clip the window
3182               ourselves. */
3183            sw->xoffset = MAX(0, x);
3184            sw->yoffset = MAX(0, y);
3185            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3186            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3187    
3188            /* If we move the window in a maximized state, then KDE won't
3189               accept restoration */
3190            switch (sw->state)
3191            {
3192                    case SEAMLESSRDP_MINIMIZED:
3193                    case SEAMLESSRDP_MAXIMIZED:
3194                            return;
3195            }
3196    
3197            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3198            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3199    }
3200    
3201    
3202    void
3203    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3204    {
3205            seamless_window *sw;
3206    
3207            if (!g_seamless_active)
3208                    return;
3209    
3210            sw = seamless_get_window_by_id(id);
3211            if (!sw)
3212            {
3213                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3214                    return;
3215            }
3216    
3217            /* FIXME: Might want to convert the name for non-EWMH WMs */
3218            XStoreName(g_display, sw->wnd, title);
3219            ewmh_set_wm_name(sw->wnd, title);
3220    }
3221    
3222    
3223    void
3224    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3225    {
3226            seamless_window *sw;
3227    
3228            if (!g_seamless_active)
3229                    return;
3230    
3231            sw = seamless_get_window_by_id(id);
3232            if (!sw)
3233            {
3234                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3235                    return;
3236            }
3237    
3238            switch (state)
3239            {
3240                    case SEAMLESSRDP_NORMAL:
3241                    case SEAMLESSRDP_MAXIMIZED:
3242                            ewmh_change_state(sw->wnd, state);
3243                            XMapWindow(g_display, sw->wnd);
3244                            break;
3245                    case SEAMLESSRDP_MINIMIZED:
3246                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3247                               the Window Manager should probably just ignore the request, since
3248                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3249                               such as minimization, rather than an independent state." Besides,
3250                               XIconifyWindow is easier. */
3251                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3252                            {
3253                                    XWMHints *hints;
3254                                    hints = XAllocWMHints();
3255                                    hints->flags = StateHint;
3256                                    hints->initial_state = IconicState;
3257                                    XSetWMHints(g_display, sw->wnd, hints);
3258                                    XFree(hints);
3259                                    XMapWindow(g_display, sw->wnd);
3260                            }
3261                            else
3262                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3263                            break;
3264                    default:
3265                            warning("SeamlessRDP: Invalid state %d\n", state);
3266                            break;
3267            }
3268    
3269            /* Handle popups without parents through some ewm hints */
3270            if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3271                    ewmh_set_window_popup(sw->wnd);
3272    
3273            sw->state = state;
3274    }
3275    
3276    
3277    void
3278    ui_seamless_syncbegin(unsigned long flags)
3279    {
3280            if (!g_seamless_active)
3281                    return;
3282    
3283            /* Destroy all seamless windows */
3284            while (g_seamless_windows)
3285            {
3286                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3287                    seamless_remove_window(g_seamless_windows);
3288            }
3289    }

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

  ViewVC Help
Powered by ViewVC 1.1.26