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

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

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.26