/[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 823 by stargo, Mon Feb 28 23:30:00 2005 UTC sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c revision 1122 by astrand, Wed Mar 15 08:35:13 2006 UTC
# Line 1  Line 1 
1  /* -*- c-basic-offset: 8 -*-  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X Window System     User interface services - X Window System
4     Copyright (C) Matthew Chapman 1999-2002     Copyright (C) Matthew Chapman 1999-2005
5    
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 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            int xoffset, yoffset;
58            int width, height;
59            unsigned int state;     /* normal/minimized/maximized */
60            unsigned int desktop;
61            struct _seamless_window *next;
62    } seamless_window;
63    static seamless_window *g_seamless_windows = NULL;
64    extern BOOL g_seamless_rdp;
65    
66  extern uint32 g_embed_wnd;  extern uint32 g_embed_wnd;
67  BOOL g_enable_compose = False;  BOOL g_enable_compose = False;
68  BOOL g_Unobscured;              /* used for screenblt */  BOOL g_Unobscured;              /* used for screenblt */
69  static GC g_gc = NULL;  static GC g_gc = NULL;
70  static GC g_create_bitmap_gc = NULL;  static GC g_create_bitmap_gc = NULL;
71  static GC g_create_glyph_gc = NULL;  static GC g_create_glyph_gc = NULL;
72    static XRectangle g_clip_rectangle;
73  static Visual *g_visual;  static Visual *g_visual;
74    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
75       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
76       as far as we're concerned. */
77  static int g_depth;  static int g_depth;
78    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
79       This may be larger than g_depth, in which case some of the bits would
80       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
81  static int g_bpp;  static int g_bpp;
82  static XIM g_IM;  static XIM g_IM;
83  static XIC g_IC;  static XIC g_IC;
# Line 60  static XModifierKeymap *g_mod_map; Line 85  static XModifierKeymap *g_mod_map;
85  static Cursor g_current_cursor;  static Cursor g_current_cursor;
86  static HCURSOR g_null_cursor = NULL;  static HCURSOR g_null_cursor = NULL;
87  static Atom g_protocol_atom, g_kill_atom;  static Atom g_protocol_atom, g_kill_atom;
88    extern Atom g_net_wm_state_atom;
89    extern Atom g_net_wm_desktop_atom;
90  static BOOL g_focused;  static BOOL g_focused;
91  static BOOL g_mouse_in_wnd;  static BOOL g_mouse_in_wnd;
92  static BOOL g_arch_match = False;       /* set to True if RGB XServer and little endian */  /* Indicates that:
93       1) visual has 15, 16 or 24 depth and the same color channel masks
94          as its RDP equivalent (implies X server is LE),
95       2) host is LE
96       This will trigger an optimization whose real value is questionable.
97    */
98    static BOOL g_compatible_arch;
99    /* Indicates whether RDP's bitmaps and our XImages have the same
100       binary format. If so, we can avoid an expensive translation.
101       Note that this can be true when g_compatible_arch is false,
102       e.g.:
103      
104         RDP(LE) <-> host(BE) <-> X-Server(LE)
105        
106       ('host' is the machine running rdesktop; the host simply memcpy's
107        so its endianess doesn't matter)
108     */
109    static BOOL g_no_translate_image = False;
110    
111  /* endianness */  /* endianness */
112  static BOOL g_host_be;  static BOOL g_host_be;
# Line 78  static Pixmap g_backstore = 0; Line 122  static Pixmap g_backstore = 0;
122  static BOOL g_moving_wnd;  static BOOL g_moving_wnd;
123  static int g_move_x_offset = 0;  static int g_move_x_offset = 0;
124  static int g_move_y_offset = 0;  static int g_move_y_offset = 0;
125    static BOOL g_using_full_workarea = False;
126    
127  #ifdef WITH_RDPSND  #ifdef WITH_RDPSND
128  extern int g_dsp_fd;  extern int g_dsp_fd;
# Line 90  extern BOOL g_rdpsnd; Line 135  extern BOOL g_rdpsnd;
135  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5  #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
136  typedef struct  typedef struct
137  {  {
138          uint32 flags;          unsigned long flags;
139          uint32 functions;          unsigned long functions;
140          uint32 decorations;          unsigned long decorations;
141          sint32 inputMode;          long inputMode;
142          uint32 status;          unsigned long status;
143  }  }
144  PropMotifWmHints;  PropMotifWmHints;
145    
# Line 106  typedef struct Line 151  typedef struct
151  }  }
152  PixelColour;  PixelColour;
153    
154    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
155            do { \
156                    seamless_window *sw; \
157                    XRectangle rect; \
158                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
159                        rect.x = g_clip_rectangle.x - sw->xoffset; \
160                        rect.y = g_clip_rectangle.y - sw->yoffset; \
161                        rect.width = g_clip_rectangle.width; \
162                        rect.height = g_clip_rectangle.height; \
163                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
164                        func args; \
165                    } \
166                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
167            } while (0)
168    
169    static void
170    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
171    {
172            points[0].x -= xoffset;
173            points[0].y -= yoffset;
174            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
175            points[0].x += xoffset;
176            points[0].y += yoffset;
177    }
178    
179    static void
180    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
181    {
182            points[0].x -= xoffset;
183            points[0].y -= yoffset;
184            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
185            points[0].x += xoffset;
186            points[0].y += yoffset;
187    }
188    
189  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
190  { \  { \
191          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
192            ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
193          if (g_ownbackstore) \          if (g_ownbackstore) \
194                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \                  XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
195  }  }
# Line 119  PixelColour; Line 199  PixelColour;
199          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \          XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
200  }  }
201    
202    #define FILL_POLYGON(p,np)\
203    { \
204            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
205            if (g_ownbackstore) \
206                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
207            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
208    }
209    
210    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
211    { \
212            switch (m) \
213            { \
214                    case 0: /* Outline */ \
215                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
216                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
217                            if (g_ownbackstore) \
218                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
219                            break; \
220                    case 1: /* Filled */ \
221                            XFillArc(g_display, g_wnd, g_gc, x, y, \
222                                     cx, cy, 0, 360*64); \
223                            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)); \
224                            if (g_ownbackstore) \
225                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
226                            break; \
227            } \
228    }
229    
230  /* colour maps */  /* colour maps */
231  extern BOOL g_owncolmap;  extern BOOL g_owncolmap;
232  static Colormap g_xcolmap;  static Colormap g_xcolmap;
233  static uint32 *g_colmap = NULL;  static uint32 *g_colmap = NULL;
234    
235  #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] )
236  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
237  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
238    
# Line 150  static int rop2_map[] = { Line 258  static int rop2_map[] = {
258  #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]); }
259  #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); }
260    
261    static seamless_window *
262    seamless_get_window_by_id(unsigned long id)
263    {
264            seamless_window *sw;
265            for (sw = g_seamless_windows; sw; sw = sw->next)
266            {
267                    if (sw->id == id)
268                            return sw;
269            }
270            return NULL;
271    }
272    
273    
274    static seamless_window *
275    seamless_get_window_by_wnd(Window wnd)
276    {
277            seamless_window *sw;
278            for (sw = g_seamless_windows; sw; sw = sw->next)
279            {
280                    if (sw->wnd == wnd)
281                            return sw;
282            }
283            return NULL;
284    }
285    
286    
287  static void  static void
288  mwm_hide_decorations(void)  seamless_remove_window(seamless_window * win)
289    {
290            seamless_window *sw, **prevnext = &g_seamless_windows;
291            for (sw = g_seamless_windows; sw; sw = sw->next)
292            {
293                    if (sw == win)
294                    {
295                            *prevnext = sw->next;
296                            xfree(sw);
297                            return;
298                    }
299                    prevnext = &sw->next;
300            }
301            return;
302    }
303    
304    
305    /* Move all windows except wnd to new desktop */
306    static void
307    seamless_all_to_desktop(Window wnd, unsigned int desktop)
308    {
309            seamless_window *sw;
310            for (sw = g_seamless_windows; sw; sw = sw->next)
311            {
312                    if (sw->wnd == wnd)
313                            continue;
314                    if (sw->desktop != desktop)
315                    {
316                            ewmh_move_to_desktop(sw->wnd, desktop);
317                            sw->desktop = desktop;
318                    }
319            }
320    }
321    
322    
323    static void
324    mwm_hide_decorations(Window wnd)
325  {  {
326          PropMotifWmHints motif_hints;          PropMotifWmHints motif_hints;
327          Atom hintsatom;          Atom hintsatom;
# Line 168  mwm_hide_decorations(void) Line 338  mwm_hide_decorations(void)
338                  return;                  return;
339          }          }
340    
341          XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,          XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
342                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);                          (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
343    
344  }  }
345    
346  #define SPLITCOLOUR15(colour, rv) \  #define SPLITCOLOUR15(colour, rv) \
# Line 203  mwm_hide_decorations(void) Line 374  mwm_hide_decorations(void)
374  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
375                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
376    
377    /* The following macros output the same octet sequences
378       on both BE and LE hosts: */
379    
380  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }  #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
381  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }  #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
382  #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 214  static uint32 Line 388  static uint32
388  translate_colour(uint32 colour)  translate_colour(uint32 colour)
389  {  {
390          PixelColour pc;          PixelColour pc;
391          switch (g_server_bpp)          switch (g_server_depth)
392          {          {
393                  case 15:                  case 15:
394                          SPLITCOLOUR15(colour, pc);                          SPLITCOLOUR15(colour, pc);
# Line 225  translate_colour(uint32 colour) Line 399  translate_colour(uint32 colour)
399                  case 24:                  case 24:
400                          SPLITCOLOUR24(colour, pc);                          SPLITCOLOUR24(colour, pc);
401                          break;                          break;
402                    default:
403                            /* Avoid warning */
404                            pc.red = 0;
405                            pc.green = 0;
406                            pc.blue = 0;
407                            break;
408          }          }
409          return MAKECOLOUR(pc);          return MAKECOLOUR(pc);
410  }  }
# Line 276  translate8to16(const uint8 * data, uint8 Line 456  translate8to16(const uint8 * data, uint8
456  {  {
457          uint16 value;          uint16 value;
458    
459          if (g_arch_match)          if (g_compatible_arch)
460          {          {
461                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
462                  REPEAT2                  REPEAT2
# Line 310  translate8to24(const uint8 * data, uint8 Line 490  translate8to24(const uint8 * data, uint8
490  {  {
491          uint32 value;          uint32 value;
492    
493          if (g_xserver_be)          if (g_compatible_arch)
494          {          {
495                  while (out < end)                  while (out < end)
496                  {                  {
# Line 333  translate8to32(const uint8 * data, uint8 Line 513  translate8to32(const uint8 * data, uint8
513  {  {
514          uint32 value;          uint32 value;
515    
516          if (g_arch_match)          if (g_compatible_arch)
517          {          {
518                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
519                  REPEAT4                  REPEAT4
# Line 405  translate15to24(const uint16 * data, uin Line 585  translate15to24(const uint16 * data, uin
585          uint16 pixel;          uint16 pixel;
586          PixelColour pc;          PixelColour pc;
587    
588          if (g_arch_match)          if (g_compatible_arch)
589          {          {
590                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
591                  REPEAT3                  REPEAT3
# Line 455  translate15to32(const uint16 * data, uin Line 635  translate15to32(const uint16 * data, uin
635          uint32 value;          uint32 value;
636          PixelColour pc;          PixelColour pc;
637    
638          if (g_arch_match)          if (g_compatible_arch)
639          {          {
640                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
641                  REPEAT4                  REPEAT4
# Line 563  translate16to24(const uint16 * data, uin Line 743  translate16to24(const uint16 * data, uin
743          uint16 pixel;          uint16 pixel;
744          PixelColour pc;          PixelColour pc;
745    
746          if (g_arch_match)          if (g_compatible_arch)
747          {          {
748                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
749                  REPEAT3                  REPEAT3
# Line 633  translate16to32(const uint16 * data, uin Line 813  translate16to32(const uint16 * data, uin
813          uint32 value;          uint32 value;
814          PixelColour pc;          PixelColour pc;
815    
816          if (g_arch_match)          if (g_compatible_arch)
817          {          {
818                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
819                  REPEAT4                  REPEAT4
# Line 762  translate24to32(const uint8 * data, uint Line 942  translate24to32(const uint8 * data, uint
942          uint32 value;          uint32 value;
943          PixelColour pc;          PixelColour pc;
944    
945          if (g_arch_match)          if (g_compatible_arch)
946          {          {
947                  /* *INDENT-OFF* */                  /* *INDENT-OFF* */
948  #ifdef NEED_ALIGN  #ifdef NEED_ALIGN
# Line 776  translate24to32(const uint8 * data, uint Line 956  translate24to32(const uint8 * data, uint
956  #else  #else
957                  REPEAT4                  REPEAT4
958                  (                  (
959                          *((uint32 *) out) = *((uint32 *) data);                   /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
960                          out += 4;                   *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
961                          data += 3;                   out += 4;
962                     data += 3;
963                  )                  )
964  #endif  #endif
965                  /* *INDENT-ON* */                  /* *INDENT-ON* */
# Line 816  translate_image(int width, int height, u Line 997  translate_image(int width, int height, u
997          uint8 *out;          uint8 *out;
998          uint8 *end;          uint8 *end;
999    
1000          /* if server and xserver bpp match, */          /*
1001          /* and arch(endian) matches, no need to translate */             If RDP depth and X Visual depths match,
1002          /* just return data */             and arch(endian) matches, no need to translate:
1003          if (g_arch_match)             just return data.
1004               Note: select_visual should've already ensured g_no_translate
1005               is only set for compatible depths, but the RDP depth might've
1006               changed during connection negotiations.
1007             */
1008            if (g_no_translate_image)
1009          {          {
1010                  if (g_depth == 15 && g_server_bpp == 15)                  if ((g_depth == 15 && g_server_depth == 15) ||
1011                          return data;                      (g_depth == 16 && g_server_depth == 16) ||
1012                  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)  
1013                          return data;                          return data;
1014          }          }
1015    
# Line 833  translate_image(int width, int height, u Line 1017  translate_image(int width, int height, u
1017          out = (uint8 *) xmalloc(size);          out = (uint8 *) xmalloc(size);
1018          end = out + size;          end = out + size;
1019    
1020          switch (g_server_bpp)          switch (g_server_depth)
1021          {          {
1022                  case 24:                  case 24:
1023                          switch (g_bpp)                          switch (g_bpp)
# Line 931  calculate_shifts(uint32 mask, int *shift Line 1115  calculate_shifts(uint32 mask, int *shift
1115          *shift_r = 8 - ffs(mask & ~(mask >> 1));          *shift_r = 8 - ffs(mask & ~(mask >> 1));
1116  }  }
1117    
1118  BOOL  /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1119  ui_init(void)     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1120     */
1121    static unsigned
1122    calculate_mask_weight(uint32 mask)
1123    {
1124            unsigned weight = 0;
1125            do
1126            {
1127                    weight += (mask & 1);
1128            }
1129            while (mask >>= 1);
1130            return weight;
1131    }
1132    
1133    static BOOL
1134    select_visual()
1135  {  {
         XVisualInfo vi;  
1136          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1137          uint16 test;          int pixmap_formats_count, visuals_count;
         int i, screen_num, nvisuals;  
1138          XVisualInfo *vmatches = NULL;          XVisualInfo *vmatches = NULL;
1139          XVisualInfo template;          XVisualInfo template;
1140          Bool TrueColorVisual = False;          int i;
1141            unsigned red_weight, blue_weight, green_weight;
1142    
1143          g_display = XOpenDisplay(NULL);          red_weight = blue_weight = green_weight = 0;
1144          if (g_display == NULL)  
1145            pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1146            if (pfm == NULL)
1147          {          {
1148                  error("Failed to open display: %s\n", XDisplayName(NULL));                  error("Unable to get list of pixmap formats from display.\n");
1149                    XCloseDisplay(g_display);
1150                  return False;                  return False;
1151          }          }
1152    
1153          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 */  
1154          template.class = TrueColor;          template.class = TrueColor;
1155          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);          vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1156            g_visual = NULL;
1157            g_no_translate_image = False;
1158            g_compatible_arch = False;
1159            if (vmatches != NULL)
1160            {
1161                    for (i = 0; i < visuals_count; ++i)
1162                    {
1163                            XVisualInfo *visual_info = &vmatches[i];
1164    
1165                            /* Try to find a no-translation visual that'll
1166                               allow us to use RDP bitmaps directly as ZPixmaps. */
1167                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1168                                                   /* R5G5B5 */
1169                                                   (visual_info->red_mask == 0x7c00) &&
1170                                                   (visual_info->green_mask == 0x3e0) &&
1171                                                   (visual_info->blue_mask == 0x1f)) ||
1172                                                  ((visual_info->depth == 16) &&
1173                                                   /* R5G6B5 */
1174                                                   (visual_info->red_mask == 0xf800) &&
1175                                                   (visual_info->green_mask == 0x7e0) &&
1176                                                   (visual_info->blue_mask == 0x1f)) ||
1177                                                  ((visual_info->depth == 24) &&
1178                                                   /* R8G8B8 */
1179                                                   (visual_info->red_mask == 0xff0000) &&
1180                                                   (visual_info->green_mask == 0xff00) &&
1181                                                   (visual_info->blue_mask == 0xff))))
1182                            {
1183                                    g_visual = visual_info->visual;
1184                                    g_depth = visual_info->depth;
1185                                    g_compatible_arch = !g_host_be;
1186                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1187                                    if (g_no_translate_image)
1188                                            /* We found the best visual */
1189                                            break;
1190                            }
1191                            else
1192                            {
1193                                    g_compatible_arch = False;
1194                            }
1195    
1196                            if (visual_info->depth > 24)
1197                            {
1198                                    /* Avoid 32-bit visuals and likes like the plague.
1199                                       They're either untested or proven to work bad
1200                                       (e.g. nvidia's Composite 32-bit visual).
1201                                       Most implementation offer a 24-bit visual anyway. */
1202                                    continue;
1203                            }
1204    
1205          nvisuals--;                          /* Only care for visuals, for whose BPPs (not depths!)
1206          while (nvisuals >= 0)                             we have a translateXtoY function. */
1207          {                          BOOL can_translate_to_bpp = False;
1208                  if ((vmatches + nvisuals)->depth > g_depth)                          int j;
1209                  {                          for (j = 0; j < pixmap_formats_count; ++j)
1210                          g_depth = (vmatches + nvisuals)->depth;                          {
1211                                    if (pfm[j].depth == visual_info->depth)
1212                                    {
1213                                            if ((pfm[j].bits_per_pixel == 16) ||
1214                                                (pfm[j].bits_per_pixel == 24) ||
1215                                                (pfm[j].bits_per_pixel == 32))
1216                                            {
1217                                                    can_translate_to_bpp = True;
1218                                            }
1219                                            break;
1220                                    }
1221                            }
1222    
1223                            /* Prefer formats which have the most colour depth.
1224                               We're being truly aristocratic here, minding each
1225                               weight on its own. */
1226                            if (can_translate_to_bpp)
1227                            {
1228                                    unsigned vis_red_weight =
1229                                            calculate_mask_weight(visual_info->red_mask);
1230                                    unsigned vis_green_weight =
1231                                            calculate_mask_weight(visual_info->green_mask);
1232                                    unsigned vis_blue_weight =
1233                                            calculate_mask_weight(visual_info->blue_mask);
1234                                    if ((vis_red_weight >= red_weight)
1235                                        && (vis_green_weight >= green_weight)
1236                                        && (vis_blue_weight >= blue_weight))
1237                                    {
1238                                            red_weight = vis_red_weight;
1239                                            green_weight = vis_green_weight;
1240                                            blue_weight = vis_blue_weight;
1241                                            g_visual = visual_info->visual;
1242                                            g_depth = visual_info->depth;
1243                                    }
1244                            }
1245                  }                  }
1246                  nvisuals--;                  XFree(vmatches);
                 TrueColorVisual = True;  
1247          }          }
1248    
1249          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)))  
1250          {          {
1251                  /* we use a colourmap, so the default visual should do */                  g_owncolmap = False;
1252                  g_visual = DefaultVisualOfScreen(g_screen);                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1253                  g_depth = DefaultDepthOfScreen(g_screen);                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1254                    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;  
                 }  
1255          }          }
1256          else          else
1257          {          {
1258                  /* need a truecolour visual */                  template.class = PseudoColor;
1259                  if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))                  template.depth = 8;
1260                  {                  template.colormap_size = 256;
1261                          error("The display does not support true colour - high colour support unavailable.\n");                  vmatches =
1262                            XGetVisualInfo(g_display,
1263                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1264                                           &template, &visuals_count);
1265                    if (vmatches == NULL)
1266                    {
1267                            error("No usable TrueColor or PseudoColor visuals on this display.\n");
1268                            XCloseDisplay(g_display);
1269                            XFree(pfm);
1270                          return False;                          return False;
1271                  }                  }
1272    
1273                  g_visual = vi.visual;                  /* we use a colourmap, so the default visual should do */
1274                  g_owncolmap = False;                  g_owncolmap = True;
1275                  calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);                  g_visual = vmatches[0].visual;
1276                  calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);                  g_depth = vmatches[0].depth;
1277                  calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);          }
1278    
1279                  /* if RGB video and everything is little endian */          g_bpp = 0;
1280                  if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&          for (i = 0; i < pixmap_formats_count; ++i)
1281                      !g_xserver_be && !g_host_be)          {
1282                    XPixmapFormatValues *pf = &pfm[i];
1283                    if (pf->depth == g_depth)
1284                  {                  {
1285                          if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&                          g_bpp = pf->bits_per_pixel;
1286                                                g_blue_shift_l == 0))  
1287                            if (g_no_translate_image)
1288                          {                          {
1289                                  g_arch_match = True;                                  switch (g_server_depth)
1290                                    {
1291                                            case 15:
1292                                            case 16:
1293                                                    if (g_bpp != 16)
1294                                                            g_no_translate_image = False;
1295                                                    break;
1296                                            case 24:
1297                                                    /* Yes, this will force image translation
1298                                                       on most modern servers which use 32 bits
1299                                                       for R8G8B8. */
1300                                                    if (g_bpp != 24)
1301                                                            g_no_translate_image = False;
1302                                                    break;
1303                                            default:
1304                                                    g_no_translate_image = False;
1305                                                    break;
1306                                    }
1307                          }                          }
                 }  
1308    
1309                  if (g_arch_match)                          /* Pixmap formats list is a depth-to-bpp mapping --
1310                  {                             there's just a single entry for every depth,
1311                          DEBUG(("Architectures match, enabling little endian optimisations.\n"));                             so we can safely break here */
1312                            break;
1313                  }                  }
1314          }          }
1315            XFree(pfm);
1316            pfm = NULL;
1317            return True;
1318    }
1319    
1320          pfm = XListPixmapFormats(g_display, &i);  BOOL
1321          if (pfm != NULL)  ui_init(void)
1322    {
1323            int screen_num;
1324    
1325            g_display = XOpenDisplay(NULL);
1326            if (g_display == NULL)
1327          {          {
1328                  /* Use maximum bpp for this depth - this is generally                  error("Failed to open display: %s\n", XDisplayName(NULL));
1329                     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);  
1330          }          }
1331    
         if (g_bpp < 8)  
1332          {          {
1333                  error("Less than 8 bpp not currently supported.\n");                  uint16 endianess_test = 1;
1334                  XCloseDisplay(g_display);                  g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1335            }
1336    
1337            g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1338            screen_num = DefaultScreen(g_display);
1339            g_x_socket = ConnectionNumber(g_display);
1340            g_screen = ScreenOfDisplay(g_display, screen_num);
1341            g_depth = DefaultDepthOfScreen(g_screen);
1342    
1343            if (!select_visual())
1344                  return False;                  return False;
1345    
1346            if (g_no_translate_image)
1347            {
1348                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1349          }          }
1350    
1351            if (g_server_depth > g_bpp)
1352            {
1353                    warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1354                            g_server_depth, g_bpp);
1355            }
1356    
1357            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1358                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1359    
1360          if (!g_owncolmap)          if (!g_owncolmap)
1361          {          {
1362                  g_xcolmap =                  g_xcolmap =
1363                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,                          XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1364                                          AllocNone);                                          AllocNone);
1365                  if (g_depth <= 8)                  if (g_depth <= 8)
1366                          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);
1367          }          }
1368    
1369          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))          if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1370          {          {
1371                  warning("External BackingStore not available, using internal\n");                  warning("External BackingStore not available. Using internal.\n");
1372                  g_ownbackstore = True;                  g_ownbackstore = True;
1373          }          }
1374    
# Line 1061  ui_init(void) Line 1379  ui_init(void)
1379          {          {
1380                  g_width = WidthOfScreen(g_screen);                  g_width = WidthOfScreen(g_screen);
1381                  g_height = HeightOfScreen(g_screen);                  g_height = HeightOfScreen(g_screen);
1382                    g_using_full_workarea = True;
1383          }          }
1384          else if (g_width < 0)          else if (g_width < 0)
1385          {          {
1386                  /* Percent of screen */                  /* Percent of screen */
1387                    if (-g_width >= 100)
1388                            g_using_full_workarea = True;
1389                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;                  g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1390                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;                  g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1391          }          }
# Line 1072  ui_init(void) Line 1393  ui_init(void)
1393          {          {
1394                  /* Fetch geometry from _NET_WORKAREA */                  /* Fetch geometry from _NET_WORKAREA */
1395                  uint32 x, y, cx, cy;                  uint32 x, y, cx, cy;
   
1396                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)                  if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1397                  {                  {
1398                          g_width = cx;                          g_width = cx;
1399                          g_height = cy;                          g_height = cy;
1400                            g_using_full_workarea = True;
1401                  }                  }
1402                  else                  else
1403                  {                  {
1404                          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");
1405                          g_width = 800;                          g_width = WidthOfScreen(g_screen);
1406                          g_height = 600;                          g_height = HeightOfScreen(g_screen);
1407                  }                  }
1408          }          }
1409    
# Line 1097  ui_init(void) Line 1418  ui_init(void)
1418                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);                  g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1419    
1420          xclip_init();          xclip_init();
1421            ewmh_init();
1422            if (g_seamless_rdp)
1423                    seamless_init();
1424    
1425          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));
1426    
1427          return True;          return True;
1428  }  }
# Line 1122  ui_deinit(void) Line 1446  ui_deinit(void)
1446          g_display = NULL;          g_display = NULL;
1447  }  }
1448    
1449    
1450    static void
1451    get_window_attribs(XSetWindowAttributes * attribs)
1452    {
1453            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1454            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1455            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1456            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1457            attribs->override_redirect = g_fullscreen;
1458            attribs->colormap = g_xcolmap;
1459    }
1460    
1461    static void
1462    get_input_mask(long *input_mask)
1463    {
1464            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1465                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1466    
1467            if (g_sendmotion)
1468                    *input_mask |= PointerMotionMask;
1469            if (g_ownbackstore)
1470                    *input_mask |= ExposureMask;
1471            if (g_fullscreen || g_grab_keyboard)
1472                    *input_mask |= EnterWindowMask;
1473            if (g_grab_keyboard)
1474                    *input_mask |= LeaveWindowMask;
1475    }
1476    
1477  BOOL  BOOL
1478  ui_create_window(void)  ui_create_window(void)
1479  {  {
# Line 1138  ui_create_window(void) Line 1490  ui_create_window(void)
1490          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;          wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1491          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;          wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1492    
1493          attribs.background_pixel = BlackPixelOfScreen(g_screen);          /* Handle -x-y portion of geometry string */
1494          attribs.border_pixel = WhitePixelOfScreen(g_screen);          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1495          attribs.backing_store = g_ownbackstore ? NotUseful : Always;                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1496          attribs.override_redirect = g_fullscreen;          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1497          attribs.colormap = g_xcolmap;                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1498    
1499            get_window_attribs(&attribs);
1500    
1501          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,
1502                                wndheight, 0, g_depth, InputOutput, g_visual,                                wndheight, 0, g_depth, InputOutput, g_visual,
# Line 1150  ui_create_window(void) Line 1504  ui_create_window(void)
1504                                CWBorderPixel, &attribs);                                CWBorderPixel, &attribs);
1505    
1506          if (g_gc == NULL)          if (g_gc == NULL)
1507            {
1508                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1509                    ui_reset_clip();
1510            }
1511    
1512          if (g_create_bitmap_gc == NULL)          if (g_create_bitmap_gc == NULL)
1513                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);                  g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
# Line 1167  ui_create_window(void) Line 1524  ui_create_window(void)
1524          XStoreName(g_display, g_wnd, g_title);          XStoreName(g_display, g_wnd, g_title);
1525    
1526          if (g_hide_decorations)          if (g_hide_decorations)
1527                  mwm_hide_decorations();                  mwm_hide_decorations(g_wnd);
1528    
1529          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1530          if (classhints != NULL)          if (classhints != NULL)
# Line 1181  ui_create_window(void) Line 1538  ui_create_window(void)
1538          if (sizehints)          if (sizehints)
1539          {          {
1540                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1541                    if (g_pos)
1542                            sizehints->flags |= PPosition;
1543                  sizehints->min_width = sizehints->max_width = g_width;                  sizehints->min_width = sizehints->max_width = g_width;
1544                  sizehints->min_height = sizehints->max_height = g_height;                  sizehints->min_height = sizehints->max_height = g_height;
1545                  XSetWMNormalHints(g_display, g_wnd, sizehints);                  XSetWMNormalHints(g_display, g_wnd, sizehints);
# Line 1192  ui_create_window(void) Line 1551  ui_create_window(void)
1551                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);                  XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1552          }          }
1553    
1554          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;  
1555    
1556          if (g_IM != NULL)          if (g_IM != NULL)
1557          {          {
# Line 1215  ui_create_window(void) Line 1564  ui_create_window(void)
1564          }          }
1565    
1566          XSelectInput(g_display, g_wnd, input_mask);          XSelectInput(g_display, g_wnd, input_mask);
1567          XMapWindow(g_display, g_wnd);          if (!g_seamless_rdp)
   
         /* wait for VisibilityNotify */  
         do  
1568          {          {
1569                  XMaskEvent(g_display, VisibilityChangeMask, &xevent);                  XMapWindow(g_display, g_wnd);
1570                    /* wait for VisibilityNotify */
1571                    do
1572                    {
1573                            XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1574                    }
1575                    while (xevent.type != VisibilityNotify);
1576                    g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1577          }          }
         while (xevent.type != VisibilityNotify);  
         g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;  
1578    
1579          g_focused = False;          g_focused = False;
1580          g_mouse_in_wnd = False;          g_mouse_in_wnd = False;
# Line 1287  xwin_toggle_fullscreen(void) Line 1638  xwin_toggle_fullscreen(void)
1638  {  {
1639          Pixmap contents = 0;          Pixmap contents = 0;
1640    
1641            if (g_seamless_rdp)
1642                    /* Turn off SeamlessRDP mode */
1643                    ui_seamless_toggle();
1644    
1645          if (!g_ownbackstore)          if (!g_ownbackstore)
1646          {          {
1647                  /* need to save contents of window */                  /* need to save contents of window */
# Line 1307  xwin_toggle_fullscreen(void) Line 1662  xwin_toggle_fullscreen(void)
1662          }          }
1663  }  }
1664    
1665  /* Process all events in Xlib queue  static void
1666    handle_button_event(XEvent xevent, BOOL down)
1667    {
1668            uint16 button, flags = 0;
1669            g_last_gesturetime = xevent.xbutton.time;
1670            button = xkeymap_translate_button(xevent.xbutton.button);
1671            if (button == 0)
1672                    return;
1673    
1674            if (down)
1675                    flags = MOUSE_FLAG_DOWN;
1676    
1677            /* Stop moving window when button is released, regardless of cursor position */
1678            if (g_moving_wnd && (xevent.type == ButtonRelease))
1679                    g_moving_wnd = False;
1680    
1681            /* If win_button_size is nonzero, enable single app mode */
1682            if (xevent.xbutton.y < g_win_button_size)
1683            {
1684                    /*  Check from right to left: */
1685                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1686                    {
1687                            /* The close button, continue */
1688                            ;
1689                    }
1690                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1691                    {
1692                            /* The maximize/restore button. Do not send to
1693                               server.  It might be a good idea to change the
1694                               cursor or give some other visible indication
1695                               that rdesktop inhibited this click */
1696                            if (xevent.type == ButtonPress)
1697                                    return;
1698                    }
1699                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1700                    {
1701                            /* The minimize button. Iconify window. */
1702                            if (xevent.type == ButtonRelease)
1703                            {
1704                                    /* Release the mouse button outside the minimize button, to prevent the
1705                                       actual minimazation to happen */
1706                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1707                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1708                                    return;
1709                            }
1710                    }
1711                    else if (xevent.xbutton.x <= g_win_button_size)
1712                    {
1713                            /* The system menu. Ignore. */
1714                            if (xevent.type == ButtonPress)
1715                                    return;
1716                    }
1717                    else
1718                    {
1719                            /* The title bar. */
1720                            if (xevent.type == ButtonPress)
1721                            {
1722                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1723                                    {
1724                                            g_moving_wnd = True;
1725                                            g_move_x_offset = xevent.xbutton.x;
1726                                            g_move_y_offset = xevent.xbutton.y;
1727                                    }
1728                                    return;
1729                            }
1730                    }
1731            }
1732    
1733            if (xevent.xmotion.window == g_wnd)
1734            {
1735                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1736                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1737            }
1738            else
1739            {
1740                    /* SeamlessRDP */
1741                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1742                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1743            }
1744    }
1745    
1746    /* Process events in Xlib queue
1747     Returns 0 after user quit, 1 otherwise */     Returns 0 after user quit, 1 otherwise */
1748  static int  static int
1749  xwin_process_events(void)  xwin_process_events(void)
1750  {  {
1751          XEvent xevent;          XEvent xevent;
1752          KeySym keysym;          KeySym keysym;
         uint16 button, flags;  
1753          uint32 ev_time;          uint32 ev_time;
         key_translation tr;  
1754          char str[256];          char str[256];
1755          Status status;          Status status;
1756            int events = 0;
1757            seamless_window *sw;
1758    
1759          while (XPending(g_display) > 0)          while ((XPending(g_display) > 0) && events++ < 20)
1760          {          {
1761                  XNextEvent(g_display, &xevent);                  XNextEvent(g_display, &xevent);
1762    
# Line 1330  xwin_process_events(void) Line 1766  xwin_process_events(void)
1766                          continue;                          continue;
1767                  }                  }
1768    
                 flags = 0;  
   
1769                  switch (xevent.type)                  switch (xevent.type)
1770                  {                  {
1771                          case VisibilityNotify:                          case VisibilityNotify:
1772                                  g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;                                  if (xevent.xvisibility.window == g_wnd)
1773                                            g_Unobscured =
1774                                                    xevent.xvisibility.state == VisibilityUnobscured;
1775    
1776                                  break;                                  break;
1777                          case ClientMessage:                          case ClientMessage:
1778                                  /* the window manager told us to quit */                                  /* the window manager told us to quit */
# Line 1368  xwin_process_events(void) Line 1805  xwin_process_events(void)
1805                                                        str, sizeof(str), &keysym, NULL);                                                        str, sizeof(str), &keysym, NULL);
1806                                  }                                  }
1807    
1808                                  DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1809                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1810    
1811                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1812                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1813                                          break;                                          break;
1814    
1815                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1816                                                             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);  
   
1817                                  break;                                  break;
1818    
1819                          case KeyRelease:                          case KeyRelease:
# Line 1393  xwin_process_events(void) Line 1821  xwin_process_events(void)
1821                                  XLookupString((XKeyEvent *) & xevent, str,                                  XLookupString((XKeyEvent *) & xevent, str,
1822                                                sizeof(str), &keysym, NULL);                                                sizeof(str), &keysym, NULL);
1823    
1824                                  DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,                                  DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1825                                             get_ksname(keysym)));                                             get_ksname(keysym)));
1826    
1827                                  ev_time = time(NULL);                                  ev_time = time(NULL);
1828                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))                                  if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1829                                          break;                                          break;
1830    
1831                                  tr = xkeymap_translate_key(keysym,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1832                                                             xevent.xkey.keycode, xevent.xkey.state);                                                    ev_time, False, 0);
   
                                 if (tr.scancode == 0)  
                                         break;  
   
                                 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);  
1833                                  break;                                  break;
1834    
1835                          case ButtonPress:                          case ButtonPress:
1836                                  flags = MOUSE_FLAG_DOWN;                                  handle_button_event(xevent, True);
1837                                  /* fall through */                                  break;
1838    
1839                          case ButtonRelease:                          case ButtonRelease:
1840                                  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);  
1841                                  break;                                  break;
1842    
1843                          case MotionNotify:                          case MotionNotify:
# Line 1486  xwin_process_events(void) Line 1852  xwin_process_events(void)
1852                                  if (g_fullscreen && !g_focused)                                  if (g_fullscreen && !g_focused)
1853                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,                                          XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1854                                                         CurrentTime);                                                         CurrentTime);
1855                                  rdp_send_input(time(NULL), RDP_INPUT_MOUSE,  
1856                                                 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);                                  if (xevent.xmotion.window == g_wnd)
1857                                    {
1858                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1859                                                           xevent.xmotion.x, xevent.xmotion.y);
1860                                    }
1861                                    else
1862                                    {
1863                                            /* SeamlessRDP */
1864                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1865                                                           xevent.xmotion.x_root,
1866                                                           xevent.xmotion.y_root);
1867                                    }
1868                                  break;                                  break;
1869    
1870                          case FocusIn:                          case FocusIn:
# Line 1530  xwin_process_events(void) Line 1907  xwin_process_events(void)
1907                                  break;                                  break;
1908    
1909                          case Expose:                          case Expose:
1910                                  XCopyArea(g_display, g_backstore, g_wnd, g_gc,                                  if (xevent.xexpose.window == g_wnd)
1911                                            xevent.xexpose.x, xevent.xexpose.y,                                  {
1912                                            xevent.xexpose.width,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1913                                            xevent.xexpose.height,                                                    g_gc,
1914                                            xevent.xexpose.x, xevent.xexpose.y);                                                    xevent.xexpose.x, xevent.xexpose.y,
1915                                                      xevent.xexpose.width, xevent.xexpose.height,
1916                                                      xevent.xexpose.x, xevent.xexpose.y);
1917                                    }
1918                                    else
1919                                    {
1920                                            sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1921                                            if (sw)
1922                                                    XCopyArea(g_display, g_backstore,
1923                                                              xevent.xexpose.window, g_gc,
1924                                                              xevent.xexpose.x + sw->xoffset,
1925                                                              xevent.xexpose.y + sw->yoffset,
1926                                                              xevent.xexpose.width,
1927                                                              xevent.xexpose.height, xevent.xexpose.x,
1928                                                              xevent.xexpose.y);
1929                                            else
1930                                            {
1931                                                    error("Expose for unknown window 0x%lx\n",
1932                                                          xevent.xexpose.window);
1933                                            }
1934                                    }
1935    
1936                                  break;                                  break;
1937    
1938                          case MappingNotify:                          case MappingNotify:
# Line 1563  xwin_process_events(void) Line 1961  xwin_process_events(void)
1961                                  break;                                  break;
1962                          case PropertyNotify:                          case PropertyNotify:
1963                                  xclip_handle_PropertyNotify(&xevent.xproperty);                                  xclip_handle_PropertyNotify(&xevent.xproperty);
1964                                    if (xevent.xproperty.window == g_wnd)
1965                                            break;
1966                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
1967                                            break;
1968    
1969                                    /* seamless */
1970                                    sw = seamless_get_window_by_wnd(xevent.xproperty.window);
1971                                    if (!sw)
1972                                            break;
1973    
1974                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
1975                                        && (xevent.xproperty.state == PropertyNewValue))
1976                                    {
1977                                            sw->state = ewmh_get_window_state(sw->wnd);
1978                                            seamless_send_state(sw->id, sw->state, 0);
1979                                    }
1980    
1981                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
1982                                        && (xevent.xproperty.state == PropertyNewValue))
1983                                    {
1984                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
1985                                            seamless_all_to_desktop(sw->wnd, sw->desktop);
1986                                    }
1987    
1988                                    break;
1989                            case MapNotify:
1990                                    if (!g_seamless_rdp)
1991                                            rdp_send_client_window_status(1);
1992                                    break;
1993                            case UnmapNotify:
1994                                    if (!g_seamless_rdp)
1995                                            rdp_send_client_window_status(0);
1996                                  break;                                  break;
1997                  }                  }
1998          }          }
# Line 1647  ui_create_bitmap(int width, int height, Line 2077  ui_create_bitmap(int width, int height,
2077          uint8 *tdata;          uint8 *tdata;
2078          int bitmap_pad;          int bitmap_pad;
2079    
2080          if (g_server_bpp == 8)          if (g_server_depth == 8)
2081          {          {
2082                  bitmap_pad = 8;                  bitmap_pad = 8;
2083          }          }
# Line 1679  ui_paint_bitmap(int x, int y, int cx, in Line 2109  ui_paint_bitmap(int x, int y, int cx, in
2109          uint8 *tdata;          uint8 *tdata;
2110          int bitmap_pad;          int bitmap_pad;
2111    
2112          if (g_server_bpp == 8)          if (g_server_depth == 8)
2113          {          {
2114                  bitmap_pad = 8;                  bitmap_pad = 8;
2115          }          }
# Line 1699  ui_paint_bitmap(int x, int y, int cx, in Line 2129  ui_paint_bitmap(int x, int y, int cx, in
2129          {          {
2130                  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);
2131                  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);
2132                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2133                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2134                                             x - sw->xoffset, y - sw->yoffset));
2135          }          }
2136          else          else
2137          {          {
2138                  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);
2139                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2140                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2141                                             x - sw->xoffset, y - sw->yoffset));
2142          }          }
2143    
2144          XFree(image);          XFree(image);
# Line 1823  ui_set_cursor(HCURSOR cursor) Line 2259  ui_set_cursor(HCURSOR cursor)
2259  {  {
2260          g_current_cursor = (Cursor) cursor;          g_current_cursor = (Cursor) cursor;
2261          XDefineCursor(g_display, g_wnd, g_current_cursor);          XDefineCursor(g_display, g_wnd, g_current_cursor);
2262            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2263  }  }
2264    
2265  void  void
# Line 1964  ui_set_colourmap(HCOLOURMAP map) Line 2401  ui_set_colourmap(HCOLOURMAP map)
2401                  g_colmap = (uint32 *) map;                  g_colmap = (uint32 *) map;
2402          }          }
2403          else          else
2404            {
2405                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);                  XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2406                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2407            }
2408  }  }
2409    
2410  void  void
2411  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2412  {  {
2413          XRectangle rect;          g_clip_rectangle.x = x;
2414            g_clip_rectangle.y = y;
2415          rect.x = x;          g_clip_rectangle.width = cx;
2416          rect.y = y;          g_clip_rectangle.height = cy;
2417          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);  
2418  }  }
2419    
2420  void  void
2421  ui_reset_clip(void)  ui_reset_clip(void)
2422  {  {
2423          XRectangle rect;          g_clip_rectangle.x = 0;
2424            g_clip_rectangle.y = 0;
2425          rect.x = 0;          g_clip_rectangle.width = g_width;
2426          rect.y = 0;          g_clip_rectangle.height = g_height;
2427          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);  
2428  }  }
2429    
2430  void  void
# Line 2069  ui_patblt(uint8 opcode, Line 2505  ui_patblt(uint8 opcode,
2505    
2506          if (g_ownbackstore)          if (g_ownbackstore)
2507                  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);
2508            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2509                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2510                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2511  }  }
2512    
2513  void  void
# Line 2079  ui_screenblt(uint8 opcode, Line 2518  ui_screenblt(uint8 opcode,
2518          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2519          if (g_ownbackstore)          if (g_ownbackstore)
2520          {          {
2521                  if (g_Unobscured)                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2522                  {                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2523                          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);  
                 }  
2524          }          }
2525          else          else
2526          {          {
2527                  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);
2528          }          }
2529    
2530            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2531                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2532                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2533    
2534          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2535  }  }
2536    
# Line 2106  ui_memblt(uint8 opcode, Line 2541  ui_memblt(uint8 opcode,
2541  {  {
2542          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2543          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);
2544            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2545                                    (g_display, (Pixmap) src, sw->wnd, g_gc,
2546                                     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2547          if (g_ownbackstore)          if (g_ownbackstore)
2548                  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);
2549          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2152  ui_line(uint8 opcode, Line 2590  ui_line(uint8 opcode,
2590          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2591          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2592          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2593            ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2594                                                startx - sw->xoffset, starty - sw->yoffset,
2595                                                endx - sw->xoffset, endy - sw->yoffset));
2596          if (g_ownbackstore)          if (g_ownbackstore)
2597                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);                  XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2598          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
# Line 2166  ui_rect( Line 2607  ui_rect(
2607          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE(x, y, cx, cy);
2608  }  }
2609    
2610    void
2611    ui_polygon(uint8 opcode,
2612               /* mode */ uint8 fillmode,
2613               /* dest */ POINT * point, int npoints,
2614               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2615    {
2616            uint8 style, i, ipattern[8];
2617            Pixmap fill;
2618    
2619            SET_FUNCTION(opcode);
2620    
2621            switch (fillmode)
2622            {
2623                    case ALTERNATE:
2624                            XSetFillRule(g_display, g_gc, EvenOddRule);
2625                            break;
2626                    case WINDING:
2627                            XSetFillRule(g_display, g_gc, WindingRule);
2628                            break;
2629                    default:
2630                            unimpl("fill mode %d\n", fillmode);
2631            }
2632    
2633            if (brush)
2634                    style = brush->style;
2635            else
2636                    style = 0;
2637    
2638            switch (style)
2639            {
2640                    case 0: /* Solid */
2641                            SET_FOREGROUND(fgcolour);
2642                            FILL_POLYGON((XPoint *) point, npoints);
2643                            break;
2644    
2645                    case 2: /* Hatch */
2646                            fill = (Pixmap) ui_create_glyph(8, 8,
2647                                                            hatch_patterns + brush->pattern[0] * 8);
2648                            SET_FOREGROUND(fgcolour);
2649                            SET_BACKGROUND(bgcolour);
2650                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2651                            XSetStipple(g_display, g_gc, fill);
2652                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2653                            FILL_POLYGON((XPoint *) point, npoints);
2654                            XSetFillStyle(g_display, g_gc, FillSolid);
2655                            XSetTSOrigin(g_display, g_gc, 0, 0);
2656                            ui_destroy_glyph((HGLYPH) fill);
2657                            break;
2658    
2659                    case 3: /* Pattern */
2660                            for (i = 0; i != 8; i++)
2661                                    ipattern[7 - i] = brush->pattern[i];
2662                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2663                            SET_FOREGROUND(bgcolour);
2664                            SET_BACKGROUND(fgcolour);
2665                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2666                            XSetStipple(g_display, g_gc, fill);
2667                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2668                            FILL_POLYGON((XPoint *) point, npoints);
2669                            XSetFillStyle(g_display, g_gc, FillSolid);
2670                            XSetTSOrigin(g_display, g_gc, 0, 0);
2671                            ui_destroy_glyph((HGLYPH) fill);
2672                            break;
2673    
2674                    default:
2675                            unimpl("brush %d\n", brush->style);
2676            }
2677    
2678            RESET_FUNCTION(opcode);
2679    }
2680    
2681    void
2682    ui_polyline(uint8 opcode,
2683                /* dest */ POINT * points, int npoints,
2684                /* pen */ PEN * pen)
2685    {
2686            /* TODO: set join style */
2687            SET_FUNCTION(opcode);
2688            SET_FOREGROUND(pen->colour);
2689            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2690            if (g_ownbackstore)
2691                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2692                               CoordModePrevious);
2693    
2694            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2695                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2696    
2697            RESET_FUNCTION(opcode);
2698    }
2699    
2700    void
2701    ui_ellipse(uint8 opcode,
2702               /* mode */ uint8 fillmode,
2703               /* dest */ int x, int y, int cx, int cy,
2704               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2705    {
2706            uint8 style, i, ipattern[8];
2707            Pixmap fill;
2708    
2709            SET_FUNCTION(opcode);
2710    
2711            if (brush)
2712                    style = brush->style;
2713            else
2714                    style = 0;
2715    
2716            switch (style)
2717            {
2718                    case 0: /* Solid */
2719                            SET_FOREGROUND(fgcolour);
2720                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2721                            break;
2722    
2723                    case 2: /* Hatch */
2724                            fill = (Pixmap) ui_create_glyph(8, 8,
2725                                                            hatch_patterns + brush->pattern[0] * 8);
2726                            SET_FOREGROUND(fgcolour);
2727                            SET_BACKGROUND(bgcolour);
2728                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2729                            XSetStipple(g_display, g_gc, fill);
2730                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2731                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2732                            XSetFillStyle(g_display, g_gc, FillSolid);
2733                            XSetTSOrigin(g_display, g_gc, 0, 0);
2734                            ui_destroy_glyph((HGLYPH) fill);
2735                            break;
2736    
2737                    case 3: /* Pattern */
2738                            for (i = 0; i != 8; i++)
2739                                    ipattern[7 - i] = brush->pattern[i];
2740                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2741                            SET_FOREGROUND(bgcolour);
2742                            SET_BACKGROUND(fgcolour);
2743                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2744                            XSetStipple(g_display, g_gc, fill);
2745                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2746                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2747                            XSetFillStyle(g_display, g_gc, FillSolid);
2748                            XSetTSOrigin(g_display, g_gc, 0, 0);
2749                            ui_destroy_glyph((HGLYPH) fill);
2750                            break;
2751    
2752                    default:
2753                            unimpl("brush %d\n", brush->style);
2754            }
2755    
2756            RESET_FUNCTION(opcode);
2757    }
2758    
2759  /* warning, this function only draws on wnd or backstore, not both */  /* warning, this function only draws on wnd or backstore, not both */
2760  void  void
2761  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
# Line 2221  ui_draw_glyph(int mixmode, Line 2811  ui_draw_glyph(int mixmode,
2811  }  }
2812    
2813  void  void
2814  ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,  ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2815               int clipx, int clipy, int clipcx, int clipcy,               int clipx, int clipy, int clipcx, int clipcy,
2816               int boxx, int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2817               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
2818  {  {
2819            /* TODO: use brush appropriately */
2820    
2821          FONTGLYPH *glyph;          FONTGLYPH *glyph;
2822          int i, j, xyoffset, x1, y1;          int i, j, xyoffset, x1, y1;
2823          DATABLOB *entry;          DATABLOB *entry;
# Line 2257  ui_draw_text(uint8 font, uint8 flags, in Line 2849  ui_draw_text(uint8 font, uint8 flags, in
2849                  switch (text[i])                  switch (text[i])
2850                  {                  {
2851                          case 0xff:                          case 0xff:
2852                                  if (i + 2 < length)                                  /* At least two bytes needs to follow */
2853                                          cache_put_text(text[i + 1], text, text[i + 2]);                                  if (i + 3 > length)
                                 else  
2854                                  {                                  {
2855                                          error("this shouldn't be happening\n");                                          warning("Skipping short 0xff command:");
2856                                          exit(1);                                          for (j = 0; j < length; j++)
2857                                                    fprintf(stderr, "%02x ", text[j]);
2858                                            fprintf(stderr, "\n");
2859                                            i = length = 0;
2860                                            break;
2861                                  }                                  }
2862                                    cache_put_text(text[i + 1], text, text[i + 2]);
2863                                    i += 3;
2864                                    length -= i;
2865                                  /* this will move pointer from start to first character after FF command */                                  /* this will move pointer from start to first character after FF command */
2866                                  length -= i + 3;                                  text = &(text[i]);
                                 text = &(text[i + 3]);  
2867                                  i = 0;                                  i = 0;
2868                                  break;                                  break;
2869    
2870                          case 0xfe:                          case 0xfe:
2871                                    /* At least one byte needs to follow */
2872                                    if (i + 2 > length)
2873                                    {
2874                                            warning("Skipping short 0xfe command:");
2875                                            for (j = 0; j < length; j++)
2876                                                    fprintf(stderr, "%02x ", text[j]);
2877                                            fprintf(stderr, "\n");
2878                                            i = length = 0;
2879                                            break;
2880                                    }
2881                                  entry = cache_get_text(text[i + 1]);                                  entry = cache_get_text(text[i + 1]);
2882                                  if (entry != NULL)                                  if (entry->data != NULL)
2883                                  {                                  {
2884                                          if ((((uint8 *) (entry->data))[1] ==                                          if ((((uint8 *) (entry->data))[1] == 0)
2885                                               0) && (!(flags & TEXT2_IMPLICIT_X)))                                              && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2886                                          {                                          {
2887                                                  if (flags & TEXT2_VERTICAL)                                                  if (flags & TEXT2_VERTICAL)
2888                                                          y += text[i + 2];                                                          y += text[i + 2];
# Line 2307  ui_draw_text(uint8 font, uint8 flags, in Line 2914  ui_draw_text(uint8 font, uint8 flags, in
2914          if (g_ownbackstore)          if (g_ownbackstore)
2915          {          {
2916                  if (boxcx > 1)                  if (boxcx > 1)
2917                    {
2918                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2919                                    boxy, boxcx, boxcy, boxx, boxy);                                    boxy, boxcx, boxcy, boxx, boxy);
2920                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2921                                                    (g_display, g_backstore, sw->wnd, g_gc,
2922                                                     boxx, boxy,
2923                                                     boxcx, boxcy,
2924                                                     boxx - sw->xoffset, boxy - sw->yoffset));
2925                    }
2926                  else                  else
2927                    {
2928                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,                          XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2929                                    clipy, clipcx, clipcy, clipx, clipy);                                    clipy, clipcx, clipcy, clipx, clipy);
2930                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2931                                                    (g_display, g_backstore, sw->wnd, g_gc,
2932                                                     clipx, clipy,
2933                                                     clipcx, clipcy, clipx - sw->xoffset,
2934                                                     clipy - sw->yoffset));
2935                    }
2936          }          }
2937  }  }
2938    
# Line 2357  ui_desktop_restore(uint32 offset, int x, Line 2978  ui_desktop_restore(uint32 offset, int x,
2978          {          {
2979                  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);
2980                  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);
2981                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2982                                            (g_display, g_backstore, sw->wnd, g_gc,
2983                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2984          }          }
2985          else          else
2986          {          {
2987                  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);
2988                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2989                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2990                                             x - sw->xoffset, y - sw->yoffset));
2991          }          }
2992    
2993          XFree(image);          XFree(image);
# Line 2376  void Line 3003  void
3003  ui_end_update(void)  ui_end_update(void)
3004  {  {
3005  }  }
3006    
3007    void
3008    ui_seamless_toggle()
3009    {
3010            if (g_seamless_rdp)
3011            {
3012                    /* Deactivate */
3013                    while (g_seamless_windows)
3014                    {
3015                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3016                            seamless_remove_window(g_seamless_windows);
3017                    }
3018                    XMapWindow(g_display, g_wnd);
3019            }
3020            else
3021            {
3022                    /* Activate */
3023                    if (g_win_button_size)
3024                    {
3025                            error("SeamlessRDP mode cannot be activated when using single application mode\n");
3026                            return;
3027                    }
3028                    if (!g_using_full_workarea)
3029                    {
3030                            error("SeamlessRDP mode requires a session that covers the whole screen");
3031                            return;
3032                    }
3033    
3034                    XUnmapWindow(g_display, g_wnd);
3035                    seamless_send_sync();
3036            }
3037    
3038            g_seamless_rdp = !g_seamless_rdp;
3039    }
3040    
3041    void
3042    ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3043    {
3044            Window wnd;
3045            XSetWindowAttributes attribs;
3046            XClassHint *classhints;
3047            long input_mask;
3048            seamless_window *sw, *sw_parent;
3049    
3050            /* Ignore CREATEs for existing windows */
3051            sw = seamless_get_window_by_id(id);
3052            if (sw)
3053                    return;
3054    
3055            get_window_attribs(&attribs);
3056            attribs.override_redirect = False;
3057    
3058            /* FIXME: Do not assume that -1, -1 is outside screen Consider
3059               wait with showing the window until STATE and others have
3060               been recieved. */
3061            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0,
3062                                InputOutput, g_visual,
3063                                CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3064                                CWBorderPixel, &attribs);
3065    
3066            XStoreName(g_display, wnd, "rdesktop-seamless");
3067    
3068            mwm_hide_decorations(wnd);
3069    
3070            classhints = XAllocClassHint();
3071            if (classhints != NULL)
3072            {
3073                    classhints->res_name = classhints->res_class = "rdesktop";
3074                    XSetClassHint(g_display, wnd, classhints);
3075                    XFree(classhints);
3076            }
3077    
3078            /* Set WM_TRANSIENT_FOR, if necessary */
3079            if (parent)
3080            {
3081                    sw_parent = seamless_get_window_by_id(parent);
3082                    if (sw_parent)
3083                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3084                    else
3085                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3086            }
3087    
3088            /* FIXME: Support for Input Context:s */
3089    
3090            get_input_mask(&input_mask);
3091            input_mask |= PropertyChangeMask;
3092    
3093            XSelectInput(g_display, wnd, input_mask);
3094    
3095            XMapWindow(g_display, wnd);
3096    
3097            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3098               seamless window, we could try to close the window on the
3099               serverside, instead of terminating rdesktop */
3100            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3101    
3102            sw = malloc(sizeof(seamless_window));
3103            sw->wnd = wnd;
3104            sw->id = id;
3105            sw->xoffset = 0;
3106            sw->yoffset = 0;
3107            sw->width = 0;
3108            sw->height = 0;
3109            sw->next = g_seamless_windows;
3110            g_seamless_windows = sw;
3111    }
3112    
3113    
3114    void
3115    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3116    {
3117            seamless_window *sw;
3118    
3119            sw = seamless_get_window_by_id(id);
3120            if (!sw)
3121            {
3122                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3123                    return;
3124            }
3125    
3126            XDestroyWindow(g_display, sw->wnd);
3127            seamless_remove_window(sw);
3128    }
3129    
3130    
3131    void
3132    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3133    {
3134            seamless_window *sw;
3135    
3136            sw = seamless_get_window_by_id(id);
3137            if (!sw)
3138            {
3139                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3140                    return;
3141            }
3142    
3143            if (!width || !height)
3144                    /* X11 windows must be at least 1x1 */
3145                    return;
3146    
3147            /* About MAX and MIN: Windows allows moving a window outside
3148               the desktop. This happens, for example, when maximizing an
3149               application. In this case, the position is set to something
3150               like -4,-4,1288,1032. Many WMs does not allow windows
3151               outside the desktop, however. Therefore, clip the window
3152               ourselves. */
3153            sw->xoffset = MAX(0, x);
3154            sw->yoffset = MAX(0, y);
3155            sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3156            sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3157    
3158            /* If we move the window in a maximized state, then KDE won't
3159               accept restoration */
3160            if (sw->state != SEAMLESSRDP_NORMAL)
3161                    return;
3162    
3163            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3164            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3165    }
3166    
3167    
3168    void
3169    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3170    {
3171            seamless_window *sw;
3172    
3173            sw = seamless_get_window_by_id(id);
3174            if (!sw)
3175            {
3176                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3177                    return;
3178            }
3179    
3180            XStoreName(g_display, sw->wnd, title);
3181    }
3182    
3183    
3184    void
3185    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3186    {
3187            seamless_window *sw;
3188    
3189            sw = seamless_get_window_by_id(id);
3190            if (!sw)
3191            {
3192                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3193                    return;
3194            }
3195    
3196            sw->state = state;
3197    
3198            switch (state)
3199            {
3200                    case SEAMLESSRDP_NORMAL:
3201                    case SEAMLESSRDP_MAXIMIZED:
3202                            ewmh_change_state(sw->wnd, state);
3203                            break;
3204                    case SEAMLESSRDP_MINIMIZED:
3205                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3206                               the Window Manager should probably just ignore the request, since
3207                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3208                               such as minimization, rather than an independent state." Besides,
3209                               XIconifyWindow is easier. */
3210                            XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3211                            break;
3212                    default:
3213                            warning("SeamlessRDP: Invalid state %d\n", state);
3214                            break;
3215            }
3216    }

Legend:
Removed from v.823  
changed lines
  Added in v.1122

  ViewVC Help
Powered by ViewVC 1.1.26