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

Legend:
Removed from v.28  
changed lines
  Added in v.1193

  ViewVC Help
Powered by ViewVC 1.1.26