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

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

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

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

Legend:
Removed from v.278  
changed lines
  Added in v.1226

  ViewVC Help
Powered by ViewVC 1.1.26