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

Legend:
Removed from v.116  
changed lines
  Added in v.1413

  ViewVC Help
Powered by ViewVC 1.1.26