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

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

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

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

Legend:
Removed from v.25  
changed lines
  Added in v.1459

  ViewVC Help
Powered by ViewVC 1.1.26