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

Diff of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

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

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

Legend:
Removed from v.263  
changed lines
  Added in v.1177

  ViewVC Help
Powered by ViewVC 1.1.26