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

Legend:
Removed from v.208  
changed lines
  Added in v.1223

  ViewVC Help
Powered by ViewVC 1.1.26