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

Legend:
Removed from v.35  
changed lines
  Added in v.1151

  ViewVC Help
Powered by ViewVC 1.1.26