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

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

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

revision 49 by mmihalik, Fri Apr 19 12:06:08 2002 UTC revision 1443 by astrand, Thu Mar 6 15:39:21 2008 UTC
# Line 1  Line 1 
1  /*  /* -*- 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-2001     Copyright (C) Matthew Chapman 1999-2007
5         Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6    
7     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
8     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
9     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.     (at your option) any later version.
11      
12     This program is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.     GNU General Public License for more details.
16      
17     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# Line 20  Line 21 
21    
22  #include <X11/Xlib.h>  #include <X11/Xlib.h>
23  #include <X11/Xutil.h>  #include <X11/Xutil.h>
24    #include <X11/Xproto.h>
25    #include <unistd.h>
26    #include <sys/time.h>
27  #include <time.h>  #include <time.h>
28  #include <errno.h>  #include <errno.h>
29    #include <strings.h>
30  #include "rdesktop.h"  #include "rdesktop.h"
31    #include "xproto.h"
32    
33  extern char keymapname[16];  extern int g_width;
34  extern int keylayout;  extern int g_height;
35  extern int width;  extern int g_xpos;
36  extern int height;  extern int g_ypos;
37  extern BOOL sendmotion;  extern int g_pos;
38  extern BOOL fullscreen;  extern RD_BOOL g_sendmotion;
39    extern RD_BOOL g_fullscreen;
40  static Display *display;  extern RD_BOOL g_grab_keyboard;
41  static int x_socket;  extern RD_BOOL g_hide_decorations;
42  static Window wnd;  extern char g_title[];
43  static GC gc;  /* Color depth of the RDP session.
44  static Visual *visual;     As of RDP 5.1, it may be 8, 15, 16 or 24. */
45  static int depth;  extern int g_server_depth;
46  static int bpp;  extern int g_win_button_size;
47    
48    Display *g_display;
49    Time g_last_gesturetime;
50    static int g_x_socket;
51    static Screen *g_screen;
52    Window g_wnd;
53    
54    /* SeamlessRDP support */
55    typedef struct _seamless_group
56    {
57            Window wnd;
58            unsigned long id;
59            unsigned int refcnt;
60    } seamless_group;
61    typedef struct _seamless_window
62    {
63            Window wnd;
64            unsigned long id;
65            unsigned long behind;
66            seamless_group *group;
67            int xoffset, yoffset;
68            int width, height;
69            int state;              /* normal/minimized/maximized. */
70            unsigned int desktop;
71            struct timeval *position_timer;
72    
73            RD_BOOL outstanding_position;
74            unsigned int outpos_serial;
75            int outpos_xoffset, outpos_yoffset;
76            int outpos_width, outpos_height;
77    
78            unsigned int icon_size;
79            unsigned int icon_offset;
80            char icon_buffer[32 * 32 * 4];
81    
82            struct _seamless_window *next;
83    } seamless_window;
84    static seamless_window *g_seamless_windows = NULL;
85    static unsigned long g_seamless_focused = 0;
86    static RD_BOOL g_seamless_started = False;      /* Server end is up and running */
87    static RD_BOOL g_seamless_active = False;       /* We are currently in seamless mode */
88    static RD_BOOL g_seamless_hidden = False;       /* Desktop is hidden on server */
89    extern RD_BOOL g_seamless_rdp;
90    
91    extern uint32 g_embed_wnd;
92    RD_BOOL g_enable_compose = False;
93    RD_BOOL g_Unobscured;           /* used for screenblt */
94    static GC g_gc = NULL;
95    static GC g_create_bitmap_gc = NULL;
96    static GC g_create_glyph_gc = NULL;
97    static XRectangle g_clip_rectangle;
98    static Visual *g_visual;
99    /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
100       This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
101       as far as we're concerned. */
102    static int g_depth;
103    /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
104       This may be larger than g_depth, in which case some of the bits would
105       be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
106    static int g_bpp;
107    static XIM g_IM;
108    static XIC g_IC;
109    static XModifierKeymap *g_mod_map;
110    /* Maps logical (xmodmap -pp) pointing device buttons (0-based) back
111       to physical (1-based) indices. */
112    static unsigned char g_pointer_log_to_phys_map[16];
113    static Cursor g_current_cursor;
114    static RD_HCURSOR g_null_cursor = NULL;
115    static Atom g_protocol_atom, g_kill_atom;
116    extern Atom g_net_wm_state_atom;
117    extern Atom g_net_wm_desktop_atom;
118    static RD_BOOL g_focused;
119    static RD_BOOL g_mouse_in_wnd;
120    /* Indicates that:
121       1) visual has 15, 16 or 24 depth and the same color channel masks
122          as its RDP equivalent (implies X server is LE),
123       2) host is LE
124       This will trigger an optimization whose real value is questionable.
125    */
126    static RD_BOOL g_compatible_arch;
127    /* Indicates whether RDP's bitmaps and our XImages have the same
128       binary format. If so, we can avoid an expensive translation.
129       Note that this can be true when g_compatible_arch is false,
130       e.g.:
131      
132         RDP(LE) <-> host(BE) <-> X-Server(LE)
133        
134       ('host' is the machine running rdesktop; the host simply memcpy's
135        so its endianess doesn't matter)
136     */
137    static RD_BOOL g_no_translate_image = False;
138    
139  /* endianness */  /* endianness */
140  static BOOL host_be;  static RD_BOOL g_host_be;
141  static BOOL xserver_be;  static RD_BOOL g_xserver_be;
142    static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
143    static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
144    
145  /* software backing store */  /* software backing store */
146  static BOOL ownbackstore;  extern RD_BOOL g_ownbackstore;
147  static Pixmap backstore;  static Pixmap g_backstore = 0;
148    
149    /* Moving in single app mode */
150    static RD_BOOL g_moving_wnd;
151    static int g_move_x_offset = 0;
152    static int g_move_y_offset = 0;
153    static RD_BOOL g_using_full_workarea = False;
154    
155    #ifdef WITH_RDPSND
156    extern RD_BOOL g_rdpsnd;
157    #endif
158    
159    /* MWM decorations */
160    #define MWM_HINTS_DECORATIONS   (1L << 1)
161    #define PROP_MOTIF_WM_HINTS_ELEMENTS    5
162    typedef struct
163    {
164            unsigned long flags;
165            unsigned long functions;
166            unsigned long decorations;
167            long inputMode;
168            unsigned long status;
169    }
170    PropMotifWmHints;
171    
172    typedef struct
173    {
174            uint32 red;
175            uint32 green;
176            uint32 blue;
177    }
178    PixelColour;
179    
180    #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
181            do { \
182                    seamless_window *sw; \
183                    XRectangle rect; \
184                    if (!g_seamless_windows) break; \
185                    for (sw = g_seamless_windows; sw; sw = sw->next) { \
186                        rect.x = g_clip_rectangle.x - sw->xoffset; \
187                        rect.y = g_clip_rectangle.y - sw->yoffset; \
188                        rect.width = g_clip_rectangle.width; \
189                        rect.height = g_clip_rectangle.height; \
190                        XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
191                        func args; \
192                    } \
193                    XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
194            } while (0)
195    
196    static void
197    seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
198    {
199            points[0].x -= xoffset;
200            points[0].y -= yoffset;
201            XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
202            points[0].x += xoffset;
203            points[0].y += yoffset;
204    }
205    
206    static void
207    seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
208    {
209            points[0].x -= xoffset;
210            points[0].y -= yoffset;
211            XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
212            points[0].x += xoffset;
213            points[0].y += yoffset;
214    }
215    
216  #define FILL_RECTANGLE(x,y,cx,cy)\  #define FILL_RECTANGLE(x,y,cx,cy)\
217  { \  { \
218          XFillRectangle(display, wnd, gc, x, y, cx, cy); \          XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
219          if (ownbackstore) \          ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
220                  XFillRectangle(display, backstore, gc, x, y, cx, cy); \          if (g_ownbackstore) \
221                    XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
222    }
223    
224    #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
225    { \
226            XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
227    }
228    
229    #define FILL_POLYGON(p,np)\
230    { \
231            XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
232            if (g_ownbackstore) \
233                    XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
234            ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
235    }
236    
237    #define DRAW_ELLIPSE(x,y,cx,cy,m)\
238    { \
239            switch (m) \
240            { \
241                    case 0: /* Outline */ \
242                            XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
243                            ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
244                            if (g_ownbackstore) \
245                                    XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
246                            break; \
247                    case 1: /* Filled */ \
248                            XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
249                            ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
250                            if (g_ownbackstore) \
251                                    XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
252                            break; \
253            } \
254  }  }
255    
256  /* colour maps */  /* colour maps */
257  static BOOL owncolmap;  extern RD_BOOL g_owncolmap;
258  static Colormap xcolmap;  static Colormap g_xcolmap;
259  static uint32 white;  static uint32 *g_colmap = NULL;
260  static uint32 *colmap;  
261    #define TRANSLATE(col)          ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
262  #define TRANSLATE(col)          ( owncolmap ? col : translate_colour(colmap[col]) )  #define SET_FOREGROUND(col)     XSetForeground(g_display, g_gc, TRANSLATE(col));
263  #define SET_FOREGROUND(col)     XSetForeground(display, gc, TRANSLATE(col));  #define SET_BACKGROUND(col)     XSetBackground(g_display, g_gc, TRANSLATE(col));
 #define SET_BACKGROUND(col)     XSetBackground(display, gc, TRANSLATE(col));  
264    
265  static int rop2_map[] = {  static int rop2_map[] = {
266          GXclear,                /* 0 */          GXclear,                /* 0 */
# Line 83  static int rop2_map[] = { Line 281  static int rop2_map[] = {
281          GXset                   /* 1 */          GXset                   /* 1 */
282  };  };
283    
284  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(display, gc, rop2_map[rop2]); }  #define SET_FUNCTION(rop2)      { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
285  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(display, gc, GXcopy); }  #define RESET_FUNCTION(rop2)    { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
286    
287  static void  static seamless_window *
288  translate8(uint8 *data, uint8 *out, uint8 *end)  sw_get_window_by_id(unsigned long id)
289  {  {
290          while (out < end)          seamless_window *sw;
291                  *(out++) = (uint8)colmap[*(data++)];          for (sw = g_seamless_windows; sw; sw = sw->next)
292            {
293                    if (sw->id == id)
294                            return sw;
295            }
296            return NULL;
297  }  }
298    
299  static void  
300  translate16(uint8 *data, uint16 *out, uint16 *end)  static seamless_window *
301    sw_get_window_by_wnd(Window wnd)
302  {  {
303          while (out < end)          seamless_window *sw;
304                  *(out++) = (uint16)colmap[*(data++)];          for (sw = g_seamless_windows; sw; sw = sw->next)
305            {
306                    if (sw->wnd == wnd)
307                            return sw;
308            }
309            return NULL;
310  }  }
311    
312  /* little endian - conversion happens when colourmap is built */  
313  static void  static void
314  translate24(uint8 *data, uint8 *out, uint8 *end)  sw_remove_window(seamless_window * win)
315  {  {
316          uint32 value;          seamless_window *sw, **prevnext = &g_seamless_windows;
317            for (sw = g_seamless_windows; sw; sw = sw->next)
318            {
319                    if (sw == win)
320                    {
321                            *prevnext = sw->next;
322                            sw->group->refcnt--;
323                            if (sw->group->refcnt == 0)
324                            {
325                                    XDestroyWindow(g_display, sw->group->wnd);
326                                    xfree(sw->group);
327                            }
328                            xfree(sw->position_timer);
329                            xfree(sw);
330                            return;
331                    }
332                    prevnext = &sw->next;
333            }
334            return;
335    }
336    
337          while (out < end)  
338    /* Move all windows except wnd to new desktop */
339    static void
340    sw_all_to_desktop(Window wnd, unsigned int desktop)
341    {
342            seamless_window *sw;
343            for (sw = g_seamless_windows; sw; sw = sw->next)
344          {          {
345                  value = colmap[*(data++)];                  if (sw->wnd == wnd)
346                  *(out++) = value;                          continue;
347                  *(out++) = value >> 8;                  if (sw->desktop != desktop)
348                  *(out++) = value >> 16;                  {
349                            ewmh_move_to_desktop(sw->wnd, desktop);
350                            sw->desktop = desktop;
351                    }
352          }          }
353  }  }
354    
355    
356    /* Send our position */
357  static void  static void
358  translate32(uint8 *data, uint32 *out, uint32 *end)  sw_update_position(seamless_window * sw)
359  {  {
360          while (out < end)          XWindowAttributes wa;
361                  *(out++) = colmap[*(data++)];          int x, y;
362            Window child_return;
363            unsigned int serial;
364    
365            XGetWindowAttributes(g_display, sw->wnd, &wa);
366            XTranslateCoordinates(g_display, sw->wnd, wa.root,
367                                  -wa.border_width, -wa.border_width, &x, &y, &child_return);
368    
369            serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
370    
371            sw->outstanding_position = True;
372            sw->outpos_serial = serial;
373    
374            sw->outpos_xoffset = x;
375            sw->outpos_yoffset = y;
376            sw->outpos_width = wa.width;
377            sw->outpos_height = wa.height;
378  }  }
379    
380  static uint8 *  
381  translate_image(int width, int height, uint8 *data)  /* Check if it's time to send our position */
382    static void
383    sw_check_timers()
384  {  {
385          int size = width * height * bpp/8;          seamless_window *sw;
386          uint8 *out = xmalloc(size);          struct timeval now;
         uint8 *end = out + size;  
387    
388          switch (bpp)          gettimeofday(&now, NULL);
389            for (sw = g_seamless_windows; sw; sw = sw->next)
390          {          {
391                  case 8:                  if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
392                          translate8(data, out, end);                  {
393                          break;                          timerclear(sw->position_timer);
394                            sw_update_position(sw);
395                    }
396            }
397    }
398    
399                  case 16:  
400                          translate16(data, (uint16 *)out, (uint16 *)end);  static void
401    sw_restack_window(seamless_window * sw, unsigned long behind)
402    {
403            seamless_window *sw_above;
404    
405            /* Remove window from stack */
406            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
407            {
408                    if (sw_above->behind == sw->id)
409                          break;                          break;
410            }
411    
412                  case 24:          if (sw_above)
413                          translate24(data, out, end);                  sw_above->behind = sw->behind;
414    
415            /* And then add it at the new position */
416            for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
417            {
418                    if (sw_above->behind == behind)
419                          break;                          break;
420            }
421    
422                  case 32:          if (sw_above)
423                          translate32(data, (uint32 *)out, (uint32 *)end);                  sw_above->behind = sw->id;
424    
425            sw->behind = behind;
426    }
427    
428    
429    static void
430    sw_handle_restack(seamless_window * sw)
431    {
432            Status status;
433            Window root, parent, *children;
434            unsigned int nchildren, i;
435            seamless_window *sw_below;
436    
437            status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
438                                &root, &parent, &children, &nchildren);
439            if (!status || !nchildren)
440                    return;
441    
442            sw_below = NULL;
443    
444            i = 0;
445            while (children[i] != sw->wnd)
446            {
447                    i++;
448                    if (i >= nchildren)
449                            goto end;
450            }
451    
452            for (i++; i < nchildren; i++)
453            {
454                    sw_below = sw_get_window_by_wnd(children[i]);
455                    if (sw_below)
456                          break;                          break;
457          }          }
458    
459          return out;          if (!sw_below && !sw->behind)
460                    goto end;
461            if (sw_below && (sw_below->id == sw->behind))
462                    goto end;
463    
464            if (sw_below)
465            {
466                    seamless_send_zchange(sw->id, sw_below->id, 0);
467                    sw_restack_window(sw, sw_below->id);
468            }
469            else
470            {
471                    seamless_send_zchange(sw->id, 0, 0);
472                    sw_restack_window(sw, 0);
473            }
474    
475          end:
476            XFree(children);
477  }  }
478    
479    
480    static seamless_group *
481    sw_find_group(unsigned long id, RD_BOOL dont_create)
482    {
483            seamless_window *sw;
484            seamless_group *sg;
485            XSetWindowAttributes attribs;
486    
487            for (sw = g_seamless_windows; sw; sw = sw->next)
488            {
489                    if (sw->group->id == id)
490                            return sw->group;
491            }
492    
493            if (dont_create)
494                    return NULL;
495    
496            sg = xmalloc(sizeof(seamless_group));
497    
498            sg->wnd =
499                    XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
500                                  CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
501    
502            sg->id = id;
503            sg->refcnt = 0;
504    
505            return sg;
506    }
507    
508    
509    static void
510    mwm_hide_decorations(Window wnd)
511    {
512            PropMotifWmHints motif_hints;
513            Atom hintsatom;
514    
515            /* setup the property */
516            motif_hints.flags = MWM_HINTS_DECORATIONS;
517            motif_hints.decorations = 0;
518    
519            /* get the atom for the property */
520            hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
521            if (!hintsatom)
522            {
523                    warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
524                    return;
525            }
526    
527            XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
528                            (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
529    
530    }
531    
532    #define SPLITCOLOUR15(colour, rv) \
533    { \
534            rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
535            rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
536            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
537    }
538    
539    #define SPLITCOLOUR16(colour, rv) \
540    { \
541            rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
542            rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
543            rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
544    } \
545    
546    #define SPLITCOLOUR24(colour, rv) \
547    { \
548            rv.blue = (colour & 0xff0000) >> 16; \
549            rv.green = (colour & 0x00ff00) >> 8; \
550            rv.red = (colour & 0x0000ff); \
551    }
552    
553    #define MAKECOLOUR(pc) \
554            ((pc.red >> g_red_shift_r) << g_red_shift_l) \
555                    | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
556                    | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
557    
558  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }  #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
559  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }  #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
560  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \  #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
561                          x = (x << 16) | (x >> 16); }                          x = (x << 16) | (x >> 16); }
562    
563    /* The following macros output the same octet sequences
564       on both BE and LE hosts: */
565    
566    #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
567    #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
568    #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
569    #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
570    #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
571    #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
572    
573  static uint32  static uint32
574  translate_colour(uint32 colour)  translate_colour(uint32 colour)
575  {  {
576          switch (bpp)          PixelColour pc;
577            switch (g_server_depth)
578          {          {
579                    case 15:
580                            SPLITCOLOUR15(colour, pc);
581                            break;
582                  case 16:                  case 16:
583                          if (host_be != xserver_be)                          SPLITCOLOUR16(colour, pc);
                                 BSWAP16(colour);  
584                          break;                          break;
   
585                  case 24:                  case 24:
586                          if (xserver_be)                  case 32:
587                                  BSWAP24(colour);                          SPLITCOLOUR24(colour, pc);
588                            break;
589                    default:
590                            /* Avoid warning */
591                            pc.red = 0;
592                            pc.green = 0;
593                            pc.blue = 0;
594                          break;                          break;
595            }
596            return MAKECOLOUR(pc);
597    }
598    
599                  case 32:  /* indent is confused by UNROLL8 */
600                          if (host_be != xserver_be)  /* *INDENT-OFF* */
601                                  BSWAP32(colour);  
602    /* repeat and unroll, similar to bitmap.c */
603    /* potentialy any of the following translate */
604    /* functions can use repeat but just doing */
605    /* the most common ones */
606    
607    #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
608    /* 2 byte output repeat */
609    #define REPEAT2(stm) \
610    { \
611            while (out <= end - 8 * 2) \
612                    UNROLL8(stm) \
613            while (out < end) \
614                    { stm } \
615    }
616    /* 3 byte output repeat */
617    #define REPEAT3(stm) \
618    { \
619            while (out <= end - 8 * 3) \
620                    UNROLL8(stm) \
621            while (out < end) \
622                    { stm } \
623    }
624    /* 4 byte output repeat */
625    #define REPEAT4(stm) \
626    { \
627            while (out <= end - 8 * 4) \
628                    UNROLL8(stm) \
629            while (out < end) \
630                    { stm } \
631    }
632    /* *INDENT-ON* */
633    
634    static void
635    translate8to8(const uint8 * data, uint8 * out, uint8 * end)
636    {
637            while (out < end)
638                    *(out++) = (uint8) g_colmap[*(data++)];
639    }
640    
641    static void
642    translate8to16(const uint8 * data, uint8 * out, uint8 * end)
643    {
644            uint16 value;
645    
646            if (g_compatible_arch)
647            {
648                    /* *INDENT-OFF* */
649                    REPEAT2
650                    (
651                            *((uint16 *) out) = g_colmap[*(data++)];
652                            out += 2;
653                    )
654                    /* *INDENT-ON* */
655            }
656            else if (g_xserver_be)
657            {
658                    while (out < end)
659                    {
660                            value = (uint16) g_colmap[*(data++)];
661                            BOUT16(out, value);
662                    }
663            }
664            else
665            {
666                    while (out < end)
667                    {
668                            value = (uint16) g_colmap[*(data++)];
669                            LOUT16(out, value);
670                    }
671            }
672    }
673    
674    /* little endian - conversion happens when colourmap is built */
675    static void
676    translate8to24(const uint8 * data, uint8 * out, uint8 * end)
677    {
678            uint32 value;
679    
680            if (g_compatible_arch)
681            {
682                    while (out < end)
683                    {
684                            value = g_colmap[*(data++)];
685                            BOUT24(out, value);
686                    }
687            }
688            else
689            {
690                    while (out < end)
691                    {
692                            value = g_colmap[*(data++)];
693                            LOUT24(out, value);
694                    }
695            }
696    }
697    
698    static void
699    translate8to32(const uint8 * data, uint8 * out, uint8 * end)
700    {
701            uint32 value;
702    
703            if (g_compatible_arch)
704            {
705                    /* *INDENT-OFF* */
706                    REPEAT4
707                    (
708                            *((uint32 *) out) = g_colmap[*(data++)];
709                            out += 4;
710                    )
711                    /* *INDENT-ON* */
712            }
713            else if (g_xserver_be)
714            {
715                    while (out < end)
716                    {
717                            value = g_colmap[*(data++)];
718                            BOUT32(out, value);
719                    }
720            }
721            else
722            {
723                    while (out < end)
724                    {
725                            value = g_colmap[*(data++)];
726                            LOUT32(out, value);
727                    }
728            }
729    }
730    
731    static void
732    translate15to16(const uint16 * data, uint8 * out, uint8 * end)
733    {
734            uint16 pixel;
735            uint16 value;
736            PixelColour pc;
737    
738            if (g_xserver_be)
739            {
740                    while (out < end)
741                    {
742                            pixel = *(data++);
743                            if (g_host_be)
744                            {
745                                    BSWAP16(pixel);
746                            }
747                            SPLITCOLOUR15(pixel, pc);
748                            value = MAKECOLOUR(pc);
749                            BOUT16(out, value);
750                    }
751            }
752            else
753            {
754                    while (out < end)
755                    {
756                            pixel = *(data++);
757                            if (g_host_be)
758                            {
759                                    BSWAP16(pixel);
760                            }
761                            SPLITCOLOUR15(pixel, pc);
762                            value = MAKECOLOUR(pc);
763                            LOUT16(out, value);
764                    }
765            }
766    }
767    
768    static void
769    translate15to24(const uint16 * data, uint8 * out, uint8 * end)
770    {
771            uint32 value;
772            uint16 pixel;
773            PixelColour pc;
774    
775            if (g_compatible_arch)
776            {
777                    /* *INDENT-OFF* */
778                    REPEAT3
779                    (
780                            pixel = *(data++);
781                            SPLITCOLOUR15(pixel, pc);
782                            *(out++) = pc.blue;
783                            *(out++) = pc.green;
784                            *(out++) = pc.red;
785                    )
786                    /* *INDENT-ON* */
787            }
788            else if (g_xserver_be)
789            {
790                    while (out < end)
791                    {
792                            pixel = *(data++);
793                            if (g_host_be)
794                            {
795                                    BSWAP16(pixel);
796                            }
797                            SPLITCOLOUR15(pixel, pc);
798                            value = MAKECOLOUR(pc);
799                            BOUT24(out, value);
800                    }
801            }
802            else
803            {
804                    while (out < end)
805                    {
806                            pixel = *(data++);
807                            if (g_host_be)
808                            {
809                                    BSWAP16(pixel);
810                            }
811                            SPLITCOLOUR15(pixel, pc);
812                            value = MAKECOLOUR(pc);
813                            LOUT24(out, value);
814                    }
815            }
816    }
817    
818    static void
819    translate15to32(const uint16 * data, uint8 * out, uint8 * end)
820    {
821            uint16 pixel;
822            uint32 value;
823            PixelColour pc;
824    
825            if (g_compatible_arch)
826            {
827                    /* *INDENT-OFF* */
828                    REPEAT4
829                    (
830                            pixel = *(data++);
831                            SPLITCOLOUR15(pixel, pc);
832                            *(out++) = pc.blue;
833                            *(out++) = pc.green;
834                            *(out++) = pc.red;
835                            *(out++) = 0;
836                    )
837                    /* *INDENT-ON* */
838            }
839            else if (g_xserver_be)
840            {
841                    while (out < end)
842                    {
843                            pixel = *(data++);
844                            if (g_host_be)
845                            {
846                                    BSWAP16(pixel);
847                            }
848                            SPLITCOLOUR15(pixel, pc);
849                            value = MAKECOLOUR(pc);
850                            BOUT32(out, value);
851                    }
852            }
853            else
854            {
855                    while (out < end)
856                    {
857                            pixel = *(data++);
858                            if (g_host_be)
859                            {
860                                    BSWAP16(pixel);
861                            }
862                            SPLITCOLOUR15(pixel, pc);
863                            value = MAKECOLOUR(pc);
864                            LOUT32(out, value);
865                    }
866            }
867    }
868    
869    static void
870    translate16to16(const uint16 * data, uint8 * out, uint8 * end)
871    {
872            uint16 pixel;
873            uint16 value;
874            PixelColour pc;
875    
876            if (g_xserver_be)
877            {
878                    if (g_host_be)
879                    {
880                            while (out < end)
881                            {
882                                    pixel = *(data++);
883                                    BSWAP16(pixel);
884                                    SPLITCOLOUR16(pixel, pc);
885                                    value = MAKECOLOUR(pc);
886                                    BOUT16(out, value);
887                            }
888                    }
889                    else
890                    {
891                            while (out < end)
892                            {
893                                    pixel = *(data++);
894                                    SPLITCOLOUR16(pixel, pc);
895                                    value = MAKECOLOUR(pc);
896                                    BOUT16(out, value);
897                            }
898                    }
899            }
900            else
901            {
902                    if (g_host_be)
903                    {
904                            while (out < end)
905                            {
906                                    pixel = *(data++);
907                                    BSWAP16(pixel);
908                                    SPLITCOLOUR16(pixel, pc);
909                                    value = MAKECOLOUR(pc);
910                                    LOUT16(out, value);
911                            }
912                    }
913                    else
914                    {
915                            while (out < end)
916                            {
917                                    pixel = *(data++);
918                                    SPLITCOLOUR16(pixel, pc);
919                                    value = MAKECOLOUR(pc);
920                                    LOUT16(out, value);
921                            }
922                    }
923            }
924    }
925    
926    static void
927    translate16to24(const uint16 * data, uint8 * out, uint8 * end)
928    {
929            uint32 value;
930            uint16 pixel;
931            PixelColour pc;
932    
933            if (g_compatible_arch)
934            {
935                    /* *INDENT-OFF* */
936                    REPEAT3
937                    (
938                            pixel = *(data++);
939                            SPLITCOLOUR16(pixel, pc);
940                            *(out++) = pc.blue;
941                            *(out++) = pc.green;
942                            *(out++) = pc.red;
943                    )
944                    /* *INDENT-ON* */
945            }
946            else if (g_xserver_be)
947            {
948                    if (g_host_be)
949                    {
950                            while (out < end)
951                            {
952                                    pixel = *(data++);
953                                    BSWAP16(pixel);
954                                    SPLITCOLOUR16(pixel, pc);
955                                    value = MAKECOLOUR(pc);
956                                    BOUT24(out, value);
957                            }
958                    }
959                    else
960                    {
961                            while (out < end)
962                            {
963                                    pixel = *(data++);
964                                    SPLITCOLOUR16(pixel, pc);
965                                    value = MAKECOLOUR(pc);
966                                    BOUT24(out, value);
967                            }
968                    }
969            }
970            else
971            {
972                    if (g_host_be)
973                    {
974                            while (out < end)
975                            {
976                                    pixel = *(data++);
977                                    BSWAP16(pixel);
978                                    SPLITCOLOUR16(pixel, pc);
979                                    value = MAKECOLOUR(pc);
980                                    LOUT24(out, value);
981                            }
982                    }
983                    else
984                    {
985                            while (out < end)
986                            {
987                                    pixel = *(data++);
988                                    SPLITCOLOUR16(pixel, pc);
989                                    value = MAKECOLOUR(pc);
990                                    LOUT24(out, value);
991                            }
992                    }
993            }
994    }
995    
996    static void
997    translate16to32(const uint16 * data, uint8 * out, uint8 * end)
998    {
999            uint16 pixel;
1000            uint32 value;
1001            PixelColour pc;
1002    
1003            if (g_compatible_arch)
1004            {
1005                    /* *INDENT-OFF* */
1006                    REPEAT4
1007                    (
1008                            pixel = *(data++);
1009                            SPLITCOLOUR16(pixel, pc);
1010                            *(out++) = pc.blue;
1011                            *(out++) = pc.green;
1012                            *(out++) = pc.red;
1013                            *(out++) = 0;
1014                    )
1015                    /* *INDENT-ON* */
1016            }
1017            else if (g_xserver_be)
1018            {
1019                    if (g_host_be)
1020                    {
1021                            while (out < end)
1022                            {
1023                                    pixel = *(data++);
1024                                    BSWAP16(pixel);
1025                                    SPLITCOLOUR16(pixel, pc);
1026                                    value = MAKECOLOUR(pc);
1027                                    BOUT32(out, value);
1028                            }
1029                    }
1030                    else
1031                    {
1032                            while (out < end)
1033                            {
1034                                    pixel = *(data++);
1035                                    SPLITCOLOUR16(pixel, pc);
1036                                    value = MAKECOLOUR(pc);
1037                                    BOUT32(out, value);
1038                            }
1039                    }
1040            }
1041            else
1042            {
1043                    if (g_host_be)
1044                    {
1045                            while (out < end)
1046                            {
1047                                    pixel = *(data++);
1048                                    BSWAP16(pixel);
1049                                    SPLITCOLOUR16(pixel, pc);
1050                                    value = MAKECOLOUR(pc);
1051                                    LOUT32(out, value);
1052                            }
1053                    }
1054                    else
1055                    {
1056                            while (out < end)
1057                            {
1058                                    pixel = *(data++);
1059                                    SPLITCOLOUR16(pixel, pc);
1060                                    value = MAKECOLOUR(pc);
1061                                    LOUT32(out, value);
1062                            }
1063                    }
1064            }
1065    }
1066    
1067    static void
1068    translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1069    {
1070            uint32 pixel = 0;
1071            uint16 value;
1072            PixelColour pc;
1073    
1074            while (out < end)
1075            {
1076                    pixel = *(data++) << 16;
1077                    pixel |= *(data++) << 8;
1078                    pixel |= *(data++);
1079                    SPLITCOLOUR24(pixel, pc);
1080                    value = MAKECOLOUR(pc);
1081                    if (g_xserver_be)
1082                    {
1083                            BOUT16(out, value);
1084                    }
1085                    else
1086                    {
1087                            LOUT16(out, value);
1088                    }
1089            }
1090    }
1091    
1092    static void
1093    translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1094    {
1095            uint32 pixel;
1096            uint32 value;
1097            PixelColour pc;
1098    
1099            if (g_xserver_be)
1100            {
1101                    while (out < end)
1102                    {
1103                            pixel = *(data++) << 16;
1104                            pixel |= *(data++) << 8;
1105                            pixel |= *(data++);
1106                            SPLITCOLOUR24(pixel, pc);
1107                            value = MAKECOLOUR(pc);
1108                            BOUT24(out, value);
1109                    }
1110            }
1111            else
1112            {
1113                    while (out < end)
1114                    {
1115                            pixel = *(data++) << 16;
1116                            pixel |= *(data++) << 8;
1117                            pixel |= *(data++);
1118                            SPLITCOLOUR24(pixel, pc);
1119                            value = MAKECOLOUR(pc);
1120                            LOUT24(out, value);
1121                    }
1122            }
1123    }
1124    
1125    static void
1126    translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1127    {
1128            uint32 pixel;
1129            uint32 value;
1130            PixelColour pc;
1131    
1132            if (g_compatible_arch)
1133            {
1134                    /* *INDENT-OFF* */
1135    #ifdef NEED_ALIGN
1136                    REPEAT4
1137                    (
1138                            *(out++) = *(data++);
1139                            *(out++) = *(data++);
1140                            *(out++) = *(data++);
1141                            *(out++) = 0;
1142                    )
1143    #else
1144                    REPEAT4
1145                    (
1146                     /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1147                     *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1148                     out += 4;
1149                     data += 3;
1150                    )
1151    #endif
1152                    /* *INDENT-ON* */
1153            }
1154            else if (g_xserver_be)
1155            {
1156                    while (out < end)
1157                    {
1158                            pixel = *(data++) << 16;
1159                            pixel |= *(data++) << 8;
1160                            pixel |= *(data++);
1161                            SPLITCOLOUR24(pixel, pc);
1162                            value = MAKECOLOUR(pc);
1163                            BOUT32(out, value);
1164                    }
1165            }
1166            else
1167            {
1168                    while (out < end)
1169                    {
1170                            pixel = *(data++) << 16;
1171                            pixel |= *(data++) << 8;
1172                            pixel |= *(data++);
1173                            SPLITCOLOUR24(pixel, pc);
1174                            value = MAKECOLOUR(pc);
1175                            LOUT32(out, value);
1176                    }
1177            }
1178    }
1179    
1180    static uint8 *
1181    translate_image(int width, int height, uint8 * data)
1182    {
1183            int size;
1184            uint8 *out;
1185            uint8 *end;
1186    
1187            /*
1188               If RDP depth and X Visual depths match,
1189               and arch(endian) matches, no need to translate:
1190               just return data.
1191               Note: select_visual should've already ensured g_no_translate
1192               is only set for compatible depths, but the RDP depth might've
1193               changed during connection negotiations.
1194             */
1195    
1196            /* todo */
1197            if (g_server_depth == 32 && g_depth == 24)
1198            {
1199                    return data;
1200            }
1201    
1202            if (g_no_translate_image)
1203            {
1204                    if ((g_depth == 15 && g_server_depth == 15) ||
1205                        (g_depth == 16 && g_server_depth == 16) ||
1206                        (g_depth == 24 && g_server_depth == 24))
1207                            return data;
1208            }
1209    
1210            size = width * height * (g_bpp / 8);
1211            out = (uint8 *) xmalloc(size);
1212            end = out + size;
1213    
1214            switch (g_server_depth)
1215            {
1216                    case 24:
1217                            switch (g_bpp)
1218                            {
1219                                    case 32:
1220                                            translate24to32(data, out, end);
1221                                            break;
1222                                    case 24:
1223                                            translate24to24(data, out, end);
1224                                            break;
1225                                    case 16:
1226                                            translate24to16(data, out, end);
1227                                            break;
1228                            }
1229                            break;
1230                    case 16:
1231                            switch (g_bpp)
1232                            {
1233                                    case 32:
1234                                            translate16to32((uint16 *) data, out, end);
1235                                            break;
1236                                    case 24:
1237                                            translate16to24((uint16 *) data, out, end);
1238                                            break;
1239                                    case 16:
1240                                            translate16to16((uint16 *) data, out, end);
1241                                            break;
1242                            }
1243                            break;
1244                    case 15:
1245                            switch (g_bpp)
1246                            {
1247                                    case 32:
1248                                            translate15to32((uint16 *) data, out, end);
1249                                            break;
1250                                    case 24:
1251                                            translate15to24((uint16 *) data, out, end);
1252                                            break;
1253                                    case 16:
1254                                            translate15to16((uint16 *) data, out, end);
1255                                            break;
1256                            }
1257                            break;
1258                    case 8:
1259                            switch (g_bpp)
1260                            {
1261                                    case 8:
1262                                            translate8to8(data, out, end);
1263                                            break;
1264                                    case 16:
1265                                            translate8to16(data, out, end);
1266                                            break;
1267                                    case 24:
1268                                            translate8to24(data, out, end);
1269                                            break;
1270                                    case 32:
1271                                            translate8to32(data, out, end);
1272                                            break;
1273                            }
1274                          break;                          break;
1275          }          }
1276            return out;
1277    }
1278    
1279          return colour;  static void
1280    xwin_refresh_pointer_map(void)
1281    {
1282            unsigned char phys_to_log_map[sizeof(g_pointer_log_to_phys_map)];
1283            int i, pointer_buttons;
1284    
1285            pointer_buttons = XGetPointerMapping(g_display, phys_to_log_map, sizeof(phys_to_log_map));
1286            for (i = 0; i < pointer_buttons; ++i)
1287            {
1288                    /* This might produce multiple logical buttons mapping
1289                       to a single physical one, but hey, that's
1290                       life... */
1291                    g_pointer_log_to_phys_map[phys_to_log_map[i] - 1] = i + 1;
1292            }
1293  }  }
1294    
1295  BOOL  RD_BOOL
1296  ui_create_window(char *title)  get_key_state(unsigned int state, uint32 keysym)
1297    {
1298            int modifierpos, key, keysymMask = 0;
1299            int offset;
1300    
1301            KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1302    
1303            if (keycode == NoSymbol)
1304                    return False;
1305    
1306            for (modifierpos = 0; modifierpos < 8; modifierpos++)
1307            {
1308                    offset = g_mod_map->max_keypermod * modifierpos;
1309    
1310                    for (key = 0; key < g_mod_map->max_keypermod; key++)
1311                    {
1312                            if (g_mod_map->modifiermap[offset + key] == keycode)
1313                                    keysymMask |= 1 << modifierpos;
1314                    }
1315            }
1316    
1317            return (state & keysymMask) ? True : False;
1318    }
1319    
1320    static void
1321    calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1322    {
1323            *shift_l = ffs(mask) - 1;
1324            mask >>= *shift_l;
1325            *shift_r = 8 - ffs(mask & ~(mask >> 1));
1326    }
1327    
1328    /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1329       calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1330     */
1331    static unsigned
1332    calculate_mask_weight(uint32 mask)
1333    {
1334            unsigned weight = 0;
1335            do
1336            {
1337                    weight += (mask & 1);
1338            }
1339            while (mask >>= 1);
1340            return weight;
1341    }
1342    
1343    static RD_BOOL
1344    select_visual(int screen_num)
1345  {  {
         XSetWindowAttributes attribs;  
         XClassHint *classhints;  
         XSizeHints *sizehints;  
         unsigned long input_mask;  
1346          XPixmapFormatValues *pfm;          XPixmapFormatValues *pfm;
1347          Screen *screen;          int pixmap_formats_count, visuals_count;
1348          uint16 test;          XVisualInfo *vmatches = NULL;
1349            XVisualInfo template;
1350          int i;          int i;
1351            unsigned red_weight, blue_weight, green_weight;
1352    
1353            red_weight = blue_weight = green_weight = 0;
1354    
1355            if (g_server_depth == -1)
1356            {
1357                    g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1358            }
1359    
1360          display = XOpenDisplay(NULL);          pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1361          if (display == NULL)          if (pfm == NULL)
1362          {          {
1363                  error("Failed to open display\n");                  error("Unable to get list of pixmap formats from display.\n");
1364                    XCloseDisplay(g_display);
1365                  return False;                  return False;
1366          }          }
1367    
1368          x_socket = ConnectionNumber(display);          /* Search for best TrueColor visual */
1369          screen = DefaultScreenOfDisplay(display);          template.class = TrueColor;
1370          visual = DefaultVisualOfScreen(screen);          template.screen = screen_num;
1371          depth = DefaultDepthOfScreen(screen);          vmatches =
1372                    XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1373                                   &visuals_count);
1374            g_visual = NULL;
1375            g_no_translate_image = False;
1376            g_compatible_arch = False;
1377            if (vmatches != NULL)
1378            {
1379                    for (i = 0; i < visuals_count; ++i)
1380                    {
1381                            XVisualInfo *visual_info = &vmatches[i];
1382                            RD_BOOL can_translate_to_bpp = False;
1383                            int j;
1384    
1385                            /* Try to find a no-translation visual that'll
1386                               allow us to use RDP bitmaps directly as ZPixmaps. */
1387                            if (!g_xserver_be && (((visual_info->depth == 15) &&
1388                                                   /* R5G5B5 */
1389                                                   (visual_info->red_mask == 0x7c00) &&
1390                                                   (visual_info->green_mask == 0x3e0) &&
1391                                                   (visual_info->blue_mask == 0x1f)) ||
1392                                                  ((visual_info->depth == 16) &&
1393                                                   /* R5G6B5 */
1394                                                   (visual_info->red_mask == 0xf800) &&
1395                                                   (visual_info->green_mask == 0x7e0) &&
1396                                                   (visual_info->blue_mask == 0x1f)) ||
1397                                                  ((visual_info->depth == 24) &&
1398                                                   /* R8G8B8 */
1399                                                   (visual_info->red_mask == 0xff0000) &&
1400                                                   (visual_info->green_mask == 0xff00) &&
1401                                                   (visual_info->blue_mask == 0xff))))
1402                            {
1403                                    g_visual = visual_info->visual;
1404                                    g_depth = visual_info->depth;
1405                                    g_compatible_arch = !g_host_be;
1406                                    g_no_translate_image = (visual_info->depth == g_server_depth);
1407                                    if (g_no_translate_image)
1408                                            /* We found the best visual */
1409                                            break;
1410                            }
1411                            else
1412                            {
1413                                    g_compatible_arch = False;
1414                            }
1415    
1416                            if (visual_info->depth > 24)
1417                            {
1418                                    /* Avoid 32-bit visuals and likes like the plague.
1419                                       They're either untested or proven to work bad
1420                                       (e.g. nvidia's Composite 32-bit visual).
1421                                       Most implementation offer a 24-bit visual anyway. */
1422                                    continue;
1423                            }
1424    
1425          pfm = XListPixmapFormats(display, &i);                          /* Only care for visuals, for whose BPPs (not depths!)
1426          if (pfm != NULL)                             we have a translateXtoY function. */
1427                            for (j = 0; j < pixmap_formats_count; ++j)
1428                            {
1429                                    if (pfm[j].depth == visual_info->depth)
1430                                    {
1431                                            if ((pfm[j].bits_per_pixel == 16) ||
1432                                                (pfm[j].bits_per_pixel == 24) ||
1433                                                (pfm[j].bits_per_pixel == 32))
1434                                            {
1435                                                    can_translate_to_bpp = True;
1436                                            }
1437                                            break;
1438                                    }
1439                            }
1440    
1441                            /* Prefer formats which have the most colour depth.
1442                               We're being truly aristocratic here, minding each
1443                               weight on its own. */
1444                            if (can_translate_to_bpp)
1445                            {
1446                                    unsigned vis_red_weight =
1447                                            calculate_mask_weight(visual_info->red_mask);
1448                                    unsigned vis_green_weight =
1449                                            calculate_mask_weight(visual_info->green_mask);
1450                                    unsigned vis_blue_weight =
1451                                            calculate_mask_weight(visual_info->blue_mask);
1452                                    if ((vis_red_weight >= red_weight)
1453                                        && (vis_green_weight >= green_weight)
1454                                        && (vis_blue_weight >= blue_weight))
1455                                    {
1456                                            red_weight = vis_red_weight;
1457                                            green_weight = vis_green_weight;
1458                                            blue_weight = vis_blue_weight;
1459                                            g_visual = visual_info->visual;
1460                                            g_depth = visual_info->depth;
1461                                    }
1462                            }
1463                    }
1464                    XFree(vmatches);
1465            }
1466    
1467            if (g_visual != NULL)
1468          {          {
1469                  /* Use maximum bpp for this depth - this is generally                  g_owncolmap = False;
1470                     desirable, e.g. 24 bits->32 bits. */                  calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1471                  while (i--)                  calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1472                    calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1473            }
1474            else
1475            {
1476                    template.class = PseudoColor;
1477                    template.depth = 8;
1478                    template.colormap_size = 256;
1479                    vmatches =
1480                            XGetVisualInfo(g_display,
1481                                           VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1482                                           &template, &visuals_count);
1483                    if (vmatches == NULL)
1484                  {                  {
1485                          if ((pfm[i].depth == depth)                          error("No usable TrueColor or PseudoColor visuals on this display.\n");
1486                              && (pfm[i].bits_per_pixel > bpp))                          XCloseDisplay(g_display);
1487                            XFree(pfm);
1488                            return False;
1489                    }
1490    
1491                    /* we use a colourmap, so the default visual should do */
1492                    g_owncolmap = True;
1493                    g_visual = vmatches[0].visual;
1494                    g_depth = vmatches[0].depth;
1495            }
1496    
1497            g_bpp = 0;
1498            for (i = 0; i < pixmap_formats_count; ++i)
1499            {
1500                    XPixmapFormatValues *pf = &pfm[i];
1501                    if (pf->depth == g_depth)
1502                    {
1503                            g_bpp = pf->bits_per_pixel;
1504    
1505                            if (g_no_translate_image)
1506                          {                          {
1507                                  bpp = pfm[i].bits_per_pixel;                                  switch (g_server_depth)
1508                                    {
1509                                            case 15:
1510                                            case 16:
1511                                                    if (g_bpp != 16)
1512                                                            g_no_translate_image = False;
1513                                                    break;
1514                                            case 24:
1515                                                    /* Yes, this will force image translation
1516                                                       on most modern servers which use 32 bits
1517                                                       for R8G8B8. */
1518                                                    if (g_bpp != 24)
1519                                                            g_no_translate_image = False;
1520                                                    break;
1521                                            default:
1522                                                    g_no_translate_image = False;
1523                                                    break;
1524                                    }
1525                          }                          }
1526    
1527                            /* Pixmap formats list is a depth-to-bpp mapping --
1528                               there's just a single entry for every depth,
1529                               so we can safely break here */
1530                            break;
1531                  }                  }
                 XFree(pfm);  
1532          }          }
1533            XFree(pfm);
1534            pfm = NULL;
1535            return True;
1536    }
1537    
1538          if (bpp < 8)  static XErrorHandler g_old_error_handler;
1539    
1540    static int
1541    error_handler(Display * dpy, XErrorEvent * eev)
1542    {
1543            if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1544          {          {
1545                  error("Less than 8 bpp not currently supported.\n");                  fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1546                  XCloseDisplay(display);                  fprintf(stderr,
1547                            "This is most likely caused by a broken window manager (commonly KWin).\n");
1548                    return 0;
1549            }
1550    
1551            return g_old_error_handler(dpy, eev);
1552    }
1553    
1554    RD_BOOL
1555    ui_init(void)
1556    {
1557            int screen_num;
1558    
1559            g_display = XOpenDisplay(NULL);
1560            if (g_display == NULL)
1561            {
1562                    error("Failed to open display: %s\n", XDisplayName(NULL));
1563                  return False;                  return False;
1564          }          }
1565    
1566          if (depth <= 8)          {
1567                  owncolmap = True;                  uint16 endianess_test = 1;
1568          else                  g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1569                  xcolmap = DefaultColormapOfScreen(screen);          }
1570    
1571          test = 1;          g_old_error_handler = XSetErrorHandler(error_handler);
1572          host_be = !(BOOL)(*(uint8 *)(&test));          g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1573          xserver_be = (ImageByteOrder(display) == MSBFirst);          screen_num = DefaultScreen(g_display);
1574            g_x_socket = ConnectionNumber(g_display);
1575            g_screen = ScreenOfDisplay(g_display, screen_num);
1576            g_depth = DefaultDepthOfScreen(g_screen);
1577    
1578          white = WhitePixelOfScreen(screen);          if (!select_visual(screen_num))
1579          attribs.background_pixel = BlackPixelOfScreen(screen);                  return False;
         attribs.backing_store = DoesBackingStore(screen);  
1580    
1581          if (attribs.backing_store == NotUseful)          if (g_no_translate_image)
1582                  ownbackstore = True;          {
1583                    DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1584            }
1585    
1586          if (fullscreen)          if (g_server_depth > g_bpp)
1587          {          {
1588                  attribs.override_redirect = True;                  warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1589                  width = WidthOfScreen(screen);                          g_server_depth, g_bpp);
                 height = HeightOfScreen(screen);  
1590          }          }
1591          else  
1592            DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1593                   g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1594    
1595            if (!g_owncolmap)
1596            {
1597                    g_xcolmap =
1598                            XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1599                                            AllocNone);
1600                    if (g_depth <= 8)
1601                            warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1602            }
1603    
1604            if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1605            {
1606                    warning("External BackingStore not available. Using internal.\n");
1607                    g_ownbackstore = True;
1608            }
1609    
1610            /*
1611             * Determine desktop size
1612             */
1613            if (g_fullscreen)
1614            {
1615                    g_width = WidthOfScreen(g_screen);
1616                    g_height = HeightOfScreen(g_screen);
1617                    g_using_full_workarea = True;
1618            }
1619            else if (g_width < 0)
1620            {
1621                    /* Percent of screen */
1622                    if (-g_width >= 100)
1623                            g_using_full_workarea = True;
1624                    g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1625                    g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1626            }
1627            else if (g_width == 0)
1628            {
1629                    /* Fetch geometry from _NET_WORKAREA */
1630                    uint32 x, y, cx, cy;
1631                    if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1632                    {
1633                            g_width = cx;
1634                            g_height = cy;
1635                            g_using_full_workarea = True;
1636                    }
1637                    else
1638                    {
1639                            warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1640                            g_width = WidthOfScreen(g_screen);
1641                            g_height = HeightOfScreen(g_screen);
1642                    }
1643            }
1644    
1645            /* make sure width is a multiple of 4 */
1646            g_width = (g_width + 3) & ~3;
1647    
1648            g_mod_map = XGetModifierMapping(g_display);
1649            xwin_refresh_pointer_map();
1650    
1651            xkeymap_init();
1652    
1653            if (g_enable_compose)
1654                    g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1655    
1656            xclip_init();
1657            ewmh_init();
1658            if (g_seamless_rdp)
1659                    seamless_init();
1660    
1661            DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1662    
1663            return True;
1664    }
1665    
1666    void
1667    ui_deinit(void)
1668    {
1669            while (g_seamless_windows)
1670          {          {
1671                  attribs.override_redirect = False;                  XDestroyWindow(g_display, g_seamless_windows->wnd);
1672                    sw_remove_window(g_seamless_windows);
1673          }          }
1674    
1675          width = (width + 3) & ~3; /* make width a multiple of 32 bits */          xclip_deinit();
1676    
1677            if (g_IM != NULL)
1678                    XCloseIM(g_IM);
1679    
1680            if (g_null_cursor != NULL)
1681                    ui_destroy_cursor(g_null_cursor);
1682    
1683            XFreeModifiermap(g_mod_map);
1684    
1685            if (g_ownbackstore)
1686                    XFreePixmap(g_display, g_backstore);
1687    
1688            XFreeGC(g_display, g_gc);
1689            XCloseDisplay(g_display);
1690            g_display = NULL;
1691    }
1692    
1693    
1694    static void
1695    get_window_attribs(XSetWindowAttributes * attribs)
1696    {
1697            attribs->background_pixel = BlackPixelOfScreen(g_screen);
1698            attribs->background_pixel = WhitePixelOfScreen(g_screen);
1699            attribs->border_pixel = WhitePixelOfScreen(g_screen);
1700            attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1701            attribs->override_redirect = g_fullscreen;
1702            attribs->colormap = g_xcolmap;
1703    }
1704    
1705    static void
1706    get_input_mask(long *input_mask)
1707    {
1708            *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1709                    VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1710    
1711            if (g_sendmotion)
1712                    *input_mask |= PointerMotionMask;
1713            if (g_ownbackstore)
1714                    *input_mask |= ExposureMask;
1715            if (g_fullscreen || g_grab_keyboard)
1716                    *input_mask |= EnterWindowMask;
1717            if (g_grab_keyboard)
1718                    *input_mask |= LeaveWindowMask;
1719    }
1720    
1721    RD_BOOL
1722    ui_create_window(void)
1723    {
1724            uint8 null_pointer_mask[1] = { 0x80 };
1725            uint8 null_pointer_data[24] = { 0x00 };
1726    
1727            XSetWindowAttributes attribs;
1728            XClassHint *classhints;
1729            XSizeHints *sizehints;
1730            int wndwidth, wndheight;
1731            long input_mask, ic_input_mask;
1732            XEvent xevent;
1733    
1734            wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1735            wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1736    
1737          wnd = XCreateWindow(display, RootWindowOfScreen(screen),          /* Handle -x-y portion of geometry string */
1738                              0, 0, width, height, 0, CopyFromParent,          if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1739                              InputOutput, CopyFromParent,                  g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1740                              CWBackingStore | CWBackPixel | CWOverrideRedirect,          if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1741                              &attribs);                  g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1742    
1743          XStoreName(display, wnd, title);          get_window_attribs(&attribs);
1744    
1745            g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1746                                  wndheight, 0, g_depth, InputOutput, g_visual,
1747                                  CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1748                                  CWBorderPixel, &attribs);
1749    
1750            if (g_gc == NULL)
1751            {
1752                    g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1753                    ui_reset_clip();
1754            }
1755    
1756            if (g_create_bitmap_gc == NULL)
1757                    g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1758    
1759            if ((g_ownbackstore) && (g_backstore == 0))
1760            {
1761                    g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1762    
1763                    /* clear to prevent rubbish being exposed at startup */
1764                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1765                    XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1766            }
1767    
1768            XStoreName(g_display, g_wnd, g_title);
1769            ewmh_set_wm_name(g_wnd, g_title);
1770    
1771            if (g_hide_decorations)
1772                    mwm_hide_decorations(g_wnd);
1773    
1774          classhints = XAllocClassHint();          classhints = XAllocClassHint();
1775          if (classhints != NULL)          if (classhints != NULL)
1776          {          {
1777                  classhints->res_name = classhints->res_class = "rdesktop";                  classhints->res_name = classhints->res_class = "rdesktop";
1778                  XSetClassHint(display, wnd, classhints);                  XSetClassHint(g_display, g_wnd, classhints);
1779                  XFree(classhints);                  XFree(classhints);
1780          }          }
1781    
# Line 276  ui_create_window(char *title) Line 1783  ui_create_window(char *title)
1783          if (sizehints)          if (sizehints)
1784          {          {
1785                  sizehints->flags = PMinSize | PMaxSize;                  sizehints->flags = PMinSize | PMaxSize;
1786                  sizehints->min_width = sizehints->max_width = width;                  if (g_pos)
1787                  sizehints->min_height = sizehints->max_height = height;                          sizehints->flags |= PPosition;
1788                  XSetWMNormalHints(display, wnd, sizehints);                  sizehints->min_width = sizehints->max_width = g_width;
1789                    sizehints->min_height = sizehints->max_height = g_height;
1790                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1791                  XFree(sizehints);                  XFree(sizehints);
1792          }          }
1793    
1794          xkeymap_init(display);          if (g_embed_wnd)
1795            {
1796                    XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1797            }
1798    
1799          input_mask = KeyPressMask | KeyReleaseMask          get_input_mask(&input_mask);
1800                          | ButtonPressMask | ButtonReleaseMask  
1801                          | EnterWindowMask | LeaveWindowMask;          if (g_IM != NULL)
1802            {
1803                    g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1804                                     XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1805    
1806          if (sendmotion)                  if ((g_IC != NULL)
1807                  input_mask |= PointerMotionMask;                      && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1808                            input_mask |= ic_input_mask;
1809            }
1810    
1811            XSelectInput(g_display, g_wnd, input_mask);
1812            XMapWindow(g_display, g_wnd);
1813    
1814            /* wait for VisibilityNotify */
1815            do
1816            {
1817                    XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1818            }
1819            while (xevent.type != VisibilityNotify);
1820            g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1821    
1822          if (ownbackstore)          g_focused = False;
1823                  input_mask |= ExposureMask;          g_mouse_in_wnd = False;
1824    
1825          XSelectInput(display, wnd, input_mask);          /* handle the WM_DELETE_WINDOW protocol */
1826          gc = XCreateGC(display, wnd, 0, NULL);          g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1827            g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1828            XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1829    
1830          if (ownbackstore)          /* create invisible 1x1 cursor to be used as null cursor */
1831                  backstore = XCreatePixmap(display, wnd, width, height, depth);          if (g_null_cursor == NULL)
1832                    g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1833    
         XMapWindow(display, wnd);  
1834          return True;          return True;
1835  }  }
1836    
1837  void  void
1838  ui_destroy_window()  ui_resize_window()
1839    {
1840            XSizeHints *sizehints;
1841            Pixmap bs;
1842    
1843            sizehints = XAllocSizeHints();
1844            if (sizehints)
1845            {
1846                    sizehints->flags = PMinSize | PMaxSize;
1847                    sizehints->min_width = sizehints->max_width = g_width;
1848                    sizehints->min_height = sizehints->max_height = g_height;
1849                    XSetWMNormalHints(g_display, g_wnd, sizehints);
1850                    XFree(sizehints);
1851            }
1852    
1853            if (!(g_fullscreen || g_embed_wnd))
1854            {
1855                    XResizeWindow(g_display, g_wnd, g_width, g_height);
1856            }
1857    
1858            /* create new backstore pixmap */
1859            if (g_backstore != 0)
1860            {
1861                    bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1862                    XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1863                    XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1864                    XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1865                    XFreePixmap(g_display, g_backstore);
1866                    g_backstore = bs;
1867            }
1868    }
1869    
1870    void
1871    ui_destroy_window(void)
1872  {  {
1873          if (ownbackstore)          if (g_IC != NULL)
1874                  XFreePixmap(display, backstore);                  XDestroyIC(g_IC);
1875    
1876          XFreeGC(display, gc);          XDestroyWindow(g_display, g_wnd);
1877          XDestroyWindow(display, wnd);  }
1878          XCloseDisplay(display);  
1879          display = NULL;  void
1880    xwin_toggle_fullscreen(void)
1881    {
1882            Pixmap contents = 0;
1883    
1884            if (g_seamless_active)
1885                    /* Turn off SeamlessRDP mode */
1886                    ui_seamless_toggle();
1887    
1888            if (!g_ownbackstore)
1889            {
1890                    /* need to save contents of window */
1891                    contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1892                    XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1893            }
1894    
1895            ui_destroy_window();
1896            g_fullscreen = !g_fullscreen;
1897            ui_create_window();
1898    
1899            XDefineCursor(g_display, g_wnd, g_current_cursor);
1900    
1901            if (!g_ownbackstore)
1902            {
1903                    XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1904                    XFreePixmap(g_display, contents);
1905            }
1906  }  }
1907    
1908  static void  static void
1909  xwin_process_events()  handle_button_event(XEvent xevent, RD_BOOL down)
1910    {
1911            uint16 button, flags = 0;
1912            g_last_gesturetime = xevent.xbutton.time;
1913            /* Reverse the pointer button mapping, e.g. in the case of
1914               "left-handed mouse mode"; the RDP session expects to
1915               receive physical buttons (true in mstsc as well) and
1916               logical button behavior depends on the remote desktop's own
1917               mouse settings */
1918            xevent.xbutton.button = g_pointer_log_to_phys_map[xevent.xbutton.button - 1];
1919            button = xkeymap_translate_button(xevent.xbutton.button);
1920            if (button == 0)
1921                    return;
1922    
1923            if (down)
1924                    flags = MOUSE_FLAG_DOWN;
1925    
1926            /* Stop moving window when button is released, regardless of cursor position */
1927            if (g_moving_wnd && (xevent.type == ButtonRelease))
1928                    g_moving_wnd = False;
1929    
1930            /* If win_button_size is nonzero, enable single app mode */
1931            if (xevent.xbutton.y < g_win_button_size)
1932            {
1933                    /*  Check from right to left: */
1934                    if (xevent.xbutton.x >= g_width - g_win_button_size)
1935                    {
1936                            /* The close button, continue */
1937                            ;
1938                    }
1939                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1940                    {
1941                            /* The maximize/restore button. Do not send to
1942                               server.  It might be a good idea to change the
1943                               cursor or give some other visible indication
1944                               that rdesktop inhibited this click */
1945                            if (xevent.type == ButtonPress)
1946                                    return;
1947                    }
1948                    else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1949                    {
1950                            /* The minimize button. Iconify window. */
1951                            if (xevent.type == ButtonRelease)
1952                            {
1953                                    /* Release the mouse button outside the minimize button, to prevent the
1954                                       actual minimazation to happen */
1955                                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1956                                    XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1957                                    return;
1958                            }
1959                    }
1960                    else if (xevent.xbutton.x <= g_win_button_size)
1961                    {
1962                            /* The system menu. Ignore. */
1963                            if (xevent.type == ButtonPress)
1964                                    return;
1965                    }
1966                    else
1967                    {
1968                            /* The title bar. */
1969                            if (xevent.type == ButtonPress)
1970                            {
1971                                    if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1972                                    {
1973                                            g_moving_wnd = True;
1974                                            g_move_x_offset = xevent.xbutton.x;
1975                                            g_move_y_offset = xevent.xbutton.y;
1976                                    }
1977                                    return;
1978                            }
1979                    }
1980            }
1981    
1982            if (xevent.xmotion.window == g_wnd)
1983            {
1984                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1985                                   flags | button, xevent.xbutton.x, xevent.xbutton.y);
1986            }
1987            else
1988            {
1989                    /* SeamlessRDP */
1990                    rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1991                                   flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1992            }
1993    }
1994    
1995    
1996    /* Process events in Xlib queue
1997       Returns 0 after user quit, 1 otherwise */
1998    static int
1999    xwin_process_events(void)
2000  {  {
2001          XEvent event;          XEvent xevent;
2002          KeySym keysym;          KeySym keysym;
         uint8 scancode;  
         uint16 button;  
2003          uint32 ev_time;          uint32 ev_time;
2004            char str[256];
2005            Status status;
2006            int events = 0;
2007            seamless_window *sw;
2008    
2009          if (display == NULL)          while ((XPending(g_display) > 0) && events++ < 20)
                 return;  
   
         while (XCheckMaskEvent(display, ~0, &event))  
2010          {          {
2011                  ev_time = time(NULL);                  XNextEvent(g_display, &xevent);
2012    
2013                    if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
2014                    {
2015                            DEBUG_KBD(("Filtering event\n"));
2016                            continue;
2017                    }
2018    
2019                  switch (event.type)                  switch (xevent.type)
2020                  {                  {
2021                            case VisibilityNotify:
2022                                    if (xevent.xvisibility.window == g_wnd)
2023                                            g_Unobscured =
2024                                                    xevent.xvisibility.state == VisibilityUnobscured;
2025    
2026                                    break;
2027                            case ClientMessage:
2028                                    /* the window manager told us to quit */
2029                                    if ((xevent.xclient.message_type == g_protocol_atom)
2030                                        && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2031                                            /* Quit */
2032                                            return 0;
2033                                    break;
2034    
2035                          case KeyPress:                          case KeyPress:
2036                                  keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0);                                  g_last_gesturetime = xevent.xkey.time;
2037                                  scancode = xkeymap_translate_key(keysym, event.xkey.keycode);                                  if (g_IC != NULL)
2038                                  if (scancode == 0)                                          /* Multi_key compatible version */
2039                                    {
2040                                            XmbLookupString(g_IC,
2041                                                            &xevent.xkey, str, sizeof(str), &keysym,
2042                                                            &status);
2043                                            if (!((status == XLookupKeySym) || (status == XLookupBoth)))
2044                                            {
2045                                                    error("XmbLookupString failed with status 0x%x\n",
2046                                                          status);
2047                                                    break;
2048                                            }
2049                                    }
2050                                    else
2051                                    {
2052                                            /* Plain old XLookupString */
2053                                            DEBUG_KBD(("\nNo input context, using XLookupString\n"));
2054                                            XLookupString((XKeyEvent *) & xevent,
2055                                                          str, sizeof(str), &keysym, NULL);
2056                                    }
2057    
2058                                    DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2059                                               get_ksname(keysym)));
2060    
2061                                    ev_time = time(NULL);
2062                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2063                                          break;                                          break;
2064    
2065                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE, 0,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2066                                                 scancode, 0);                                                    ev_time, True, 0);
2067                                  break;                                  break;
2068    
2069                          case KeyRelease:                          case KeyRelease:
2070                                  keysym = XKeycodeToKeysym(display, event.xkey.keycode, 0);                                  g_last_gesturetime = xevent.xkey.time;
2071                                  scancode = xkeymap_translate_key(keysym, event.xkey.keycode);                                  XLookupString((XKeyEvent *) & xevent, str,
2072                                  if (scancode == 0)                                                sizeof(str), &keysym, NULL);
2073    
2074                                    DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2075                                               get_ksname(keysym)));
2076    
2077                                    ev_time = time(NULL);
2078                                    if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2079                                          break;                                          break;
2080    
2081                                  rdp_send_input(ev_time, RDP_INPUT_SCANCODE,                                  xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2082                                                 KBD_FLAG_DOWN | KBD_FLAG_UP,                                                    ev_time, False, 0);
                                                scancode, 0);  
2083                                  break;                                  break;
2084    
2085                          case ButtonPress:                          case ButtonPress:
2086                                  button = xkeymap_translate_button(event.xbutton.button);                                  handle_button_event(xevent, True);
2087                                  if (button == 0)                                  break;
2088    
2089                            case ButtonRelease:
2090                                    handle_button_event(xevent, False);
2091                                    break;
2092    
2093                            case MotionNotify:
2094                                    if (g_moving_wnd)
2095                                    {
2096                                            XMoveWindow(g_display, g_wnd,
2097                                                        xevent.xmotion.x_root - g_move_x_offset,
2098                                                        xevent.xmotion.y_root - g_move_y_offset);
2099                                          break;                                          break;
2100                                    }
2101    
2102                                    if (g_fullscreen && !g_focused)
2103                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2104                                                           CurrentTime);
2105    
2106                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (xevent.xmotion.window == g_wnd)
2107                                                 button | MOUSE_FLAG_DOWN,                                  {
2108                                                 event.xbutton.x,                                          rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2109                                                 event.xbutton.y);                                                         xevent.xmotion.x, xevent.xmotion.y);
2110                                    }
2111                                    else
2112                                    {
2113                                            /* SeamlessRDP */
2114                                            rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2115                                                           xevent.xmotion.x_root,
2116                                                           xevent.xmotion.y_root);
2117                                    }
2118                                  break;                                  break;
2119    
2120                          case ButtonRelease:                          case FocusIn:
2121                                  button = xkeymap_translate_button(event.xbutton.button);                                  if (xevent.xfocus.mode == NotifyGrab)
                                 if (button == 0)  
2122                                          break;                                          break;
2123                                    g_focused = True;
2124                                    reset_modifier_keys();
2125                                    if (g_grab_keyboard && g_mouse_in_wnd)
2126                                            XGrabKeyboard(g_display, g_wnd, True,
2127                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2128    
2129                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  sw = sw_get_window_by_wnd(xevent.xfocus.window);
2130                                                 button,                                  if (!sw)
2131                                                 event.xbutton.x,                                          break;
2132                                                 event.xbutton.y);  
2133                                    if (sw->id != g_seamless_focused)
2134                                    {
2135                                            seamless_send_focus(sw->id, 0);
2136                                            g_seamless_focused = sw->id;
2137                                    }
2138                                  break;                                  break;
2139    
2140                          case MotionNotify:                          case FocusOut:
2141                                  rdp_send_input(ev_time, RDP_INPUT_MOUSE,                                  if (xevent.xfocus.mode == NotifyUngrab)
2142                                                 MOUSE_FLAG_MOVE,                                          break;
2143                                                 event.xmotion.x,                                  g_focused = False;
2144                                                 event.xmotion.y);                                  if (xevent.xfocus.mode == NotifyWhileGrabbed)
2145                                            XUngrabKeyboard(g_display, CurrentTime);
2146                                  break;                                  break;
2147    
2148                          case EnterNotify:                          case EnterNotify:
2149                                  XGrabKeyboard(display, wnd, True, GrabModeAsync,                                  /* we only register for this event when in fullscreen mode */
2150                                                GrabModeAsync, CurrentTime);                                  /* or grab_keyboard */
2151                                    g_mouse_in_wnd = True;
2152                                    if (g_fullscreen)
2153                                    {
2154                                            XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2155                                                           CurrentTime);
2156                                            break;
2157                                    }
2158                                    if (g_focused)
2159                                            XGrabKeyboard(g_display, g_wnd, True,
2160                                                          GrabModeAsync, GrabModeAsync, CurrentTime);
2161                                  break;                                  break;
2162    
2163                          case LeaveNotify:                          case LeaveNotify:
2164                                  XUngrabKeyboard(display, CurrentTime);                                  /* we only register for this event when grab_keyboard */
2165                                    g_mouse_in_wnd = False;
2166                                    XUngrabKeyboard(g_display, CurrentTime);
2167                                  break;                                  break;
2168    
2169                          case Expose:                          case Expose:
2170                                  XCopyArea(display, backstore, wnd, gc,                                  if (xevent.xexpose.window == g_wnd)
2171                                            event.xexpose.x, event.xexpose.y,                                  {
2172                                            event.xexpose.width, event.xexpose.height,                                          XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2173                                            event.xexpose.x, event.xexpose.y);                                                    g_gc,
2174                                                      xevent.xexpose.x, xevent.xexpose.y,
2175                                                      xevent.xexpose.width, xevent.xexpose.height,
2176                                                      xevent.xexpose.x, xevent.xexpose.y);
2177                                    }
2178                                    else
2179                                    {
2180                                            sw = sw_get_window_by_wnd(xevent.xexpose.window);
2181                                            if (!sw)
2182                                                    break;
2183                                            XCopyArea(g_display, g_backstore,
2184                                                      xevent.xexpose.window, g_gc,
2185                                                      xevent.xexpose.x + sw->xoffset,
2186                                                      xevent.xexpose.y + sw->yoffset,
2187                                                      xevent.xexpose.width,
2188                                                      xevent.xexpose.height, xevent.xexpose.x,
2189                                                      xevent.xexpose.y);
2190                                    }
2191    
2192                                    break;
2193    
2194                            case MappingNotify:
2195                                    /* Refresh keyboard mapping if it has changed. This is important for
2196                                       Xvnc, since it allocates keycodes dynamically */
2197                                    if (xevent.xmapping.request == MappingKeyboard
2198                                        || xevent.xmapping.request == MappingModifier)
2199                                            XRefreshKeyboardMapping(&xevent.xmapping);
2200    
2201                                    if (xevent.xmapping.request == MappingModifier)
2202                                    {
2203                                            XFreeModifiermap(g_mod_map);
2204                                            g_mod_map = XGetModifierMapping(g_display);
2205                                    }
2206    
2207                                    if (xevent.xmapping.request == MappingPointer)
2208                                    {
2209                                            xwin_refresh_pointer_map();
2210                                    }
2211    
2212                                    break;
2213    
2214                                    /* clipboard stuff */
2215                            case SelectionNotify:
2216                                    xclip_handle_SelectionNotify(&xevent.xselection);
2217                                    break;
2218                            case SelectionRequest:
2219                                    xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2220                                    break;
2221                            case SelectionClear:
2222                                    xclip_handle_SelectionClear();
2223                                    break;
2224                            case PropertyNotify:
2225                                    xclip_handle_PropertyNotify(&xevent.xproperty);
2226                                    if (xevent.xproperty.window == g_wnd)
2227                                            break;
2228                                    if (xevent.xproperty.window == DefaultRootWindow(g_display))
2229                                            break;
2230    
2231                                    /* seamless */
2232                                    sw = sw_get_window_by_wnd(xevent.xproperty.window);
2233                                    if (!sw)
2234                                            break;
2235    
2236                                    if ((xevent.xproperty.atom == g_net_wm_state_atom)
2237                                        && (xevent.xproperty.state == PropertyNewValue))
2238                                    {
2239                                            sw->state = ewmh_get_window_state(sw->wnd);
2240                                            seamless_send_state(sw->id, sw->state, 0);
2241                                    }
2242    
2243                                    if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2244                                        && (xevent.xproperty.state == PropertyNewValue))
2245                                    {
2246                                            sw->desktop = ewmh_get_window_desktop(sw->wnd);
2247                                            sw_all_to_desktop(sw->wnd, sw->desktop);
2248                                    }
2249    
2250                                    break;
2251                            case MapNotify:
2252                                    if (!g_seamless_active)
2253                                            rdp_send_client_window_status(1);
2254                                    break;
2255                            case UnmapNotify:
2256                                    if (!g_seamless_active)
2257                                            rdp_send_client_window_status(0);
2258                                    break;
2259                            case ConfigureNotify:
2260                                    if (!g_seamless_active)
2261                                            break;
2262    
2263                                    sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2264                                    if (!sw)
2265                                            break;
2266    
2267                                    gettimeofday(sw->position_timer, NULL);
2268                                    if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2269                                        1000000)
2270                                    {
2271                                            sw->position_timer->tv_usec +=
2272                                                    SEAMLESSRDP_POSITION_TIMER - 1000000;
2273                                            sw->position_timer->tv_sec += 1;
2274                                    }
2275                                    else
2276                                    {
2277                                            sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2278                                    }
2279    
2280                                    sw_handle_restack(sw);
2281                                  break;                                  break;
2282                  }                  }
2283          }          }
2284            /* Keep going */
2285            return 1;
2286  }  }
2287    
2288  void  /* Returns 0 after user quit, 1 otherwise */
2289    int
2290  ui_select(int rdp_socket)  ui_select(int rdp_socket)
2291  {  {
2292          int n = (rdp_socket > x_socket) ? rdp_socket+1 : x_socket+1;          int n;
2293          fd_set rfds;          fd_set rfds, wfds;
2294            struct timeval tv;
2295          XFlush(display);          RD_BOOL s_timeout = False;
   
         FD_ZERO(&rfds);  
2296    
2297          while (True)          while (True)
2298          {          {
2299                    n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2300                    /* Process any events already waiting */
2301                    if (!xwin_process_events())
2302                            /* User quit */
2303                            return 0;
2304    
2305                    if (g_seamless_active)
2306                            sw_check_timers();
2307    
2308                  FD_ZERO(&rfds);                  FD_ZERO(&rfds);
2309                    FD_ZERO(&wfds);
2310                  FD_SET(rdp_socket, &rfds);                  FD_SET(rdp_socket, &rfds);
2311                  FD_SET(x_socket, &rfds);                  FD_SET(g_x_socket, &rfds);
2312    
2313                  switch (select(n, &rfds, NULL, NULL, NULL))                  /* default timeout */
2314                    tv.tv_sec = 60;
2315                    tv.tv_usec = 0;
2316    
2317    #ifdef WITH_RDPSND
2318                    rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2319    #endif
2320    
2321                    /* add redirection handles */
2322                    rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2323                    seamless_select_timeout(&tv);
2324    
2325                    n++;
2326    
2327                    switch (select(n, &rfds, &wfds, NULL, &tv))
2328                  {                  {
2329                          case -1:                          case -1:
2330                                  error("select: %s\n", strerror(errno));                                  error("select: %s\n", strerror(errno));
2331    
2332                          case 0:                          case 0:
2333    #ifdef WITH_RDPSND
2334                                    rdpsnd_check_fds(&rfds, &wfds);
2335    #endif
2336    
2337                                    /* Abort serial read calls */
2338                                    if (s_timeout)
2339                                            rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2340                                  continue;                                  continue;
2341                  }                  }
2342    
2343                  if (FD_ISSET(x_socket, &rfds))  #ifdef WITH_RDPSND
2344                          xwin_process_events();                  rdpsnd_check_fds(&rfds, &wfds);
2345    #endif
2346    
2347                    rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2348    
2349                  if (FD_ISSET(rdp_socket, &rfds))                  if (FD_ISSET(rdp_socket, &rfds))
2350                          return;                          return 1;
2351    
2352          }          }
2353  }  }
2354    
2355  void  void
2356  ui_move_pointer(int x, int y)  ui_move_pointer(int x, int y)
2357  {  {
2358          XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);          XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2359  }  }
2360    
2361  HBITMAP  RD_HBITMAP
2362  ui_create_bitmap(int width, int height, uint8 *data)  ui_create_bitmap(int width, int height, uint8 * data)
2363  {  {
2364          XImage *image;          XImage *image;
2365          Pixmap bitmap;          Pixmap bitmap;
2366          uint8 *tdata;          uint8 *tdata;
2367            int bitmap_pad;
2368    
2369          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2370          bitmap = XCreatePixmap(display, wnd, width, height, depth);          {
2371          image = XCreateImage(display, visual, depth, ZPixmap,                  bitmap_pad = 8;
2372                               0, tdata, width, height, 8, 0);          }
2373            else
2374            {
2375                    bitmap_pad = g_bpp;
2376    
2377                    if (g_bpp == 24)
2378                            bitmap_pad = 32;
2379            }
2380    
2381          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          tdata = (g_owncolmap ? data : translate_image(width, height, data));
2382            bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2383            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2384                                 (char *) tdata, width, height, bitmap_pad, 0);
2385    
2386            XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2387    
2388          XFree(image);          XFree(image);
2389          if (!owncolmap)          if (tdata != data)
2390                  xfree(tdata);                  xfree(tdata);
2391          return (HBITMAP) bitmap;          return (RD_HBITMAP) bitmap;
2392  }  }
2393    
2394  void  void
2395  ui_paint_bitmap(int x, int y, int cx, int cy,  ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
                 int width, int height, uint8 *data)  
2396  {  {
2397          XImage *image;          XImage *image;
2398          uint8 *tdata;          uint8 *tdata;
2399            int bitmap_pad;
2400    
2401          tdata = (owncolmap ? data : translate_image(width, height, data));          if (g_server_depth == 8)
2402          image = XCreateImage(display, visual, depth, ZPixmap,          {
2403                               0, tdata, width, height, 8, 0);                  bitmap_pad = 8;
2404            }
2405            else
2406            {
2407                    bitmap_pad = g_bpp;
2408    
2409          if (ownbackstore)                  if (g_bpp == 24)
2410                            bitmap_pad = 32;
2411            }
2412    
2413            tdata = (g_owncolmap ? data : translate_image(width, height, data));
2414            image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2415                                 (char *) tdata, width, height, bitmap_pad, 0);
2416    
2417            if (g_ownbackstore)
2418          {          {
2419                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2420                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2421                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2422                                            (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2423                                             x - sw->xoffset, y - sw->yoffset));
2424          }          }
2425          else          else
2426          {          {
2427                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2428                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2429                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2430                                             x - sw->xoffset, y - sw->yoffset));
2431          }          }
2432    
2433          XFree(image);          XFree(image);
2434          if (!owncolmap)          if (tdata != data)
2435                  xfree(tdata);                  xfree(tdata);
2436  }  }
2437    
2438  void  void
2439  ui_destroy_bitmap(HBITMAP bmp)  ui_destroy_bitmap(RD_HBITMAP bmp)
2440  {  {
2441          XFreePixmap(display, (Pixmap)bmp);          XFreePixmap(g_display, (Pixmap) bmp);
2442  }  }
2443    
2444  HGLYPH  RD_HGLYPH
2445  ui_create_glyph(int width, int height, uint8 *data)  ui_create_glyph(int width, int height, uint8 * data)
2446  {  {
2447          XImage *image;          XImage *image;
2448          Pixmap bitmap;          Pixmap bitmap;
2449          int scanline;          int scanline;
         GC gc;  
2450    
2451          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2452    
2453          bitmap = XCreatePixmap(display, wnd, width, height, 1);          bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2454          gc = XCreateGC(display, bitmap, 0, NULL);          if (g_create_glyph_gc == 0)
2455                    g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2456    
2457          image = XCreateImage(display, visual, 1, ZPixmap, 0,          image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2458                               data, width, height, 8, scanline);                               width, height, 8, scanline);
2459          image->byte_order = MSBFirst;          image->byte_order = MSBFirst;
2460          image->bitmap_bit_order = MSBFirst;          image->bitmap_bit_order = MSBFirst;
2461          XInitImage(image);          XInitImage(image);
2462    
2463          XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);          XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2464    
2465          XFree(image);          XFree(image);
2466          XFreeGC(display, gc);          return (RD_HGLYPH) bitmap;
         return (HGLYPH)bitmap;  
2467  }  }
2468    
2469  void  void
2470  ui_destroy_glyph(HGLYPH glyph)  ui_destroy_glyph(RD_HGLYPH glyph)
2471  {  {
2472          XFreePixmap(display, (Pixmap)glyph);          XFreePixmap(g_display, (Pixmap) glyph);
2473  }  }
2474    
2475  HCURSOR  RD_HCURSOR
2476  ui_create_cursor(unsigned int x, unsigned int y, int width,  ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2477                   int height, uint8 *andmask, uint8 *xormask)                   uint8 * andmask, uint8 * xormask)
2478  {  {
2479          HGLYPH maskglyph, cursorglyph;          RD_HGLYPH maskglyph, cursorglyph;
2480          XColor bg, fg;          XColor bg, fg;
2481          Cursor xcursor;          Cursor xcursor;
2482          uint8 *cursor, *pcursor;          uint8 *cursor, *pcursor;
# Line 542  ui_create_cursor(unsigned int x, unsigne Line 2488  ui_create_cursor(unsigned int x, unsigne
2488          scanline = (width + 7) / 8;          scanline = (width + 7) / 8;
2489          offset = scanline * height;          offset = scanline * height;
2490    
2491          cursor = xmalloc(offset);          cursor = (uint8 *) xmalloc(offset);
2492          memset(cursor, 0, offset);          memset(cursor, 0, offset);
2493    
2494          mask = xmalloc(offset);          mask = (uint8 *) xmalloc(offset);
2495          memset(mask, 0, offset);          memset(mask, 0, offset);
2496    
2497          /* approximate AND and XOR masks with a monochrome X pointer */          /* approximate AND and XOR masks with a monochrome X pointer */
# Line 585  ui_create_cursor(unsigned int x, unsigne Line 2531  ui_create_cursor(unsigned int x, unsigne
2531    
2532          cursorglyph = ui_create_glyph(width, height, cursor);          cursorglyph = ui_create_glyph(width, height, cursor);
2533          maskglyph = ui_create_glyph(width, height, mask);          maskglyph = ui_create_glyph(width, height, mask);
2534            
2535          xcursor = XCreatePixmapCursor(display, (Pixmap)cursorglyph,          xcursor =
2536                                  (Pixmap)maskglyph, &fg, &bg, x, y);                  XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2537                                        (Pixmap) maskglyph, &fg, &bg, x, y);
2538    
2539          ui_destroy_glyph(maskglyph);          ui_destroy_glyph(maskglyph);
2540          ui_destroy_glyph(cursorglyph);          ui_destroy_glyph(cursorglyph);
2541          xfree(mask);          xfree(mask);
2542          xfree(cursor);          xfree(cursor);
2543          return (HCURSOR)xcursor;          return (RD_HCURSOR) xcursor;
2544    }
2545    
2546    void
2547    ui_set_cursor(RD_HCURSOR cursor)
2548    {
2549            g_current_cursor = (Cursor) cursor;
2550            XDefineCursor(g_display, g_wnd, g_current_cursor);
2551            ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2552  }  }
2553    
2554  void  void
2555  ui_set_cursor(HCURSOR cursor)  ui_destroy_cursor(RD_HCURSOR cursor)
2556  {  {
2557          XDefineCursor(display, wnd, (Cursor)cursor);          XFreeCursor(g_display, (Cursor) cursor);
2558  }  }
2559    
2560  void  void
2561  ui_destroy_cursor(HCURSOR cursor)  ui_set_null_cursor(void)
2562  {  {
2563          XFreeCursor(display, (Cursor)cursor);          ui_set_cursor(g_null_cursor);
2564  }  }
2565    
2566  #define MAKE_XCOLOR(xc,c) \  #define MAKE_XCOLOR(xc,c) \
# Line 614  ui_destroy_cursor(HCURSOR cursor) Line 2569  ui_destroy_cursor(HCURSOR cursor)
2569                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \                  (xc)->blue  = ((c)->blue  << 8) | (c)->blue; \
2570                  (xc)->flags = DoRed | DoGreen | DoBlue;                  (xc)->flags = DoRed | DoGreen | DoBlue;
2571    
2572  HCOLOURMAP  
2573  ui_create_colourmap(COLOURMAP *colours)  RD_HCOLOURMAP
2574    ui_create_colourmap(COLOURMAP * colours)
2575  {  {
2576          COLOURENTRY *entry;          COLOURENTRY *entry;
2577          int i, ncolours = colours->ncolours;          int i, ncolours = colours->ncolours;
2578            if (!g_owncolmap)
         if (owncolmap)  
2579          {          {
2580                  XColor *xcolours, *xentry;                  uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2581                  Colormap map;                  XColor xentry;
2582                    XColor xc_cache[256];
2583                  xcolours = xmalloc(sizeof(XColor) * ncolours);                  uint32 colour;
2584                    int colLookup = 256;
2585                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2586                  {                  {
2587                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2588                          xentry = &xcolours[i];                          MAKE_XCOLOR(&xentry, entry);
                         xentry->pixel = i;  
                         MAKE_XCOLOR(xentry, entry);  
                 }  
2589    
2590                  map = XCreateColormap(display, wnd, visual, AllocAll);                          if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2591                  XStoreColors(display, map, xcolours, ncolours);                          {
2592                                    /* Allocation failed, find closest match. */
2593                                    int j = 256;
2594                                    int nMinDist = 3 * 256 * 256;
2595                                    long nDist = nMinDist;
2596    
2597                  xfree(xcolours);                                  /* only get the colors once */
2598                  return (HCOLOURMAP)map;                                  while (colLookup--)
2599                                    {
2600                                            xc_cache[colLookup].pixel = colLookup;
2601                                            xc_cache[colLookup].red = xc_cache[colLookup].green =
2602                                                    xc_cache[colLookup].blue = 0;
2603                                            xc_cache[colLookup].flags = 0;
2604                                            XQueryColor(g_display,
2605                                                        DefaultColormap(g_display,
2606                                                                        DefaultScreen(g_display)),
2607                                                        &xc_cache[colLookup]);
2608                                    }
2609                                    colLookup = 0;
2610    
2611                                    /* approximate the pixel */
2612                                    while (j--)
2613                                    {
2614                                            if (xc_cache[j].flags)
2615                                            {
2616                                                    nDist = ((long) (xc_cache[j].red >> 8) -
2617                                                             (long) (xentry.red >> 8)) *
2618                                                            ((long) (xc_cache[j].red >> 8) -
2619                                                             (long) (xentry.red >> 8)) +
2620                                                            ((long) (xc_cache[j].green >> 8) -
2621                                                             (long) (xentry.green >> 8)) *
2622                                                            ((long) (xc_cache[j].green >> 8) -
2623                                                             (long) (xentry.green >> 8)) +
2624                                                            ((long) (xc_cache[j].blue >> 8) -
2625                                                             (long) (xentry.blue >> 8)) *
2626                                                            ((long) (xc_cache[j].blue >> 8) -
2627                                                             (long) (xentry.blue >> 8));
2628                                            }
2629                                            if (nDist < nMinDist)
2630                                            {
2631                                                    nMinDist = nDist;
2632                                                    xentry.pixel = j;
2633                                            }
2634                                    }
2635                            }
2636                            colour = xentry.pixel;
2637    
2638                            /* update our cache */
2639                            if (xentry.pixel < 256)
2640                            {
2641                                    xc_cache[xentry.pixel].red = xentry.red;
2642                                    xc_cache[xentry.pixel].green = xentry.green;
2643                                    xc_cache[xentry.pixel].blue = xentry.blue;
2644    
2645                            }
2646    
2647                            map[i] = colour;
2648                    }
2649                    return map;
2650          }          }
2651          else          else
2652          {          {
2653                  uint32 *map = xmalloc(sizeof(*colmap) * ncolours);                  XColor *xcolours, *xentry;
2654                  XColor xentry;                  Colormap map;
                 uint32 colour;  
2655    
2656                    xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2657                  for (i = 0; i < ncolours; i++)                  for (i = 0; i < ncolours; i++)
2658                  {                  {
2659                          entry = &colours->colours[i];                          entry = &colours->colours[i];
2660                          MAKE_XCOLOR(&xentry, entry);                          xentry = &xcolours[i];
2661                            xentry->pixel = i;
2662                          if (XAllocColor(display, xcolmap, &xentry) != 0)                          MAKE_XCOLOR(xentry, entry);
                                 colour = xentry.pixel;  
                         else  
                                 colour = white;  
   
                         /* byte swap here to make translate_image faster */  
                         map[i] = translate_colour(colour);  
2663                  }                  }
2664    
2665                  return map;                  map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2666                    XStoreColors(g_display, map, xcolours, ncolours);
2667    
2668                    xfree(xcolours);
2669                    return (RD_HCOLOURMAP) map;
2670          }          }
2671  }  }
2672    
2673  void  void
2674  ui_destroy_colourmap(HCOLOURMAP map)  ui_destroy_colourmap(RD_HCOLOURMAP map)
2675  {  {
2676          if (owncolmap)          if (!g_owncolmap)
                 XFreeColormap(display, (Colormap)map);  
         else  
2677                  xfree(map);                  xfree(map);
2678            else
2679                    XFreeColormap(g_display, (Colormap) map);
2680  }  }
2681    
2682  void  void
2683  ui_set_colourmap(HCOLOURMAP map)  ui_set_colourmap(RD_HCOLOURMAP map)
2684  {  {
2685          if (owncolmap)          if (!g_owncolmap)
2686                  XSetWindowColormap(display, wnd, (Colormap)map);          {
2687                    if (g_colmap)
2688                            xfree(g_colmap);
2689    
2690                    g_colmap = (uint32 *) map;
2691            }
2692          else          else
2693                  colmap = map;          {
2694                    XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2695                    ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2696            }
2697  }  }
2698    
2699  void  void
2700  ui_set_clip(int x, int y, int cx, int cy)  ui_set_clip(int x, int y, int cx, int cy)
2701  {  {
2702          XRectangle rect;          g_clip_rectangle.x = x;
2703            g_clip_rectangle.y = y;
2704          rect.x = x;          g_clip_rectangle.width = cx;
2705          rect.y = y;          g_clip_rectangle.height = cy;
2706          rect.width = cx;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = cy;  
         XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);  
2707  }  }
2708    
2709  void  void
2710  ui_reset_clip()  ui_reset_clip(void)
2711  {  {
2712          XRectangle rect;          g_clip_rectangle.x = 0;
2713            g_clip_rectangle.y = 0;
2714          rect.x = 0;          g_clip_rectangle.width = g_width;
2715          rect.y = 0;          g_clip_rectangle.height = g_height;
2716          rect.width = width;          XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
         rect.height = height;  
         XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);  
2717  }  }
2718    
2719  void  void
2720  ui_bell()  ui_bell(void)
2721  {  {
2722          XBell(display, 0);          XBell(g_display, 0);
2723  }  }
2724    
2725  void  void
# Line 721  ui_destblt(uint8 opcode, Line 2731  ui_destblt(uint8 opcode,
2731          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2732  }  }
2733    
2734    static uint8 hatch_patterns[] = {
2735            0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2736            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2737            0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2738            0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2739            0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2740            0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81  /* 5 - bsDiagCross */
2741    };
2742    
2743  void  void
2744  ui_patblt(uint8 opcode,  ui_patblt(uint8 opcode,
2745            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2746            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2747  {  {
2748          Pixmap fill;          Pixmap fill;
2749            uint8 i, ipattern[8];
2750    
2751          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2752    
# Line 734  ui_patblt(uint8 opcode, Line 2754  ui_patblt(uint8 opcode,
2754          {          {
2755                  case 0: /* Solid */                  case 0: /* Solid */
2756                          SET_FOREGROUND(fgcolour);                          SET_FOREGROUND(fgcolour);
2757                          FILL_RECTANGLE(x, y, cx, cy);                          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2758                          break;                          break;
2759    
2760                  case 3: /* Pattern */                  case 2: /* Hatch */
2761                          fill = (Pixmap)ui_create_glyph(8, 8, brush->pattern);                          fill = (Pixmap) ui_create_glyph(8, 8,
2762                                                            hatch_patterns + brush->pattern[0] * 8);
2763                            SET_FOREGROUND(fgcolour);
2764                            SET_BACKGROUND(bgcolour);
2765                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2766                            XSetStipple(g_display, g_gc, fill);
2767                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2768                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2769                            XSetFillStyle(g_display, g_gc, FillSolid);
2770                            XSetTSOrigin(g_display, g_gc, 0, 0);
2771                            ui_destroy_glyph((RD_HGLYPH) fill);
2772                            break;
2773    
2774                    case 3: /* Pattern */
2775                            for (i = 0; i != 8; i++)
2776                                    ipattern[7 - i] = brush->pattern[i];
2777                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2778                          SET_FOREGROUND(bgcolour);                          SET_FOREGROUND(bgcolour);
2779                          SET_BACKGROUND(fgcolour);                          SET_BACKGROUND(fgcolour);
2780                          XSetFillStyle(display, gc, FillOpaqueStippled);                          XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2781                          XSetStipple(display, gc, fill);                          XSetStipple(g_display, g_gc, fill);
2782                          XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);                          XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2783                            FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2784                          FILL_RECTANGLE(x, y, cx, cy);                          XSetFillStyle(g_display, g_gc, FillSolid);
2785                            XSetTSOrigin(g_display, g_gc, 0, 0);
2786                          XSetFillStyle(display, gc, FillSolid);                          ui_destroy_glyph((RD_HGLYPH) fill);
                         ui_destroy_glyph((HGLYPH)fill);  
2787                          break;                          break;
2788    
2789                  default:                  default:
# Line 757  ui_patblt(uint8 opcode, Line 2791  ui_patblt(uint8 opcode,
2791          }          }
2792    
2793          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2794    
2795            if (g_ownbackstore)
2796                    XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2797            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2798                                    (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2799                                     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2800  }  }
2801    
2802  void  void
# Line 765  ui_screenblt(uint8 opcode, Line 2805  ui_screenblt(uint8 opcode,
2805               /* src */ int srcx, int srcy)               /* src */ int srcx, int srcy)
2806  {  {
2807          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2808          XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);          if (g_ownbackstore)
2809          if (ownbackstore)          {
2810                  XCopyArea(display, backstore, backstore, gc, srcx, srcy,                  XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2811                            cx, cy, x, y);                            g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2812                    XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2813            }
2814            else
2815            {
2816                    XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2817            }
2818    
2819            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2820                                    (g_display, g_ownbackstore ? g_backstore : g_wnd,
2821                                     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2822    
2823          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2824  }  }
2825    
2826  void  void
2827  ui_memblt(uint8 opcode,  ui_memblt(uint8 opcode,
2828            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2829            /* src */ HBITMAP src, int srcx, int srcy)            /* src */ RD_HBITMAP src, int srcx, int srcy)
2830  {  {
2831          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2832          XCopyArea(display, (Pixmap)src, wnd, gc, srcx, srcy, cx, cy, x, y);          XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2833          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2834                  XCopyArea(display, (Pixmap)src, backstore, gc, srcx, srcy,                                  (g_display, (Pixmap) src, sw->wnd, g_gc,
2835                            cx, cy, x, y);                                   srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2836            if (g_ownbackstore)
2837                    XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2838          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2839  }  }
2840    
2841  void  void
2842  ui_triblt(uint8 opcode,  ui_triblt(uint8 opcode,
2843            /* dest */ int x, int y, int cx, int cy,            /* dest */ int x, int y, int cx, int cy,
2844            /* src */ HBITMAP src, int srcx, int srcy,            /* src */ RD_HBITMAP src, int srcx, int srcy,
2845            /* brush */ BRUSH *brush, int bgcolour, int fgcolour)            /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2846  {  {
2847          /* This is potentially difficult to do in general. Until someone          /* This is potentially difficult to do in general. Until someone
2848             comes up with a more efficient way of doing it I am using cases. */             comes up with a more efficient way of doing it I am using cases. */
# Line 798  ui_triblt(uint8 opcode, Line 2851  ui_triblt(uint8 opcode,
2851          {          {
2852                  case 0x69:      /* PDSxxn */                  case 0x69:      /* PDSxxn */
2853                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2854                          ui_patblt(ROP2_NXOR, x, y, cx, cy,                          ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2855                          break;                          break;
2856    
2857                  case 0xb8:      /* PSDPxax */                  case 0xb8:      /* PSDPxax */
2858                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2859                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2860                          ui_patblt(ROP2_XOR, x, y, cx, cy,                          ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   brush, bgcolour, fgcolour);  
2861                          break;                          break;
2862    
2863                  case 0xc0:      /* PSa */                  case 0xc0:      /* PSa */
2864                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);                          ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2865                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour,                          ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
                                   fgcolour);  
2866                          break;                          break;
2867    
2868                  default:                  default:
# Line 825  ui_triblt(uint8 opcode, Line 2874  ui_triblt(uint8 opcode,
2874  void  void
2875  ui_line(uint8 opcode,  ui_line(uint8 opcode,
2876          /* dest */ int startx, int starty, int endx, int endy,          /* dest */ int startx, int starty, int endx, int endy,
2877          /* pen */ PEN *pen)          /* pen */ PEN * pen)
2878  {  {
2879          SET_FUNCTION(opcode);          SET_FUNCTION(opcode);
2880          SET_FOREGROUND(pen->colour);          SET_FOREGROUND(pen->colour);
2881          XDrawLine(display, wnd, gc, startx, starty, endx, endy);          XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2882          if (ownbackstore)          ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2883                  XDrawLine(display, backstore, gc, startx, starty, endx, endy);                                              startx - sw->xoffset, starty - sw->yoffset,
2884                                                endx - sw->xoffset, endy - sw->yoffset));
2885            if (g_ownbackstore)
2886                    XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2887          RESET_FUNCTION(opcode);          RESET_FUNCTION(opcode);
2888  }  }
2889    
# Line 845  ui_rect( Line 2897  ui_rect(
2897  }  }
2898    
2899  void  void
2900    ui_polygon(uint8 opcode,
2901               /* mode */ uint8 fillmode,
2902               /* dest */ RD_POINT * point, int npoints,
2903               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2904    {
2905            uint8 style, i, ipattern[8];
2906            Pixmap fill;
2907    
2908            SET_FUNCTION(opcode);
2909    
2910            switch (fillmode)
2911            {
2912                    case ALTERNATE:
2913                            XSetFillRule(g_display, g_gc, EvenOddRule);
2914                            break;
2915                    case WINDING:
2916                            XSetFillRule(g_display, g_gc, WindingRule);
2917                            break;
2918                    default:
2919                            unimpl("fill mode %d\n", fillmode);
2920            }
2921    
2922            if (brush)
2923                    style = brush->style;
2924            else
2925                    style = 0;
2926    
2927            switch (style)
2928            {
2929                    case 0: /* Solid */
2930                            SET_FOREGROUND(fgcolour);
2931                            FILL_POLYGON((XPoint *) point, npoints);
2932                            break;
2933    
2934                    case 2: /* Hatch */
2935                            fill = (Pixmap) ui_create_glyph(8, 8,
2936                                                            hatch_patterns + brush->pattern[0] * 8);
2937                            SET_FOREGROUND(fgcolour);
2938                            SET_BACKGROUND(bgcolour);
2939                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2940                            XSetStipple(g_display, g_gc, fill);
2941                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2942                            FILL_POLYGON((XPoint *) point, npoints);
2943                            XSetFillStyle(g_display, g_gc, FillSolid);
2944                            XSetTSOrigin(g_display, g_gc, 0, 0);
2945                            ui_destroy_glyph((RD_HGLYPH) fill);
2946                            break;
2947    
2948                    case 3: /* Pattern */
2949                            for (i = 0; i != 8; i++)
2950                                    ipattern[7 - i] = brush->pattern[i];
2951                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2952                            SET_FOREGROUND(bgcolour);
2953                            SET_BACKGROUND(fgcolour);
2954                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2955                            XSetStipple(g_display, g_gc, fill);
2956                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2957                            FILL_POLYGON((XPoint *) point, npoints);
2958                            XSetFillStyle(g_display, g_gc, FillSolid);
2959                            XSetTSOrigin(g_display, g_gc, 0, 0);
2960                            ui_destroy_glyph((RD_HGLYPH) fill);
2961                            break;
2962    
2963                    default:
2964                            unimpl("brush %d\n", brush->style);
2965            }
2966    
2967            RESET_FUNCTION(opcode);
2968    }
2969    
2970    void
2971    ui_polyline(uint8 opcode,
2972                /* dest */ RD_POINT * points, int npoints,
2973                /* pen */ PEN * pen)
2974    {
2975            /* TODO: set join style */
2976            SET_FUNCTION(opcode);
2977            SET_FOREGROUND(pen->colour);
2978            XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2979            if (g_ownbackstore)
2980                    XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2981                               CoordModePrevious);
2982    
2983            ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2984                                    (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2985    
2986            RESET_FUNCTION(opcode);
2987    }
2988    
2989    void
2990    ui_ellipse(uint8 opcode,
2991               /* mode */ uint8 fillmode,
2992               /* dest */ int x, int y, int cx, int cy,
2993               /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2994    {
2995            uint8 style, i, ipattern[8];
2996            Pixmap fill;
2997    
2998            SET_FUNCTION(opcode);
2999    
3000            if (brush)
3001                    style = brush->style;
3002            else
3003                    style = 0;
3004    
3005            switch (style)
3006            {
3007                    case 0: /* Solid */
3008                            SET_FOREGROUND(fgcolour);
3009                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3010                            break;
3011    
3012                    case 2: /* Hatch */
3013                            fill = (Pixmap) ui_create_glyph(8, 8,
3014                                                            hatch_patterns + brush->pattern[0] * 8);
3015                            SET_FOREGROUND(fgcolour);
3016                            SET_BACKGROUND(bgcolour);
3017                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3018                            XSetStipple(g_display, g_gc, fill);
3019                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3020                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3021                            XSetFillStyle(g_display, g_gc, FillSolid);
3022                            XSetTSOrigin(g_display, g_gc, 0, 0);
3023                            ui_destroy_glyph((RD_HGLYPH) fill);
3024                            break;
3025    
3026                    case 3: /* Pattern */
3027                            for (i = 0; i != 8; i++)
3028                                    ipattern[7 - i] = brush->pattern[i];
3029                            fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3030                            SET_FOREGROUND(bgcolour);
3031                            SET_BACKGROUND(fgcolour);
3032                            XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3033                            XSetStipple(g_display, g_gc, fill);
3034                            XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3035                            DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3036                            XSetFillStyle(g_display, g_gc, FillSolid);
3037                            XSetTSOrigin(g_display, g_gc, 0, 0);
3038                            ui_destroy_glyph((RD_HGLYPH) fill);
3039                            break;
3040    
3041                    default:
3042                            unimpl("brush %d\n", brush->style);
3043            }
3044    
3045            RESET_FUNCTION(opcode);
3046    }
3047    
3048    /* warning, this function only draws on wnd or backstore, not both */
3049    void
3050  ui_draw_glyph(int mixmode,  ui_draw_glyph(int mixmode,
3051                /* dest */ int x, int y, int cx, int cy,                /* dest */ int x, int y, int cx, int cy,
3052                /* src */ HGLYPH glyph, int srcx, int srcy, int bgcolour,                /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3053                int fgcolour)                int bgcolour, int fgcolour)
3054  {  {
3055          SET_FOREGROUND(fgcolour);          SET_FOREGROUND(fgcolour);
3056          SET_BACKGROUND(bgcolour);          SET_BACKGROUND(bgcolour);
3057    
3058          XSetFillStyle(display, gc, (mixmode == MIX_TRANSPARENT)          XSetFillStyle(g_display, g_gc,
3059                        ? FillStippled : FillOpaqueStippled);                        (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3060          XSetStipple(display, gc, (Pixmap)glyph);          XSetStipple(g_display, g_gc, (Pixmap) glyph);
3061          XSetTSOrigin(display, gc, x, y);          XSetTSOrigin(g_display, g_gc, x, y);
3062    
3063          FILL_RECTANGLE(x, y, cx, cy);          FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3064    
3065          XSetFillStyle(display, gc, FillSolid);          XSetFillStyle(g_display, g_gc, FillSolid);
3066  }  }
3067    
3068  #define DO_GLYPH(ttext,idx) \  #define DO_GLYPH(ttext,idx) \
3069  {\  {\
3070    glyph = cache_get_font (font, ttext[idx]);\    glyph = cache_get_font (font, ttext[idx]);\
3071    if (!(flags & TEXT2_IMPLICIT_X))\    if (!(flags & TEXT2_IMPLICIT_X))\
3072      {\
3073        xyoffset = ttext[++idx];\
3074        if ((xyoffset & 0x80))\
3075      {\      {\
3076        xyoffset = ttext[++idx];\        if (flags & TEXT2_VERTICAL)\
3077        if ((xyoffset & 0x80))\          y += ttext[idx+1] | (ttext[idx+2] << 8);\
         {\  
           if (flags & TEXT2_VERTICAL) \  
             y += ttext[++idx] | (ttext[++idx] << 8);\  
           else\  
             x += ttext[++idx] | (ttext[++idx] << 8);\  
         }\  
3078        else\        else\
3079          {\          x += ttext[idx+1] | (ttext[idx+2] << 8);\
3080            if (flags & TEXT2_VERTICAL) \        idx += 2;\
             y += xyoffset;\  
           else\  
             x += xyoffset;\  
         }\  
3081      }\      }\
3082    if (glyph != NULL)\      else\
3083      {\      {\
3084        ui_draw_glyph (mixmode, x + (short) glyph->offset,\        if (flags & TEXT2_VERTICAL)\
3085                       y + (short) glyph->baseline,\          y += xyoffset;\
3086                       glyph->width, glyph->height,\        else\
3087                       glyph->pixmap, 0, 0, bgcolour, fgcolour);\          x += xyoffset;\
       if (flags & TEXT2_IMPLICIT_X)\  
         x += glyph->width;\  
3088      }\      }\
3089      }\
3090      if (glyph != NULL)\
3091      {\
3092        x1 = x + glyph->offset;\
3093        y1 = y + glyph->baseline;\
3094        XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3095        XSetTSOrigin(g_display, g_gc, x1, y1);\
3096        FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3097        if (flags & TEXT2_IMPLICIT_X)\
3098          x += glyph->width;\
3099      }\
3100  }  }
3101    
3102  void  void
3103  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,
3104               int clipx, int clipy, int clipcx, int clipcy, int boxx,               int clipx, int clipy, int clipcx, int clipcy,
3105               int boxy, int boxcx, int boxcy, int bgcolour,               int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3106               int fgcolour, uint8 * text, uint8 length)               int bgcolour, int fgcolour, uint8 * text, uint8 length)
3107  {  {
3108            /* TODO: use brush appropriately */
3109    
3110          FONTGLYPH *glyph;          FONTGLYPH *glyph;
3111          int i, j, xyoffset;          int i, j, xyoffset, x1, y1;
3112          DATABLOB *entry;          DATABLOB *entry;
3113    
3114          SET_FOREGROUND(bgcolour);          SET_FOREGROUND(bgcolour);
3115    
3116            /* Sometimes, the boxcx value is something really large, like
3117               32691. This makes XCopyArea fail with Xvnc. The code below
3118               is a quick fix. */
3119            if (boxx + boxcx > g_width)
3120                    boxcx = g_width - boxx;
3121    
3122          if (boxcx > 1)          if (boxcx > 1)
3123          {          {
3124                  FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);                  FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3125          }          }
3126          else if (mixmode == MIX_OPAQUE)          else if (mixmode == MIX_OPAQUE)
3127          {          {
3128                  FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);                  FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3129          }          }
3130    
3131            SET_FOREGROUND(fgcolour);
3132            SET_BACKGROUND(bgcolour);
3133            XSetFillStyle(g_display, g_gc, FillStippled);
3134    
3135          /* Paint text, character by character */          /* Paint text, character by character */
3136          for (i = 0; i < length;) {          for (i = 0; i < length;)
3137                  switch (text[i]) {          {
3138                  case 0xff:                  switch (text[i])
3139                          if (i + 2 < length)                  {
3140                            case 0xff:
3141                                    /* At least two bytes needs to follow */
3142                                    if (i + 3 > length)
3143                                    {
3144                                            warning("Skipping short 0xff command:");
3145                                            for (j = 0; j < length; j++)
3146                                                    fprintf(stderr, "%02x ", text[j]);
3147                                            fprintf(stderr, "\n");
3148                                            i = length = 0;
3149                                            break;
3150                                    }
3151                                  cache_put_text(text[i + 1], text, text[i + 2]);                                  cache_put_text(text[i + 1], text, text[i + 2]);
3152                          else {                                  i += 3;
3153                                  error("this shouldn't be happening\n");                                  length -= i;
3154                                    /* this will move pointer from start to first character after FF command */
3155                                    text = &(text[i]);
3156                                    i = 0;
3157                                  break;                                  break;
3158                          }  
3159                          /* this will move pointer from start to first character after FF command */                          case 0xfe:
3160                          length -= i + 3;                                  /* At least one byte needs to follow */
3161                          text = &(text[i + 3]);                                  if (i + 2 > length)
3162                          i = 0;                                  {
3163                          break;                                          warning("Skipping short 0xfe command:");
3164                                            for (j = 0; j < length; j++)
3165                  case 0xfe:                                                  fprintf(stderr, "%02x ", text[j]);
3166                          entry = cache_get_text(text[i + 1]);                                          fprintf(stderr, "\n");
3167                          if (entry != NULL) {                                          i = length = 0;
3168                                  if ((((uint8 *) (entry->data))[1] == 0)                                          break;
3169                                      && (!(flags & TEXT2_IMPLICIT_X))) {                                  }
3170                                          if (flags & TEXT2_VERTICAL)                                        entry = cache_get_text(text[i + 1]);
3171                                                  y += text[i + 2];                                  if (entry->data != NULL)
3172                                          else                                  {
3173                                                  x += text[i + 2];                                          if ((((uint8 *) (entry->data))[1] == 0)
3174                                                && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3175                                            {
3176                                                    if (flags & TEXT2_VERTICAL)
3177                                                            y += text[i + 2];
3178                                                    else
3179                                                            x += text[i + 2];
3180                                            }
3181                                            for (j = 0; j < entry->size; j++)
3182                                                    DO_GLYPH(((uint8 *) (entry->data)), j);
3183                                  }                                  }
3184                                  if (i + 2 < length)                                  if (i + 2 < length)
3185                                          i += 3;                                          i += 3;
3186                                  else                                  else
3187                                          i += 2;                                          i += 2;
3188                                  length -= i;                                    length -= i;
3189                                  /* this will move pointer from start to first character after FE command */                                  /* this will move pointer from start to first character after FE command */
3190                                  text = &(text[i]);                                  text = &(text[i]);
3191                                  i = 0;                                  i = 0;
3192                                  for (j = 0; j < entry->size; j++)                                  break;
                                         DO_GLYPH(((uint8 *) (entry->data)), j);  
                         }  
                         break;  
3193    
3194                  default:                          default:
3195                          DO_GLYPH(text, i);                                  DO_GLYPH(text, i);
3196                          i++;                                  i++;
3197                          break;                                  break;
3198                  }                  }
3199          }          }
3200    
3201            XSetFillStyle(g_display, g_gc, FillSolid);
3202    
3203            if (g_ownbackstore)
3204            {
3205                    if (boxcx > 1)
3206                    {
3207                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3208                                      boxy, boxcx, boxcy, boxx, boxy);
3209                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3210                                                    (g_display, g_backstore, sw->wnd, g_gc,
3211                                                     boxx, boxy,
3212                                                     boxcx, boxcy,
3213                                                     boxx - sw->xoffset, boxy - sw->yoffset));
3214                    }
3215                    else
3216                    {
3217                            XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3218                                      clipy, clipcx, clipcy, clipx, clipy);
3219                            ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3220                                                    (g_display, g_backstore, sw->wnd, g_gc,
3221                                                     clipx, clipy,
3222                                                     clipcx, clipcy, clipx - sw->xoffset,
3223                                                     clipy - sw->yoffset));
3224                    }
3225            }
3226  }  }
3227    
3228  void  void
# Line 971  ui_desktop_save(uint32 offset, int x, in Line 3231  ui_desktop_save(uint32 offset, int x, in
3231          Pixmap pix;          Pixmap pix;
3232          XImage *image;          XImage *image;
3233    
3234          if (ownbackstore)          if (g_ownbackstore)
3235          {          {
3236                  image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes,                  image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3237                                    ZPixmap);                  exit_if_null(image);
3238          }          }
3239          else          else
3240          {          {
3241                  pix = XCreatePixmap(display, wnd, cx, cy, depth);                  pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3242                  XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);                  XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3243                  image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes,                  image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3244                                    ZPixmap);                  exit_if_null(image);
3245                  XFreePixmap(display, pix);                  XFreePixmap(g_display, pix);
3246          }          }
3247    
3248          offset *= bpp/8;          offset *= g_bpp / 8;
3249          cache_put_desktop(offset, cx, cy, image->bytes_per_line,          cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
                           bpp/8, (uint8 *)image->data);  
3250    
3251          XDestroyImage(image);          XDestroyImage(image);
3252  }  }
# Line 998  ui_desktop_restore(uint32 offset, int x, Line 3257  ui_desktop_restore(uint32 offset, int x,
3257          XImage *image;          XImage *image;
3258          uint8 *data;          uint8 *data;
3259    
3260          offset *= bpp/8;          offset *= g_bpp / 8;
3261          data = cache_get_desktop(offset, cx, cy, bpp/8);          data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3262          if (data == NULL)          if (data == NULL)
3263                  return;                  return;
3264    
3265          image = XCreateImage(display, visual, depth, ZPixmap,          image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3266                               0, data, cx, cy, BitmapPad(display),                               (char *) data, cx, cy, g_bpp, 0);
                              cx * bpp/8);  
3267    
3268          if (ownbackstore)          if (g_ownbackstore)
3269          {          {
3270                  XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3271                  XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);                  XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3272                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3273                                            (g_display, g_backstore, sw->wnd, g_gc,
3274                                             x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3275          }          }
3276          else          else
3277          {          {
3278                  XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);                  XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3279                    ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3280                                            (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3281                                             x - sw->xoffset, y - sw->yoffset));
3282          }          }
3283    
3284          XFree(image);          XFree(image);
3285  }  }
3286    
3287    /* these do nothing here but are used in uiports */
3288    void
3289    ui_begin_update(void)
3290    {
3291    }
3292    
3293    void
3294    ui_end_update(void)
3295    {
3296    }
3297    
3298    
3299    void
3300    ui_seamless_begin(RD_BOOL hidden)
3301    {
3302            if (!g_seamless_rdp)
3303                    return;
3304    
3305            if (g_seamless_started)
3306                    return;
3307    
3308            g_seamless_started = True;
3309            g_seamless_hidden = hidden;
3310    
3311            if (!hidden)
3312                    ui_seamless_toggle();
3313    }
3314    
3315    
3316    void
3317    ui_seamless_hide_desktop()
3318    {
3319            if (!g_seamless_rdp)
3320                    return;
3321    
3322            if (!g_seamless_started)
3323                    return;
3324    
3325            if (g_seamless_active)
3326                    ui_seamless_toggle();
3327    
3328            g_seamless_hidden = True;
3329    }
3330    
3331    
3332    void
3333    ui_seamless_unhide_desktop()
3334    {
3335            if (!g_seamless_rdp)
3336                    return;
3337    
3338            if (!g_seamless_started)
3339                    return;
3340    
3341            g_seamless_hidden = False;
3342    
3343            ui_seamless_toggle();
3344    }
3345    
3346    
3347    void
3348    ui_seamless_toggle()
3349    {
3350            if (!g_seamless_rdp)
3351                    return;
3352    
3353            if (!g_seamless_started)
3354                    return;
3355    
3356            if (g_seamless_hidden)
3357                    return;
3358    
3359            if (g_seamless_active)
3360            {
3361                    /* Deactivate */
3362                    while (g_seamless_windows)
3363                    {
3364                            XDestroyWindow(g_display, g_seamless_windows->wnd);
3365                            sw_remove_window(g_seamless_windows);
3366                    }
3367                    XMapWindow(g_display, g_wnd);
3368            }
3369            else
3370            {
3371                    /* Activate */
3372                    XUnmapWindow(g_display, g_wnd);
3373                    seamless_send_sync();
3374            }
3375    
3376            g_seamless_active = !g_seamless_active;
3377    }
3378    
3379    
3380    void
3381    ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3382                              unsigned long flags)
3383    {
3384            Window wnd;
3385            XSetWindowAttributes attribs;
3386            XClassHint *classhints;
3387            XSizeHints *sizehints;
3388            XWMHints *wmhints;
3389            long input_mask;
3390            seamless_window *sw, *sw_parent;
3391    
3392            if (!g_seamless_active)
3393                    return;
3394    
3395            /* Ignore CREATEs for existing windows */
3396            sw = sw_get_window_by_id(id);
3397            if (sw)
3398                    return;
3399    
3400            get_window_attribs(&attribs);
3401            wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3402                                InputOutput, g_visual,
3403                                CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3404    
3405            XStoreName(g_display, wnd, "SeamlessRDP");
3406            ewmh_set_wm_name(wnd, "SeamlessRDP");
3407    
3408            mwm_hide_decorations(wnd);
3409    
3410            classhints = XAllocClassHint();
3411            if (classhints != NULL)
3412            {
3413                    classhints->res_name = "rdesktop";
3414                    classhints->res_class = "SeamlessRDP";
3415                    XSetClassHint(g_display, wnd, classhints);
3416                    XFree(classhints);
3417            }
3418    
3419            /* WM_NORMAL_HINTS */
3420            sizehints = XAllocSizeHints();
3421            if (sizehints != NULL)
3422            {
3423                    sizehints->flags = USPosition;
3424                    XSetWMNormalHints(g_display, wnd, sizehints);
3425                    XFree(sizehints);
3426            }
3427    
3428            /* Parent-less transient windows */
3429            if (parent == 0xFFFFFFFF)
3430            {
3431                    XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3432                    /* Some buggy wm:s (kwin) do not handle the above, so fake it
3433                       using some other hints. */
3434                    ewmh_set_window_popup(wnd);
3435            }
3436            /* Normal transient windows */
3437            else if (parent != 0x00000000)
3438            {
3439                    sw_parent = sw_get_window_by_id(parent);
3440                    if (sw_parent)
3441                            XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3442                    else
3443                            warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3444            }
3445    
3446            if (flags & SEAMLESSRDP_CREATE_MODAL)
3447            {
3448                    /* We do this to support buggy wm:s (*cough* metacity *cough*)
3449                       somewhat at least */
3450                    if (parent == 0x00000000)
3451                            XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3452                    ewmh_set_window_modal(wnd);
3453            }
3454    
3455            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3456            {
3457                    /* Make window always-on-top */
3458                    ewmh_set_window_above(wnd);
3459            }
3460    
3461            /* FIXME: Support for Input Context:s */
3462    
3463            get_input_mask(&input_mask);
3464            input_mask |= PropertyChangeMask;
3465    
3466            XSelectInput(g_display, wnd, input_mask);
3467    
3468            /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3469               seamless window, we could try to close the window on the
3470               serverside, instead of terminating rdesktop */
3471            XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3472    
3473            sw = xmalloc(sizeof(seamless_window));
3474    
3475            memset(sw, 0, sizeof(seamless_window));
3476    
3477            sw->wnd = wnd;
3478            sw->id = id;
3479            sw->group = sw_find_group(group, False);
3480            sw->group->refcnt++;
3481            sw->state = SEAMLESSRDP_NOTYETMAPPED;
3482            sw->desktop = 0;
3483            sw->position_timer = xmalloc(sizeof(struct timeval));
3484            timerclear(sw->position_timer);
3485    
3486            sw->outstanding_position = False;
3487            sw->outpos_serial = 0;
3488            sw->outpos_xoffset = sw->outpos_yoffset = 0;
3489            sw->outpos_width = sw->outpos_height = 0;
3490    
3491            sw->next = g_seamless_windows;
3492            g_seamless_windows = sw;
3493    
3494            /* WM_HINTS */
3495            wmhints = XAllocWMHints();
3496            if (wmhints)
3497            {
3498                    wmhints->flags = WindowGroupHint;
3499                    wmhints->window_group = sw->group->wnd;
3500                    XSetWMHints(g_display, sw->wnd, wmhints);
3501                    XFree(wmhints);
3502            }
3503    }
3504    
3505    
3506    void
3507    ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3508    {
3509            seamless_window *sw;
3510    
3511            if (!g_seamless_active)
3512                    return;
3513    
3514            sw = sw_get_window_by_id(id);
3515            if (!sw)
3516            {
3517                    warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3518                    return;
3519            }
3520    
3521            XDestroyWindow(g_display, sw->wnd);
3522            sw_remove_window(sw);
3523    }
3524    
3525    
3526    void
3527    ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3528    {
3529            seamless_window *sw, *sw_next;
3530    
3531            if (!g_seamless_active)
3532                    return;
3533    
3534            for (sw = g_seamless_windows; sw; sw = sw_next)
3535            {
3536                    sw_next = sw->next;
3537    
3538                    if (sw->group->id == id)
3539                    {
3540                            XDestroyWindow(g_display, sw->wnd);
3541                            sw_remove_window(sw);
3542                    }
3543            }
3544    }
3545    
3546    
3547    void
3548    ui_seamless_seticon(unsigned long id, const char *format, int width, int height, int chunk,
3549                        const char *data, int chunk_len)
3550    {
3551            seamless_window *sw;
3552    
3553            if (!g_seamless_active)
3554                    return;
3555    
3556            sw = sw_get_window_by_id(id);
3557            if (!sw)
3558            {
3559                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3560                    return;
3561            }
3562    
3563            if (chunk == 0)
3564            {
3565                    if (sw->icon_size)
3566                            warning("ui_seamless_seticon: New icon started before previous completed\n");
3567    
3568                    if (strcmp(format, "RGBA") != 0)
3569                    {
3570                            warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3571                            return;
3572                    }
3573    
3574                    sw->icon_size = width * height * 4;
3575                    if (sw->icon_size > 32 * 32 * 4)
3576                    {
3577                            warning("ui_seamless_seticon: Icon too large (%d bytes)\n", sw->icon_size);
3578                            sw->icon_size = 0;
3579                            return;
3580                    }
3581    
3582                    sw->icon_offset = 0;
3583            }
3584            else
3585            {
3586                    if (!sw->icon_size)
3587                            return;
3588            }
3589    
3590            if (chunk_len > (sw->icon_size - sw->icon_offset))
3591            {
3592                    warning("ui_seamless_seticon: Too large chunk received (%d bytes > %d bytes)\n",
3593                            chunk_len, sw->icon_size - sw->icon_offset);
3594                    sw->icon_size = 0;
3595                    return;
3596            }
3597    
3598            memcpy(sw->icon_buffer + sw->icon_offset, data, chunk_len);
3599            sw->icon_offset += chunk_len;
3600    
3601            if (sw->icon_offset == sw->icon_size)
3602            {
3603                    ewmh_set_icon(sw->wnd, width, height, sw->icon_buffer);
3604                    sw->icon_size = 0;
3605            }
3606    }
3607    
3608    
3609    void
3610    ui_seamless_delicon(unsigned long id, const char *format, int width, int height)
3611    {
3612            seamless_window *sw;
3613    
3614            if (!g_seamless_active)
3615                    return;
3616    
3617            sw = sw_get_window_by_id(id);
3618            if (!sw)
3619            {
3620                    warning("ui_seamless_seticon: No information for window 0x%lx\n", id);
3621                    return;
3622            }
3623    
3624            if (strcmp(format, "RGBA") != 0)
3625            {
3626                    warning("ui_seamless_seticon: Uknown icon format \"%s\"\n", format);
3627                    return;
3628            }
3629    
3630            ewmh_del_icon(sw->wnd, width, height);
3631    }
3632    
3633    
3634    void
3635    ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3636    {
3637            seamless_window *sw;
3638    
3639            if (!g_seamless_active)
3640                    return;
3641    
3642            sw = sw_get_window_by_id(id);
3643            if (!sw)
3644            {
3645                    warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3646                    return;
3647            }
3648    
3649            /* We ignore server updates until it has handled our request. */
3650            if (sw->outstanding_position)
3651                    return;
3652    
3653            if (!width || !height)
3654                    /* X11 windows must be at least 1x1 */
3655                    return;
3656    
3657            sw->xoffset = x;
3658            sw->yoffset = y;
3659            sw->width = width;
3660            sw->height = height;
3661    
3662            /* If we move the window in a maximized state, then KDE won't
3663               accept restoration */
3664            switch (sw->state)
3665            {
3666                    case SEAMLESSRDP_MINIMIZED:
3667                    case SEAMLESSRDP_MAXIMIZED:
3668                            return;
3669            }
3670    
3671            /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3672            XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3673    }
3674    
3675    
3676    void
3677    ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3678    {
3679            seamless_window *sw;
3680    
3681            if (!g_seamless_active)
3682                    return;
3683    
3684            sw = sw_get_window_by_id(id);
3685            if (!sw)
3686            {
3687                    warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3688                    return;
3689            }
3690    
3691            if (behind)
3692            {
3693                    seamless_window *sw_behind;
3694                    Window wnds[2];
3695    
3696                    sw_behind = sw_get_window_by_id(behind);
3697                    if (!sw_behind)
3698                    {
3699                            warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3700                                    behind);
3701                            return;
3702                    }
3703    
3704                    wnds[1] = sw_behind->wnd;
3705                    wnds[0] = sw->wnd;
3706    
3707                    XRestackWindows(g_display, wnds, 2);
3708            }
3709            else
3710            {
3711                    XRaiseWindow(g_display, sw->wnd);
3712            }
3713    
3714            sw_restack_window(sw, behind);
3715    
3716            if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3717            {
3718                    /* Make window always-on-top */
3719                    ewmh_set_window_above(sw->wnd);
3720            }
3721    }
3722    
3723    
3724    void
3725    ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3726    {
3727            seamless_window *sw;
3728    
3729            if (!g_seamless_active)
3730                    return;
3731    
3732            sw = sw_get_window_by_id(id);
3733            if (!sw)
3734            {
3735                    warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3736                    return;
3737            }
3738    
3739            /* FIXME: Might want to convert the name for non-EWMH WMs */
3740            XStoreName(g_display, sw->wnd, title);
3741            ewmh_set_wm_name(sw->wnd, title);
3742    }
3743    
3744    
3745    void
3746    ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3747    {
3748            seamless_window *sw;
3749    
3750            if (!g_seamless_active)
3751                    return;
3752    
3753            sw = sw_get_window_by_id(id);
3754            if (!sw)
3755            {
3756                    warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3757                    return;
3758            }
3759    
3760            switch (state)
3761            {
3762                    case SEAMLESSRDP_NORMAL:
3763                    case SEAMLESSRDP_MAXIMIZED:
3764                            ewmh_change_state(sw->wnd, state);
3765                            XMapWindow(g_display, sw->wnd);
3766                            break;
3767                    case SEAMLESSRDP_MINIMIZED:
3768                            /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3769                               the Window Manager should probably just ignore the request, since
3770                               _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3771                               such as minimization, rather than an independent state." Besides,
3772                               XIconifyWindow is easier. */
3773                            if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3774                            {
3775                                    XWMHints *hints;
3776                                    hints = XGetWMHints(g_display, sw->wnd);
3777                                    if (hints)
3778                                    {
3779                                            hints->flags |= StateHint;
3780                                            hints->initial_state = IconicState;
3781                                            XSetWMHints(g_display, sw->wnd, hints);
3782                                            XFree(hints);
3783                                    }
3784                                    XMapWindow(g_display, sw->wnd);
3785                            }
3786                            else
3787                                    XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3788                            break;
3789                    default:
3790                            warning("SeamlessRDP: Invalid state %d\n", state);
3791                            break;
3792            }
3793    
3794            sw->state = state;
3795    }
3796    
3797    
3798    void
3799    ui_seamless_syncbegin(unsigned long flags)
3800    {
3801            if (!g_seamless_active)
3802                    return;
3803    
3804            /* Destroy all seamless windows */
3805            while (g_seamless_windows)
3806            {
3807                    XDestroyWindow(g_display, g_seamless_windows->wnd);
3808                    sw_remove_window(g_seamless_windows);
3809            }
3810    }
3811    
3812    
3813    void
3814    ui_seamless_ack(unsigned int serial)
3815    {
3816            seamless_window *sw;
3817            for (sw = g_seamless_windows; sw; sw = sw->next)
3818            {
3819                    if (sw->outstanding_position && (sw->outpos_serial == serial))
3820                    {
3821                            sw->xoffset = sw->outpos_xoffset;
3822                            sw->yoffset = sw->outpos_yoffset;
3823                            sw->width = sw->outpos_width;
3824                            sw->height = sw->outpos_height;
3825                            sw->outstanding_position = False;
3826    
3827                            /* Do a complete redraw of the window as part of the
3828                               completion of the move. This is to remove any
3829                               artifacts caused by our lack of synchronization. */
3830                            XCopyArea(g_display, g_backstore,
3831                                      sw->wnd, g_gc,
3832                                      sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3833    
3834                            break;
3835                    }
3836            }
3837    }

Legend:
Removed from v.49  
changed lines
  Added in v.1443

  ViewVC Help
Powered by ViewVC 1.1.26