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

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

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

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

Legend:
Removed from v.84  
changed lines
  Added in v.1171

  ViewVC Help
Powered by ViewVC 1.1.26