/[rdesktop]/jpeg/rdesktop/trunk/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

Annotation of /jpeg/rdesktop/trunk/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1459 - (hide annotations)
Wed Mar 26 16:44:55 2008 UTC (16 years, 2 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 95394 byte(s)
Re-worked the support for SeamlessRDP window stacking:

* Since many window managers cannot properly restack a window between
two other windows, we need to check for this at startup.

* A new utility function, sw_wait_configurenotify, is used to wait for
the WM to process our restacking request.

* We are using XReconfigureWMWindow instead of XRestackWindows and
XRaiseWindow, to easier meet the demands of ICCCM. Restacking between
is only done if the WM is not broken, though.

* The error handler does not ignore BadMatch from ConfigureWindow
requests any longer. I haven't found any WM that gives BadMatch for
XReconfigureWMWindow.

* The test cases has been updated to test more stacking cases.


A somewhat related bug fix wrt focus handling is also included, which
prevents FOCUS messages when reverting focus from a destroyed window

1 forsberg 415 /* -*- c-basic-offset: 8 -*-
2 matty 6 rdesktop: A Remote Desktop Protocol client.
3 matthewc 38 User interface services - X Window System
4 jsorg71 1365 Copyright (C) Matthew Chapman 1999-2007
5 ossman_ 1413 Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 n-ki 52
7 matty 6 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
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 n-ki 52
12 matty 6 This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16 n-ki 52
17 matty 6 You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20     */
21    
22 matty 10 #include <X11/Xlib.h>
23 matty 28 #include <X11/Xutil.h>
24 stargo 1370 #include <X11/Xproto.h>
25 matthewc 537 #include <unistd.h>
26 stargo 609 #include <sys/time.h>
27 matty 10 #include <time.h>
28 matty 33 #include <errno.h>
29 stargo 603 #include <strings.h>
30 matty 10 #include "rdesktop.h"
31 forsberg 415 #include "xproto.h"
32 matty 6
33 jsorg71 447 extern int g_width;
34     extern int g_height;
35 stargo 800 extern int g_xpos;
36     extern int g_ypos;
37 stargo 867 extern int g_pos;
38 jsorg71 1372 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 jsorg71 450 extern char g_title[];
43 astrand 1042 /* 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 jsorg71 450 extern int g_win_button_size;
47 matty 10
48 jsorg71 450 Display *g_display;
49     Time g_last_gesturetime;
50     static int g_x_socket;
51     static Screen *g_screen;
52     Window g_wnd;
53 astrand 1199
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 jsorg71 1372 RD_BOOL outstanding_position;
74 astrand 1199 unsigned int outpos_serial;
75     int outpos_xoffset, outpos_yoffset;
76     int outpos_width, outpos_height;
77    
78 ossman_ 1413 unsigned int icon_size;
79     unsigned int icon_offset;
80     char icon_buffer[32 * 32 * 4];
81    
82 astrand 1199 struct _seamless_window *next;
83     } seamless_window;
84     static seamless_window *g_seamless_windows = NULL;
85     static unsigned long g_seamless_focused = 0;
86 jsorg71 1372 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 astrand 1459 static RD_BOOL g_seamless_broken_restack = False; /* WM does not properly restack */
90 jsorg71 1372 extern RD_BOOL g_seamless_rdp;
91 astrand 1199
92 stargo 648 extern uint32 g_embed_wnd;
93 jsorg71 1372 RD_BOOL g_enable_compose = False;
94     RD_BOOL g_Unobscured; /* used for screenblt */
95 stargo 576 static GC g_gc = NULL;
96 jsorg71 725 static GC g_create_bitmap_gc = NULL;
97     static GC g_create_glyph_gc = NULL;
98 astrand 1199 static XRectangle g_clip_rectangle;
99 jsorg71 450 static Visual *g_visual;
100 astrand 1042 /* 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 jsorg71 450 static int g_depth;
104 astrand 1042 /* 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 jsorg71 450 static int g_bpp;
108     static XIM g_IM;
109     static XIC g_IC;
110     static XModifierKeymap *g_mod_map;
111 astrand 1407 /* 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 jsorg71 450 static Cursor g_current_cursor;
115 jsorg71 1364 static RD_HCURSOR g_null_cursor = NULL;
116 jsorg71 450 static Atom g_protocol_atom, g_kill_atom;
117 astrand 1199 extern Atom g_net_wm_state_atom;
118     extern Atom g_net_wm_desktop_atom;
119 jsorg71 1372 static RD_BOOL g_focused;
120     static RD_BOOL g_mouse_in_wnd;
121 astrand 1049 /* 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 jsorg71 1372 static RD_BOOL g_compatible_arch;
128 astrand 1042 /* Indicates whether RDP's bitmaps and our XImages have the same
129     binary format. If so, we can avoid an expensive translation.
130 astrand 1049 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 jsorg71 1372 static RD_BOOL g_no_translate_image = False;
139 matty 29
140 matty 33 /* endianness */
141 jsorg71 1372 static RD_BOOL g_host_be;
142     static RD_BOOL g_xserver_be;
143 matthewc 527 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 matty 33
146     /* software backing store */
147 jsorg71 1372 extern RD_BOOL g_ownbackstore;
148 stargo 603 static Pixmap g_backstore = 0;
149 matty 31
150 astrand 342 /* Moving in single app mode */
151 jsorg71 1372 static RD_BOOL g_moving_wnd;
152 jsorg71 450 static int g_move_x_offset = 0;
153     static int g_move_y_offset = 0;
154 jsorg71 1372 static RD_BOOL g_using_full_workarea = False;
155 astrand 342
156 matthewc 474 #ifdef WITH_RDPSND
157 jsorg71 1372 extern RD_BOOL g_rdpsnd;
158 matthewc 474 #endif
159    
160 astrand 262 /* MWM decorations */
161     #define MWM_HINTS_DECORATIONS (1L << 1)
162     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
163     typedef struct
164     {
165 astrand 1033 unsigned long flags;
166     unsigned long functions;
167     unsigned long decorations;
168     long inputMode;
169     unsigned long status;
170 astrand 262 }
171     PropMotifWmHints;
172    
173 jsorg71 316 typedef struct
174     {
175     uint32 red;
176     uint32 green;
177     uint32 blue;
178     }
179     PixelColour;
180 astrand 262
181 astrand 1199 #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 forsberg 415
197 astrand 1199 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 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
218     { \
219 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
220 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
221 jsorg71 450 if (g_ownbackstore) \
222     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
223 matty 31 }
224    
225 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
226 jsorg71 281 { \
227 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
228 jsorg71 281 }
229    
230 jdmeijer 831 #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 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
236 jdmeijer 831 }
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 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
245 jdmeijer 831 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 jsorg71 1022 XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
250 astrand 1249 ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
251 jdmeijer 831 if (g_ownbackstore) \
252 jsorg71 1022 XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
253 jdmeijer 831 break; \
254     } \
255     }
256    
257 matty 33 /* colour maps */
258 jsorg71 1372 extern RD_BOOL g_owncolmap;
259 jsorg71 450 static Colormap g_xcolmap;
260     static uint32 *g_colmap = NULL;
261 matty 10
262 astrand 1042 #define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
263 jsorg71 450 #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
264     #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
265 matty 28
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 jsorg71 450 #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 matty 29
288 astrand 1199 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 astrand 319 static void
315 astrand 1199 sw_remove_window(seamless_window * win)
316 astrand 262 {
317 astrand 1199 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    
338    
339     /* Move all windows except wnd to new desktop */
340     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     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 jsorg71 1372 sw_find_group(unsigned long id, RD_BOOL dont_create)
483 astrand 1199 {
484     seamless_window *sw;
485     seamless_group *sg;
486     XSetWindowAttributes attribs;
487    
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 astrand 262 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 jsorg71 450 hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
522 astrand 262 if (!hintsatom)
523     {
524 matthewc 297 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
525 astrand 262 return;
526     }
527    
528 astrand 1199 XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
529 astrand 262 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
530 astrand 1199
531 astrand 262 }
532    
533 astrand 1459 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 jdmeijer 821 #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 jsorg71 311 }
776    
777 jdmeijer 821 #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 jsorg71 311
784 jdmeijer 821 #define SPLITCOLOUR24(colour, rv) \
785     { \
786     rv.blue = (colour & 0xff0000) >> 16; \
787     rv.green = (colour & 0x00ff00) >> 8; \
788     rv.red = (colour & 0x0000ff); \
789 jsorg71 311 }
790    
791 jdmeijer 821 #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 jsorg71 316
796 jsorg71 311 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
797 stargo 534 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
798 jsorg71 311 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
799     x = (x << 16) | (x >> 16); }
800    
801 astrand 1049 /* The following macros output the same octet sequences
802     on both BE and LE hosts: */
803    
804 jdmeijer 821 #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 jsorg71 311 static uint32
812     translate_colour(uint32 colour)
813     {
814 matthewc 527 PixelColour pc;
815 astrand 1042 switch (g_server_depth)
816 jsorg71 311 {
817 jsorg71 316 case 15:
818 jdmeijer 821 SPLITCOLOUR15(colour, pc);
819 jsorg71 316 break;
820 jsorg71 311 case 16:
821 jdmeijer 821 SPLITCOLOUR16(colour, pc);
822 jsorg71 311 break;
823     case 24:
824 jsorg71 1417 case 32:
825 jdmeijer 821 SPLITCOLOUR24(colour, pc);
826 jsorg71 311 break;
827 astrand 1042 default:
828     /* Avoid warning */
829     pc.red = 0;
830     pc.green = 0;
831     pc.blue = 0;
832     break;
833 jsorg71 311 }
834 jdmeijer 821 return MAKECOLOUR(pc);
835 jsorg71 311 }
836    
837 jsorg71 709 /* 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 jsorg71 679 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
846 jsorg71 709 /* 2 byte output repeat */
847     #define REPEAT2(stm) \
848 jsorg71 679 { \
849 jsorg71 709 while (out <= end - 8 * 2) \
850     UNROLL8(stm) \
851     while (out < end) \
852     { stm } \
853     }
854 jdmeijer 821 /* 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 jsorg71 709 /* 4 byte output repeat */
863     #define REPEAT4(stm) \
864     { \
865 jsorg71 679 while (out <= end - 8 * 4) \
866     UNROLL8(stm) \
867     while (out < end) \
868     { stm } \
869     }
870 jdmeijer 821 /* *INDENT-ON* */
871 jsorg71 679
872 matty 28 static void
873 jdmeijer 821 translate8to8(const uint8 * data, uint8 * out, uint8 * end)
874 matty 28 {
875 matty 29 while (out < end)
876 jsorg71 450 *(out++) = (uint8) g_colmap[*(data++)];
877 matty 29 }
878 matty 28
879 matty 29 static void
880 jdmeijer 821 translate8to16(const uint8 * data, uint8 * out, uint8 * end)
881 matty 29 {
882 stargo 521 uint16 value;
883    
884 astrand 1049 if (g_compatible_arch)
885 stargo 521 {
886 jdmeijer 821 /* *INDENT-OFF* */
887 jsorg71 709 REPEAT2
888     (
889     *((uint16 *) out) = g_colmap[*(data++)];
890     out += 2;
891     )
892 jdmeijer 821 /* *INDENT-ON* */
893 jsorg71 643 }
894 jsorg71 709 else if (g_xserver_be)
895 jsorg71 643 {
896 jsorg71 709 while (out < end)
897     {
898     value = (uint16) g_colmap[*(data++)];
899 jdmeijer 821 BOUT16(out, value);
900 jsorg71 709 }
901 stargo 521 }
902 jsorg71 709 else
903     {
904     while (out < end)
905     {
906     value = (uint16) g_colmap[*(data++)];
907 jdmeijer 821 LOUT16(out, value);
908 jsorg71 709 }
909     }
910 matty 29 }
911    
912 jsorg71 316 /* little endian - conversion happens when colourmap is built */
913 jsorg71 311 static void
914 jdmeijer 821 translate8to24(const uint8 * data, uint8 * out, uint8 * end)
915 jsorg71 311 {
916 jsorg71 316 uint32 value;
917    
918 astrand 1049 if (g_compatible_arch)
919 jsorg71 316 {
920 jsorg71 643 while (out < end)
921 stargo 521 {
922 jsorg71 643 value = g_colmap[*(data++)];
923 jdmeijer 821 BOUT24(out, value);
924 stargo 521 }
925 jsorg71 643 }
926     else
927     {
928     while (out < end)
929 stargo 521 {
930 jsorg71 643 value = g_colmap[*(data++)];
931 jdmeijer 821 LOUT24(out, value);
932 stargo 521 }
933 jsorg71 316 }
934 jsorg71 311 }
935    
936 matty 29 static void
937 jdmeijer 821 translate8to32(const uint8 * data, uint8 * out, uint8 * end)
938 matty 29 {
939 stargo 521 uint32 value;
940    
941 astrand 1049 if (g_compatible_arch)
942 stargo 521 {
943 jdmeijer 821 /* *INDENT-OFF* */
944 jsorg71 709 REPEAT4
945     (
946     *((uint32 *) out) = g_colmap[*(data++)];
947     out += 4;
948     )
949 jdmeijer 821 /* *INDENT-ON* */
950 jsorg71 643 }
951 jsorg71 709 else if (g_xserver_be)
952 jsorg71 643 {
953 jsorg71 709 while (out < end)
954     {
955     value = g_colmap[*(data++)];
956 jdmeijer 821 BOUT32(out, value);
957 jsorg71 709 }
958 stargo 521 }
959 jsorg71 709 else
960     {
961     while (out < end)
962     {
963     value = g_colmap[*(data++)];
964 jdmeijer 821 LOUT32(out, value);
965 jsorg71 709 }
966     }
967 jsorg71 316 }
968    
969     static void
970 jdmeijer 821 translate15to16(const uint16 * data, uint8 * out, uint8 * end)
971 jsorg71 316 {
972 jsorg71 483 uint16 pixel;
973     uint16 value;
974 jdmeijer 821 PixelColour pc;
975 jsorg71 483
976 jdmeijer 821 if (g_xserver_be)
977 jsorg71 483 {
978 jdmeijer 821 while (out < end)
979 jsorg71 483 {
980 jdmeijer 821 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 stargo 521 }
989 jdmeijer 821 }
990     else
991     {
992     while (out < end)
993 jsorg71 483 {
994 jdmeijer 821 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 jsorg71 483 }
1003     }
1004 jsorg71 316 }
1005    
1006     static void
1007 jdmeijer 821 translate15to24(const uint16 * data, uint8 * out, uint8 * end)
1008 jsorg71 316 {
1009 matty 29 uint32 value;
1010 jsorg71 483 uint16 pixel;
1011 jdmeijer 821 PixelColour pc;
1012 matty 29
1013 astrand 1049 if (g_compatible_arch)
1014 matty 28 {
1015 jdmeijer 821 /* *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 jsorg71 483 {
1030 jdmeijer 821 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 stargo 521 }
1039 jdmeijer 821 }
1040     else
1041     {
1042     while (out < end)
1043 jsorg71 483 {
1044 jdmeijer 821 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 jsorg71 483 }
1053 matty 28 }
1054     }
1055    
1056     static void
1057 jdmeijer 821 translate15to32(const uint16 * data, uint8 * out, uint8 * end)
1058 jsorg71 316 {
1059 jsorg71 472 uint16 pixel;
1060 jsorg71 483 uint32 value;
1061 jdmeijer 821 PixelColour pc;
1062 jsorg71 472
1063 astrand 1049 if (g_compatible_arch)
1064 jsorg71 472 {
1065 jdmeijer 821 /* *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 jsorg71 472 {
1081 jdmeijer 821 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 jsorg71 472 }
1090 jdmeijer 821 }
1091     else
1092     {
1093     while (out < end)
1094 jsorg71 483 {
1095 jdmeijer 821 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 jsorg71 483 }
1104 jsorg71 472 }
1105 jsorg71 316 }
1106    
1107     static void
1108 jdmeijer 821 translate16to16(const uint16 * data, uint8 * out, uint8 * end)
1109 jsorg71 316 {
1110 matthewc 528 uint16 pixel;
1111 jsorg71 483 uint16 value;
1112 jdmeijer 821 PixelColour pc;
1113 jsorg71 483
1114 jdmeijer 821 if (g_xserver_be)
1115 jsorg71 483 {
1116 matthewc 528 if (g_host_be)
1117 jsorg71 483 {
1118 jdmeijer 821 while (out < end)
1119     {
1120     pixel = *(data++);
1121     BSWAP16(pixel);
1122     SPLITCOLOUR16(pixel, pc);
1123     value = MAKECOLOUR(pc);
1124     BOUT16(out, value);
1125     }
1126 jsorg71 483 }
1127 jdmeijer 821 else
1128 jsorg71 483 {
1129 jdmeijer 821 while (out < end)
1130     {
1131     pixel = *(data++);
1132     SPLITCOLOUR16(pixel, pc);
1133     value = MAKECOLOUR(pc);
1134     BOUT16(out, value);
1135     }
1136 jsorg71 483 }
1137 jdmeijer 821 }
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 matthewc 528 else
1152     {
1153 jdmeijer 821 while (out < end)
1154     {
1155     pixel = *(data++);
1156     SPLITCOLOUR16(pixel, pc);
1157     value = MAKECOLOUR(pc);
1158     LOUT16(out, value);
1159     }
1160 matthewc 528 }
1161 jsorg71 483 }
1162 jsorg71 316 }
1163    
1164     static void
1165 jdmeijer 821 translate16to24(const uint16 * data, uint8 * out, uint8 * end)
1166 matty 28 {
1167 jsorg71 311 uint32 value;
1168 jsorg71 483 uint16 pixel;
1169 jdmeijer 821 PixelColour pc;
1170 jsorg71 311
1171 astrand 1049 if (g_compatible_arch)
1172 jsorg71 311 {
1173 jdmeijer 821 /* *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 jsorg71 483 if (g_host_be)
1187     {
1188 jdmeijer 821 while (out < end)
1189     {
1190     pixel = *(data++);
1191     BSWAP16(pixel);
1192     SPLITCOLOUR16(pixel, pc);
1193     value = MAKECOLOUR(pc);
1194     BOUT24(out, value);
1195     }
1196 stargo 521 }
1197 jdmeijer 821 else
1198 jsorg71 483 {
1199 jdmeijer 821 while (out < end)
1200     {
1201     pixel = *(data++);
1202     SPLITCOLOUR16(pixel, pc);
1203     value = MAKECOLOUR(pc);
1204     BOUT24(out, value);
1205     }
1206 jsorg71 483 }
1207 jdmeijer 821 }
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 jsorg71 483 else
1222     {
1223 jdmeijer 821 while (out < end)
1224     {
1225     pixel = *(data++);
1226     SPLITCOLOUR16(pixel, pc);
1227     value = MAKECOLOUR(pc);
1228     LOUT24(out, value);
1229     }
1230 jsorg71 483 }
1231 jsorg71 311 }
1232     }
1233    
1234     static void
1235 jdmeijer 821 translate16to32(const uint16 * data, uint8 * out, uint8 * end)
1236 jsorg71 311 {
1237 jsorg71 472 uint16 pixel;
1238 jsorg71 483 uint32 value;
1239 jdmeijer 821 PixelColour pc;
1240 jsorg71 472
1241 astrand 1049 if (g_compatible_arch)
1242 jsorg71 472 {
1243 jdmeijer 821 /* *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 jsorg71 472 if (g_host_be)
1258     {
1259 jdmeijer 821 while (out < end)
1260     {
1261     pixel = *(data++);
1262     BSWAP16(pixel);
1263     SPLITCOLOUR16(pixel, pc);
1264     value = MAKECOLOUR(pc);
1265     BOUT32(out, value);
1266     }
1267 stargo 534 }
1268 jdmeijer 821 else
1269 jsorg71 472 {
1270 stargo 823 while (out < end)
1271 jdmeijer 821 {
1272     pixel = *(data++);
1273     SPLITCOLOUR16(pixel, pc);
1274     value = MAKECOLOUR(pc);
1275     BOUT32(out, value);
1276     }
1277 astrand 499 }
1278 jdmeijer 821 }
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 astrand 499 else
1293     {
1294 jdmeijer 821 while (out < end)
1295     {
1296     pixel = *(data++);
1297     SPLITCOLOUR16(pixel, pc);
1298     value = MAKECOLOUR(pc);
1299     LOUT32(out, value);
1300     }
1301 astrand 499 }
1302     }
1303 matty 28 }
1304    
1305 jsorg71 311 static void
1306 jdmeijer 821 translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1307 jsorg71 311 {
1308 jsorg71 316 uint32 pixel = 0;
1309 jsorg71 483 uint16 value;
1310 jdmeijer 821 PixelColour pc;
1311    
1312 jsorg71 311 while (out < end)
1313 jsorg71 316 {
1314     pixel = *(data++) << 16;
1315     pixel |= *(data++) << 8;
1316     pixel |= *(data++);
1317 jdmeijer 821 SPLITCOLOUR24(pixel, pc);
1318     value = MAKECOLOUR(pc);
1319 jsorg71 483 if (g_xserver_be)
1320     {
1321 jdmeijer 821 BOUT16(out, value);
1322 jsorg71 483 }
1323     else
1324     {
1325 jdmeijer 821 LOUT16(out, value);
1326 jsorg71 483 }
1327 jsorg71 316 }
1328 jsorg71 311 }
1329    
1330 jsorg71 316 static void
1331 jdmeijer 821 translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1332 jsorg71 316 {
1333 stargo 534 uint32 pixel;
1334     uint32 value;
1335 jdmeijer 821 PixelColour pc;
1336 stargo 534
1337 jdmeijer 821 if (g_xserver_be)
1338 jsorg71 316 {
1339 jdmeijer 821 while (out < end)
1340 stargo 534 {
1341 jdmeijer 821 pixel = *(data++) << 16;
1342     pixel |= *(data++) << 8;
1343     pixel |= *(data++);
1344     SPLITCOLOUR24(pixel, pc);
1345     value = MAKECOLOUR(pc);
1346     BOUT24(out, value);
1347 stargo 534 }
1348 jdmeijer 821 }
1349     else
1350     {
1351     while (out < end)
1352 stargo 534 {
1353 jdmeijer 821 pixel = *(data++) << 16;
1354     pixel |= *(data++) << 8;
1355     pixel |= *(data++);
1356     SPLITCOLOUR24(pixel, pc);
1357     value = MAKECOLOUR(pc);
1358     LOUT24(out, value);
1359 stargo 534 }
1360 jsorg71 316 }
1361     }
1362    
1363     static void
1364 jdmeijer 821 translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1365 jsorg71 316 {
1366 stargo 534 uint32 pixel;
1367     uint32 value;
1368 jdmeijer 821 PixelColour pc;
1369 stargo 534
1370 astrand 1049 if (g_compatible_arch)
1371 jsorg71 316 {
1372 jdmeijer 821 /* *INDENT-OFF* */
1373 stargo 822 #ifdef NEED_ALIGN
1374 jdmeijer 821 REPEAT4
1375     (
1376     *(out++) = *(data++);
1377     *(out++) = *(data++);
1378     *(out++) = *(data++);
1379     *(out++) = 0;
1380 stargo 822 )
1381 jdmeijer 821 #else
1382 stargo 822 REPEAT4
1383     (
1384 astrand 1041 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1385 astrand 1040 *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1386     out += 4;
1387     data += 3;
1388 stargo 822 )
1389 jdmeijer 821 #endif
1390     /* *INDENT-ON* */
1391     }
1392     else if (g_xserver_be)
1393     {
1394     while (out < end)
1395 jsorg71 472 {
1396 jdmeijer 821 pixel = *(data++) << 16;
1397     pixel |= *(data++) << 8;
1398     pixel |= *(data++);
1399     SPLITCOLOUR24(pixel, pc);
1400     value = MAKECOLOUR(pc);
1401     BOUT32(out, value);
1402 jsorg71 472 }
1403 jdmeijer 821 }
1404     else
1405     {
1406     while (out < end)
1407 jsorg71 472 {
1408 jdmeijer 821 pixel = *(data++) << 16;
1409     pixel |= *(data++) << 8;
1410     pixel |= *(data++);
1411     SPLITCOLOUR24(pixel, pc);
1412     value = MAKECOLOUR(pc);
1413     LOUT32(out, value);
1414 jsorg71 472 }
1415 jsorg71 316 }
1416     }
1417    
1418 matty 29 static uint8 *
1419 astrand 64 translate_image(int width, int height, uint8 * data)
1420 matty 28 {
1421 jsorg71 644 int size;
1422     uint8 *out;
1423     uint8 *end;
1424 matty 29
1425 astrand 1042 /*
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 jsorg71 1417
1434     /* todo */
1435     if (g_server_depth == 32 && g_depth == 24)
1436     {
1437     return data;
1438     }
1439    
1440 astrand 1042 if (g_no_translate_image)
1441 jsorg71 645 {
1442 astrand 1042 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 jsorg71 645 return data;
1446     }
1447 jsorg71 644
1448     size = width * height * (g_bpp / 8);
1449     out = (uint8 *) xmalloc(size);
1450     end = out + size;
1451    
1452 astrand 1042 switch (g_server_depth)
1453 jsorg71 311 {
1454 jsorg71 316 case 24:
1455 jsorg71 450 switch (g_bpp)
1456 jsorg71 316 {
1457     case 32:
1458 jsorg71 483 translate24to32(data, out, end);
1459 jsorg71 316 break;
1460     case 24:
1461     translate24to24(data, out, end);
1462     break;
1463     case 16:
1464 jsorg71 483 translate24to16(data, out, end);
1465 jsorg71 316 break;
1466     }
1467 matty 29 break;
1468     case 16:
1469 jsorg71 450 switch (g_bpp)
1470 jsorg71 316 {
1471     case 32:
1472 jsorg71 483 translate16to32((uint16 *) data, out, end);
1473 jsorg71 316 break;
1474     case 24:
1475     translate16to24((uint16 *) data, out, end);
1476     break;
1477     case 16:
1478 matthewc 528 translate16to16((uint16 *) data, out, end);
1479 jsorg71 316 break;
1480     }
1481 matty 29 break;
1482 jsorg71 316 case 15:
1483 jsorg71 450 switch (g_bpp)
1484 jsorg71 316 {
1485     case 32:
1486 jsorg71 483 translate15to32((uint16 *) data, out, end);
1487 jsorg71 316 break;
1488     case 24:
1489     translate15to24((uint16 *) data, out, end);
1490     break;
1491     case 16:
1492 jsorg71 483 translate15to16((uint16 *) data, out, end);
1493 jsorg71 316 break;
1494     }
1495 matty 29 break;
1496 jsorg71 316 case 8:
1497 jsorg71 450 switch (g_bpp)
1498 jsorg71 316 {
1499     case 8:
1500     translate8to8(data, out, end);
1501     break;
1502     case 16:
1503 stargo 521 translate8to16(data, out, end);
1504 jsorg71 316 break;
1505     case 24:
1506     translate8to24(data, out, end);
1507     break;
1508     case 32:
1509 stargo 521 translate8to32(data, out, end);
1510 jsorg71 316 break;
1511     }
1512 matty 29 break;
1513     }
1514     return out;
1515 matty 28 }
1516    
1517 astrand 1407 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 jsorg71 1372 RD_BOOL
1534 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
1535 astrand 102 {
1536 matthewc 203 int modifierpos, key, keysymMask = 0;
1537 astrand 102 int offset;
1538    
1539 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1540 astrand 102
1541     if (keycode == NoSymbol)
1542     return False;
1543    
1544     for (modifierpos = 0; modifierpos < 8; modifierpos++)
1545     {
1546 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
1547 astrand 102
1548 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
1549 astrand 102 {
1550 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
1551 matthewc 203 keysymMask |= 1 << modifierpos;
1552 astrand 102 }
1553     }
1554    
1555 matthewc 203 return (state & keysymMask) ? True : False;
1556 astrand 102 }
1557    
1558 matthewc 527 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 astrand 1042 /* 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 jsorg71 81 {
1572 astrand 1042 unsigned weight = 0;
1573     do
1574     {
1575     weight += (mask & 1);
1576     }
1577     while (mask >>= 1);
1578     return weight;
1579     }
1580    
1581 jsorg71 1372 static RD_BOOL
1582 stargo 1246 select_visual(int screen_num)
1583 astrand 1042 {
1584 matthewc 121 XPixmapFormatValues *pfm;
1585 astrand 1042 int pixmap_formats_count, visuals_count;
1586 stargo 565 XVisualInfo *vmatches = NULL;
1587     XVisualInfo template;
1588 astrand 1042 int i;
1589     unsigned red_weight, blue_weight, green_weight;
1590 matthewc 121
1591 astrand 1042 red_weight = blue_weight = green_weight = 0;
1592    
1593 astrand 1226 if (g_server_depth == -1)
1594     {
1595     g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1596     }
1597    
1598 astrand 1042 pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1599     if (pfm == NULL)
1600 jsorg71 81 {
1601 astrand 1042 error("Unable to get list of pixmap formats from display.\n");
1602     XCloseDisplay(g_display);
1603 jsorg71 81 return False;
1604     }
1605 matthewc 121
1606 astrand 1042 /* Search for best TrueColor visual */
1607 stargo 565 template.class = TrueColor;
1608 stargo 1246 template.screen = screen_num;
1609 astrand 1250 vmatches =
1610     XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1611     &visuals_count);
1612 astrand 1042 g_visual = NULL;
1613     g_no_translate_image = False;
1614 astrand 1049 g_compatible_arch = False;
1615 astrand 1042 if (vmatches != NULL)
1616 matthewc 527 {
1617 astrand 1042 for (i = 0; i < visuals_count; ++i)
1618 stargo 565 {
1619 astrand 1042 XVisualInfo *visual_info = &vmatches[i];
1620 jsorg71 1372 RD_BOOL can_translate_to_bpp = False;
1621 astrand 1223 int j;
1622 stargo 565
1623 astrand 1042 /* 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 astrand 1049 g_compatible_arch = !g_host_be;
1644 astrand 1042 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 astrand 1049 g_compatible_arch = False;
1652 astrand 1042 }
1653 jsorg71 644
1654 astrand 1042 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 stargo 565
1663 astrand 1042 /* 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 stargo 565 }
1702 astrand 1042 XFree(vmatches);
1703 matthewc 527 }
1704 astrand 1042
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 matthewc 527 else
1713     {
1714 astrand 1042 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 matthewc 527 {
1723 astrand 1042 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1724     XCloseDisplay(g_display);
1725     XFree(pfm);
1726 matthewc 527 return False;
1727     }
1728    
1729 astrand 1042 /* 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 jsorg71 644
1735 astrand 1042 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 jdmeijer 821 {
1741 astrand 1042 g_bpp = pf->bits_per_pixel;
1742    
1743     if (g_no_translate_image)
1744 jdmeijer 821 {
1745 astrand 1042 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 jdmeijer 821 }
1764    
1765 astrand 1042 /* 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;
1769 jdmeijer 821 }
1770 matthewc 527 }
1771 astrand 1042 XFree(pfm);
1772     pfm = NULL;
1773     return True;
1774     }
1775 matthewc 527
1776 astrand 1199 static XErrorHandler g_old_error_handler;
1777 astrand 1459 static RD_BOOL g_error_expected = False;
1778 astrand 1199
1779 astrand 1459 /* 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     XFree(name);
1798     }
1799    
1800     return sts;
1801     }
1802    
1803 astrand 1199 static int
1804     error_handler(Display * dpy, XErrorEvent * eev)
1805     {
1806 astrand 1459 if (g_error_expected)
1807 astrand 1199 return 0;
1808    
1809     return g_old_error_handler(dpy, eev);
1810     }
1811    
1812 jsorg71 1372 RD_BOOL
1813 astrand 1042 ui_init(void)
1814     {
1815     int screen_num;
1816    
1817     g_display = XOpenDisplay(NULL);
1818     if (g_display == NULL)
1819 matthewc 121 {
1820 astrand 1042 error("Failed to open display: %s\n", XDisplayName(NULL));
1821     return False;
1822 matthewc 121 }
1823    
1824     {
1825 astrand 1042 uint16 endianess_test = 1;
1826 jsorg71 1372 g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1827 astrand 1042 }
1828    
1829 astrand 1199 g_old_error_handler = XSetErrorHandler(error_handler);
1830 astrand 1042 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 stargo 1246 if (!select_visual(screen_num))
1837 matthewc 121 return False;
1838 astrand 1042
1839     if (g_no_translate_image)
1840     {
1841     DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1842 matthewc 121 }
1843    
1844 astrand 1042 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 matthewc 517 if (!g_owncolmap)
1854 n-ki 279 {
1855 astrand 580 g_xcolmap =
1856     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1857     AllocNone);
1858 jsorg71 450 if (g_depth <= 8)
1859 astrand 1042 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1860 n-ki 279 }
1861    
1862 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1863     {
1864 astrand 1042 warning("External BackingStore not available. Using internal.\n");
1865 jsorg71 450 g_ownbackstore = True;
1866 stargo 609 }
1867 matthewc 121
1868 astrand 500 /*
1869     * Determine desktop size
1870     */
1871 astrand 547 if (g_fullscreen)
1872 astrand 263 {
1873 astrand 547 g_width = WidthOfScreen(g_screen);
1874     g_height = HeightOfScreen(g_screen);
1875 astrand 1057 g_using_full_workarea = True;
1876 astrand 547 }
1877     else if (g_width < 0)
1878     {
1879 astrand 500 /* Percent of screen */
1880 astrand 991 if (-g_width >= 100)
1881     g_using_full_workarea = True;
1882 astrand 500 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 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1888 matthewc 300 uint32 x, y, cx, cy;
1889     if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1890 astrand 263 {
1891 jsorg71 447 g_width = cx;
1892     g_height = cy;
1893 astrand 1057 g_using_full_workarea = True;
1894 matthewc 300 }
1895     else
1896     {
1897 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1898 astrand 1057 g_width = WidthOfScreen(g_screen);
1899     g_height = HeightOfScreen(g_screen);
1900 astrand 263 }
1901     }
1902 matthewc 121
1903 matthewc 160 /* make sure width is a multiple of 4 */
1904 jsorg71 447 g_width = (g_width + 3) & ~3;
1905 matthewc 160
1906 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1907 astrand 1407 xwin_refresh_pointer_map();
1908 matthewc 203
1909 astrand 498 xkeymap_init();
1910    
1911 jsorg71 447 if (g_enable_compose)
1912 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1913 matthewc 188
1914 matthewc 432 xclip_init();
1915 astrand 1199 ewmh_init();
1916     if (g_seamless_rdp)
1917 astrand 1459 {
1918     seamless_restack_test();
1919 astrand 1199 seamless_init();
1920 astrand 1459 }
1921 jsorg71 316
1922 astrand 1042 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1923 jsorg71 316
1924 jsorg71 81 return True;
1925     }
1926 astrand 66
1927 matthewc 188 void
1928 matthewc 192 ui_deinit(void)
1929 matthewc 188 {
1930 astrand 1199 while (g_seamless_windows)
1931     {
1932     XDestroyWindow(g_display, g_seamless_windows->wnd);
1933     sw_remove_window(g_seamless_windows);
1934     }
1935    
1936 ossman_ 1214 xclip_deinit();
1937    
1938 jsorg71 450 if (g_IM != NULL)
1939     XCloseIM(g_IM);
1940 astrand 580
1941 stargo 576 if (g_null_cursor != NULL)
1942     ui_destroy_cursor(g_null_cursor);
1943 matthewc 188
1944 jsorg71 450 XFreeModifiermap(g_mod_map);
1945 matthewc 203
1946 jsorg71 450 if (g_ownbackstore)
1947     XFreePixmap(g_display, g_backstore);
1948 matthewc 188
1949 jsorg71 450 XFreeGC(g_display, g_gc);
1950     XCloseDisplay(g_display);
1951     g_display = NULL;
1952 matthewc 188 }
1953    
1954 astrand 1199
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 void
1967     get_input_mask(long *input_mask)
1968     {
1969     *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1970     VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1971    
1972     if (g_sendmotion)
1973     *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 jsorg71 1372 RD_BOOL
1983 matthewc 192 ui_create_window(void)
1984 matty 6 {
1985 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1986 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1987    
1988 matthewc 121 XSetWindowAttributes attribs;
1989 matty 28 XClassHint *classhints;
1990     XSizeHints *sizehints;
1991 matthewc 188 int wndwidth, wndheight;
1992 matthewc 432 long input_mask, ic_input_mask;
1993 jsorg71 100 XEvent xevent;
1994    
1995 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1996     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1997 matthewc 188
1998 stargo 867 /* 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 astrand 1199 get_window_attribs(&attribs);
2005 matthewc 188
2006 astrand 801 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 jsorg71 100
2011 stargo 576 if (g_gc == NULL)
2012 astrand 1199 {
2013 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2014 astrand 1199 ui_reset_clip();
2015     }
2016 stargo 565
2017 jsorg71 725 if (g_create_bitmap_gc == NULL)
2018     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
2019    
2020 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
2021 stargo 565 {
2022 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
2023 stargo 565
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 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
2030 astrand 1380 ewmh_set_wm_name(g_wnd, g_title);
2031 jsorg71 100
2032 jsorg71 450 if (g_hide_decorations)
2033 astrand 1199 mwm_hide_decorations(g_wnd);
2034 astrand 262
2035 jsorg71 100 classhints = XAllocClassHint();
2036     if (classhints != NULL)
2037     {
2038     classhints->res_name = classhints->res_class = "rdesktop";
2039 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
2040 jsorg71 100 XFree(classhints);
2041     }
2042    
2043     sizehints = XAllocSizeHints();
2044     if (sizehints)
2045     {
2046     sizehints->flags = PMinSize | PMaxSize;
2047 stargo 867 if (g_pos)
2048     sizehints->flags |= PPosition;
2049 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
2050     sizehints->min_height = sizehints->max_height = g_height;
2051 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
2052 jsorg71 100 XFree(sizehints);
2053     }
2054    
2055 astrand 651 if (g_embed_wnd)
2056     {
2057     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
2058     }
2059 stargo 636
2060 astrand 1199 get_input_mask(&input_mask);
2061 matthewc 121
2062 jsorg71 450 if (g_IM != NULL)
2063 matthewc 188 {
2064 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
2065 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
2066 matthewc 188
2067 jsorg71 450 if ((g_IC != NULL)
2068     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
2069 matthewc 188 input_mask |= ic_input_mask;
2070     }
2071    
2072 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
2073     XMapWindow(g_display, g_wnd);
2074 jsorg71 100
2075 matthewc 208 /* wait for VisibilityNotify */
2076 astrand 196 do
2077     {
2078 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
2079 astrand 196 }
2080 matthewc 208 while (xevent.type != VisibilityNotify);
2081 jsorg71 688 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
2082 matthewc 123
2083 jsorg71 447 g_focused = False;
2084     g_mouse_in_wnd = False;
2085 jsorg71 257
2086 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
2087 jsorg71 450 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 astrand 275
2091 astrand 508 /* create invisible 1x1 cursor to be used as null cursor */
2092 stargo 576 if (g_null_cursor == NULL)
2093     g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
2094 astrand 508
2095 matty 10 return True;
2096 matty 6 }
2097    
2098 matty 25 void
2099 n-ki 677 ui_resize_window()
2100     {
2101     XSizeHints *sizehints;
2102 jsorg71 708 Pixmap bs;
2103 n-ki 677
2104     sizehints = XAllocSizeHints();
2105     if (sizehints)
2106     {
2107     sizehints->flags = PMinSize | PMaxSize;
2108     sizehints->min_width = sizehints->max_width = g_width;
2109     sizehints->min_height = sizehints->max_height = g_height;
2110     XSetWMNormalHints(g_display, g_wnd, sizehints);
2111     XFree(sizehints);
2112     }
2113    
2114     if (!(g_fullscreen || g_embed_wnd))
2115     {
2116     XResizeWindow(g_display, g_wnd, g_width, g_height);
2117     }
2118 jsorg71 708
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 n-ki 677 }
2130    
2131     void
2132 matthewc 192 ui_destroy_window(void)
2133 matty 6 {
2134 jsorg71 450 if (g_IC != NULL)
2135     XDestroyIC(g_IC);
2136 matty 31
2137 jsorg71 450 XDestroyWindow(g_display, g_wnd);
2138 matty 6 }
2139    
2140 jsorg71 100 void
2141 matthewc 192 xwin_toggle_fullscreen(void)
2142 jsorg71 100 {
2143 matthewc 188 Pixmap contents = 0;
2144 matthewc 123
2145 astrand 1199 if (g_seamless_active)
2146     /* Turn off SeamlessRDP mode */
2147     ui_seamless_toggle();
2148    
2149 jsorg71 450 if (!g_ownbackstore)
2150 matthewc 188 {
2151     /* need to save contents of window */
2152 jsorg71 450 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 matthewc 188 }
2155    
2156     ui_destroy_window();
2157 jsorg71 447 g_fullscreen = !g_fullscreen;
2158 matthewc 188 ui_create_window();
2159 matthewc 123
2160 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
2161 matthewc 188
2162 jsorg71 450 if (!g_ownbackstore)
2163 matthewc 188 {
2164 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
2165     XFreePixmap(g_display, contents);
2166 matthewc 188 }
2167 jsorg71 100 }
2168    
2169 astrand 988 static void
2170 jsorg71 1372 handle_button_event(XEvent xevent, RD_BOOL down)
2171 astrand 988 {
2172     uint16 button, flags = 0;
2173     g_last_gesturetime = xevent.xbutton.time;
2174 astrand 1407 /* 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 astrand 988 button = xkeymap_translate_button(xevent.xbutton.button);
2181     if (button == 0)
2182     return;
2183    
2184     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 astrand 991 if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
2233 astrand 988 {
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 astrand 1199 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 astrand 988 }
2255    
2256 astrand 1199
2257 stargo 887 /* Process events in Xlib queue
2258 astrand 275 Returns 0 after user quit, 1 otherwise */
2259     static int
2260 matthewc 192 xwin_process_events(void)
2261 matty 9 {
2262 n-ki 54 XEvent xevent;
2263 matthewc 38 KeySym keysym;
2264 matty 10 uint32 ev_time;
2265 astrand 66 char str[256];
2266     Status status;
2267 stargo 887 int events = 0;
2268 astrand 1199 seamless_window *sw;
2269 matty 9
2270 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
2271 matty 9 {
2272 jsorg71 450 XNextEvent(g_display, &xevent);
2273 matthewc 123
2274 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
2275 astrand 66 {
2276 astrand 84 DEBUG_KBD(("Filtering event\n"));
2277 astrand 66 continue;
2278     }
2279    
2280 n-ki 54 switch (xevent.type)
2281 matty 9 {
2282 jsorg71 688 case VisibilityNotify:
2283 astrand 1199 if (xevent.xvisibility.window == g_wnd)
2284     g_Unobscured =
2285     xevent.xvisibility.state == VisibilityUnobscured;
2286    
2287 jsorg71 688 break;
2288 astrand 275 case ClientMessage:
2289     /* the window manager told us to quit */
2290 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
2291     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
2292 astrand 1447 {
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 astrand 275 break;
2303    
2304 matty 9 case KeyPress:
2305 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
2306     if (g_IC != NULL)
2307 astrand 66 /* Multi_key compatible version */
2308     {
2309 jsorg71 450 XmbLookupString(g_IC,
2310 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
2311     &status);
2312 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
2313 astrand 66 {
2314 astrand 82 error("XmbLookupString failed with status 0x%x\n",
2315     status);
2316 astrand 66 break;
2317     }
2318     }
2319     else
2320     {
2321     /* Plain old XLookupString */
2322 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
2323 astrand 66 XLookupString((XKeyEvent *) & xevent,
2324 astrand 82 str, sizeof(str), &keysym, NULL);
2325 astrand 66 }
2326    
2327 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2328 astrand 261 get_ksname(keysym)));
2329 astrand 66
2330 matthewc 203 ev_time = time(NULL);
2331     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2332 astrand 118 break;
2333    
2334 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2335 astrand 976 ev_time, True, 0);
2336 astrand 66 break;
2337 matthewc 203
2338 astrand 66 case KeyRelease:
2339 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
2340 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
2341     sizeof(str), &keysym, NULL);
2342 n-ki 52
2343 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2344 matthewc 203 get_ksname(keysym)));
2345 n-ki 52
2346 matthewc 203 ev_time = time(NULL);
2347     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2348 astrand 118 break;
2349    
2350 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2351 astrand 976 ev_time, False, 0);
2352 matty 9 break;
2353    
2354     case ButtonPress:
2355 astrand 988 handle_button_event(xevent, True);
2356     break;
2357 matty 9
2358     case ButtonRelease:
2359 astrand 988 handle_button_event(xevent, False);
2360 matty 10 break;
2361    
2362     case MotionNotify:
2363 jsorg71 450 if (g_moving_wnd)
2364 astrand 342 {
2365 jsorg71 450 XMoveWindow(g_display, g_wnd,
2366     xevent.xmotion.x_root - g_move_x_offset,
2367     xevent.xmotion.y_root - g_move_y_offset);
2368 astrand 342 break;
2369     }
2370    
2371 jsorg71 447 if (g_fullscreen && !g_focused)
2372 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2373 jsorg71 288 CurrentTime);
2374 astrand 1199
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 matty 28 break;
2388    
2389 matthewc 194 case FocusIn:
2390 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
2391     break;
2392 jsorg71 447 g_focused = True;
2393 astrand 543 reset_modifier_keys();
2394 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
2395     XGrabKeyboard(g_display, g_wnd, True,
2396 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
2397 astrand 1199
2398     sw = sw_get_window_by_wnd(xevent.xfocus.window);
2399     if (!sw)
2400     break;
2401    
2402 astrand 1459 /* Menu windows are real X11 windows,
2403     with focus. When such a window is
2404     destroyed, focus is reverted to the
2405     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 astrand 1199 if (sw->id != g_seamless_focused)
2416     {
2417 astrand 1459
2418     if (sw_window_exists(g_seamless_focused))
2419     seamless_send_focus(sw->id, 0);
2420 astrand 1199 g_seamless_focused = sw->id;
2421     }
2422 matty 28 break;
2423    
2424 matthewc 194 case FocusOut:
2425 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
2426     break;
2427 jsorg71 447 g_focused = False;
2428 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
2429 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2430 matty 28 break;
2431 matty 31
2432 matthewc 250 case EnterNotify:
2433     /* we only register for this event when in fullscreen mode */
2434 jsorg71 257 /* or grab_keyboard */
2435 jsorg71 447 g_mouse_in_wnd = True;
2436     if (g_fullscreen)
2437 jsorg71 257 {
2438 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2439 astrand 261 CurrentTime);
2440 jsorg71 257 break;
2441     }
2442 jsorg71 447 if (g_focused)
2443 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
2444 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
2445 matthewc 250 break;
2446    
2447 matthewc 253 case LeaveNotify:
2448 jsorg71 257 /* we only register for this event when grab_keyboard */
2449 jsorg71 447 g_mouse_in_wnd = False;
2450 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2451 matthewc 253 break;
2452    
2453 matty 31 case Expose:
2454 astrand 1199 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 matty 31 break;
2477 astrand 119
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 matthewc 203
2485     if (xevent.xmapping.request == MappingModifier)
2486     {
2487 jsorg71 450 XFreeModifiermap(g_mod_map);
2488     g_mod_map = XGetModifierMapping(g_display);
2489 matthewc 203 }
2490 astrand 1407
2491     if (xevent.xmapping.request == MappingPointer)
2492     {
2493     xwin_refresh_pointer_map();
2494     }
2495    
2496 astrand 119 break;
2497 matthewc 432
2498 astrand 435 /* clipboard stuff */
2499 forsberg 415 case SelectionNotify:
2500 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
2501 forsberg 415 break;
2502     case SelectionRequest:
2503 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2504 forsberg 415 break;
2505 matthewc 432 case SelectionClear:
2506     xclip_handle_SelectionClear();
2507     break;
2508 forsberg 415 case PropertyNotify:
2509 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
2510 astrand 1199 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 forsberg 415 break;
2535 jdmeijer 905 case MapNotify:
2536 astrand 1199 if (!g_seamless_active)
2537     rdp_send_client_window_status(1);
2538 jdmeijer 905 break;
2539     case UnmapNotify:
2540 astrand 1199 if (!g_seamless_active)
2541     rdp_send_client_window_status(0);
2542 jdmeijer 905 break;
2543 astrand 1199 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 matty 9 }
2567     }
2568 astrand 275 /* Keep going */
2569     return 1;
2570 matty 9 }
2571    
2572 astrand 275 /* Returns 0 after user quit, 1 otherwise */
2573     int
2574 matty 33 ui_select(int rdp_socket)
2575     {
2576 stargo 606 int n;
2577 matthewc 474 fd_set rfds, wfds;
2578 n-ki 592 struct timeval tv;
2579 jsorg71 1372 RD_BOOL s_timeout = False;
2580 matty 33
2581     while (True)
2582     {
2583 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2584 matthewc 121 /* Process any events already waiting */
2585 astrand 275 if (!xwin_process_events())
2586     /* User quit */
2587     return 0;
2588 astrand 119
2589 astrand 1199 if (g_seamless_active)
2590     sw_check_timers();
2591    
2592 matty 33 FD_ZERO(&rfds);
2593 matthewc 474 FD_ZERO(&wfds);
2594 matty 33 FD_SET(rdp_socket, &rfds);
2595 jsorg71 450 FD_SET(g_x_socket, &rfds);
2596 matty 33
2597 n-ki 592 /* default timeout */
2598     tv.tv_sec = 60;
2599     tv.tv_usec = 0;
2600 matthewc 474
2601 ossman_ 1302 #ifdef WITH_RDPSND
2602     rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2603     #endif
2604    
2605 n-ki 592 /* add redirection handles */
2606     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2607 astrand 1199 seamless_select_timeout(&tv);
2608 n-ki 592
2609     n++;
2610    
2611     switch (select(n, &rfds, &wfds, NULL, &tv))
2612 matthewc 474 {
2613 matty 33 case -1:
2614     error("select: %s\n", strerror(errno));
2615    
2616     case 0:
2617 ossman_ 1302 #ifdef WITH_RDPSND
2618     rdpsnd_check_fds(&rfds, &wfds);
2619     #endif
2620    
2621 stargo 795 /* Abort serial read calls */
2622     if (s_timeout)
2623 jsorg71 1372 rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2624 matty 33 continue;
2625     }
2626    
2627 ossman_ 1302 #ifdef WITH_RDPSND
2628     rdpsnd_check_fds(&rfds, &wfds);
2629     #endif
2630    
2631 jsorg71 1372 rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2632 n-ki 592
2633 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2634     return 1;
2635    
2636 matty 33 }
2637     }
2638    
2639     void
2640 matty 25 ui_move_pointer(int x, int y)
2641 matty 9 {
2642 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2643 matty 9 }
2644    
2645 jsorg71 1364 RD_HBITMAP
2646 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2647 matty 6 {
2648     XImage *image;
2649 matty 9 Pixmap bitmap;
2650 matty 28 uint8 *tdata;
2651 stargo 521 int bitmap_pad;
2652 matty 29
2653 astrand 1042 if (g_server_depth == 8)
2654 stargo 521 {
2655     bitmap_pad = 8;
2656     }
2657     else
2658     {
2659     bitmap_pad = g_bpp;
2660    
2661     if (g_bpp == 24)
2662     bitmap_pad = 32;
2663     }
2664    
2665 jsorg71 450 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 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2669 matty 6
2670 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2671 matty 9
2672     XFree(image);
2673 jsorg71 644 if (tdata != data)
2674 n-ki 279 xfree(tdata);
2675 jsorg71 1364 return (RD_HBITMAP) bitmap;
2676 matty 6 }
2677    
2678 matty 25 void
2679 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2680 matty 6 {
2681 matty 10 XImage *image;
2682 matty 29 uint8 *tdata;
2683 stargo 521 int bitmap_pad;
2684    
2685 astrand 1042 if (g_server_depth == 8)
2686 stargo 521 {
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 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2698     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2699 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2700 matty 28
2701 jsorg71 450 if (g_ownbackstore)
2702 matty 31 {
2703 jsorg71 450 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 astrand 1199 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 matty 31 }
2709     else
2710     {
2711 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2712 astrand 1199 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 matty 31 }
2716 matty 29
2717 matty 24 XFree(image);
2718 jsorg71 644 if (tdata != data)
2719 n-ki 279 xfree(tdata);
2720 matty 6 }
2721    
2722 matty 25 void
2723 jsorg71 1364 ui_destroy_bitmap(RD_HBITMAP bmp)
2724 matty 6 {
2725 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2726 matty 10 }
2727    
2728 jsorg71 1364 RD_HGLYPH
2729 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2730 matty 10 {
2731 matty 9 XImage *image;
2732     Pixmap bitmap;
2733     int scanline;
2734 matty 6
2735 matty 9 scanline = (width + 7) / 8;
2736 matty 6
2737 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2738 jsorg71 725 if (g_create_glyph_gc == 0)
2739     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2740 matty 9
2741 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2742 astrand 73 width, height, 8, scanline);
2743 matty 23 image->byte_order = MSBFirst;
2744     image->bitmap_bit_order = MSBFirst;
2745     XInitImage(image);
2746    
2747 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2748 matty 29
2749 matty 9 XFree(image);
2750 jsorg71 1364 return (RD_HGLYPH) bitmap;
2751 matty 6 }
2752 matty 7
2753 matty 25 void
2754 jsorg71 1364 ui_destroy_glyph(RD_HGLYPH glyph)
2755 matty 7 {
2756 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2757 matty 9 }
2758    
2759 jsorg71 1364 RD_HCURSOR
2760 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2761     uint8 * andmask, uint8 * xormask)
2762 matty 9 {
2763 jsorg71 1364 RD_HGLYPH maskglyph, cursorglyph;
2764 matty 29 XColor bg, fg;
2765     Cursor xcursor;
2766     uint8 *cursor, *pcursor;
2767     uint8 *mask, *pmask;
2768     uint8 nextbit;
2769     int scanline, offset;
2770     int i, j;
2771    
2772     scanline = (width + 7) / 8;
2773     offset = scanline * height;
2774    
2775 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2776 matty 29 memset(cursor, 0, offset);
2777    
2778 forsberg 415 mask = (uint8 *) xmalloc(offset);
2779 matty 29 memset(mask, 0, offset);
2780    
2781     /* approximate AND and XOR masks with a monochrome X pointer */
2782     for (i = 0; i < height; i++)
2783 matty 7 {
2784 matty 29 offset -= scanline;
2785     pcursor = &cursor[offset];
2786     pmask = &mask[offset];
2787    
2788     for (j = 0; j < scanline; j++)
2789 matty 28 {
2790 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2791     {
2792     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 matty 28 }
2810 matty 7 }
2811 matty 29
2812     fg.red = fg.blue = fg.green = 0xffff;
2813     bg.red = bg.blue = bg.green = 0x0000;
2814     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2815    
2816     cursorglyph = ui_create_glyph(width, height, cursor);
2817     maskglyph = ui_create_glyph(width, height, mask);
2818    
2819 astrand 66 xcursor =
2820 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2821 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2822 astrand 64
2823 matty 29 ui_destroy_glyph(maskglyph);
2824     ui_destroy_glyph(cursorglyph);
2825     xfree(mask);
2826     xfree(cursor);
2827 jsorg71 1364 return (RD_HCURSOR) xcursor;
2828 matty 29 }
2829    
2830     void
2831 jsorg71 1364 ui_set_cursor(RD_HCURSOR cursor)
2832 matty 29 {
2833 jsorg71 450 g_current_cursor = (Cursor) cursor;
2834     XDefineCursor(g_display, g_wnd, g_current_cursor);
2835 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2836 matty 29 }
2837    
2838     void
2839 jsorg71 1364 ui_destroy_cursor(RD_HCURSOR cursor)
2840 matty 29 {
2841 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2842 matty 29 }
2843    
2844 astrand 508 void
2845     ui_set_null_cursor(void)
2846     {
2847     ui_set_cursor(g_null_cursor);
2848     }
2849    
2850 matty 29 #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 n-ki 279
2857 jsorg71 1364 RD_HCOLOURMAP
2858 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2859 matty 29 {
2860     COLOURENTRY *entry;
2861     int i, ncolours = colours->ncolours;
2862 jsorg71 450 if (!g_owncolmap)
2863 matty 28 {
2864 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2865 n-ki 279 XColor xentry;
2866     XColor xc_cache[256];
2867     uint32 colour;
2868     int colLookup = 256;
2869     for (i = 0; i < ncolours; i++)
2870 matty 28 {
2871 n-ki 279 entry = &colours->colours[i];
2872     MAKE_XCOLOR(&xentry, entry);
2873 matty 7
2874 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2875 astrand 196 {
2876 n-ki 279 /* Allocation failed, find closest match. */
2877     int j = 256;
2878     int nMinDist = 3 * 256 * 256;
2879     long nDist = nMinDist;
2880 matty 28
2881 n-ki 279 /* only get the colors once */
2882     while (colLookup--)
2883 astrand 196 {
2884 n-ki 279 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 jsorg71 450 XQueryColor(g_display,
2889     DefaultColormap(g_display,
2890     DefaultScreen(g_display)),
2891 n-ki 279 &xc_cache[colLookup]);
2892 n-ki 185 }
2893 n-ki 279 colLookup = 0;
2894    
2895     /* approximate the pixel */
2896     while (j--)
2897 astrand 196 {
2898 n-ki 279 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 n-ki 185 }
2919     }
2920 n-ki 279 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 matthewc 527 map[i] = colour;
2932 n-ki 185 }
2933 n-ki 279 return map;
2934     }
2935     else
2936     {
2937     XColor *xcolours, *xentry;
2938     Colormap map;
2939 matty 29
2940 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2941 n-ki 279 for (i = 0; i < ncolours; i++)
2942 astrand 196 {
2943 n-ki 279 entry = &colours->colours[i];
2944     xentry = &xcolours[i];
2945     xentry->pixel = i;
2946     MAKE_XCOLOR(xentry, entry);
2947 matty 29 }
2948    
2949 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2950     XStoreColors(g_display, map, xcolours, ncolours);
2951 n-ki 185
2952 n-ki 279 xfree(xcolours);
2953 jsorg71 1364 return (RD_HCOLOURMAP) map;
2954 matty 29 }
2955 matty 7 }
2956    
2957 matty 25 void
2958 jsorg71 1364 ui_destroy_colourmap(RD_HCOLOURMAP map)
2959 matty 7 {
2960 jsorg71 450 if (!g_owncolmap)
2961 n-ki 279 xfree(map);
2962     else
2963 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2964 matty 7 }
2965    
2966 matty 25 void
2967 jsorg71 1364 ui_set_colourmap(RD_HCOLOURMAP map)
2968 matty 7 {
2969 jsorg71 450 if (!g_owncolmap)
2970 astrand 448 {
2971 jsorg71 450 if (g_colmap)
2972     xfree(g_colmap);
2973 astrand 448
2974 jsorg71 450 g_colmap = (uint32 *) map;
2975 astrand 448 }
2976 n-ki 279 else
2977 astrand 1199 {
2978 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2979 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2980     }
2981 matty 7 }
2982    
2983 matty 25 void
2984     ui_set_clip(int x, int y, int cx, int cy)
2985 matty 7 {
2986 astrand 1199 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 matty 9 }
2992 matty 7
2993 matty 25 void
2994 matthewc 192 ui_reset_clip(void)
2995 matty 9 {
2996 astrand 1199 g_clip_rectangle.x = 0;
2997     g_clip_rectangle.y = 0;
2998     g_clip_rectangle.width = g_width;
2999     g_clip_rectangle.height = g_height;
3000     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
3001 matty 7 }
3002    
3003 matty 25 void
3004 matthewc 192 ui_bell(void)
3005 matty 10 {
3006 jsorg71 450 XBell(g_display, 0);
3007 matty 10 }
3008    
3009 matty 25 void
3010     ui_destblt(uint8 opcode,
3011     /* dest */ int x, int y, int cx, int cy)
3012 matty 9 {
3013 matty 29 SET_FUNCTION(opcode);
3014 matty 31 FILL_RECTANGLE(x, y, cx, cy);
3015 matty 29 RESET_FUNCTION(opcode);
3016 matty 9 }
3017    
3018 jsorg71 373 static uint8 hatch_patterns[] = {
3019 forsberg 415 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 jsorg71 373 };
3026    
3027 matty 25 void
3028     ui_patblt(uint8 opcode,
3029     /* dest */ int x, int y, int cx, int cy,
3030 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3031 matty 9 {
3032     Pixmap fill;
3033 jsorg71 59 uint8 i, ipattern[8];
3034 matty 9
3035 matty 29 SET_FUNCTION(opcode);
3036 matty 9
3037     switch (brush->style)
3038     {
3039 matty 24 case 0: /* Solid */
3040 matty 29 SET_FOREGROUND(fgcolour);
3041 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3042 matty 9 break;
3043    
3044 jsorg71 373 case 2: /* Hatch */
3045 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
3046     hatch_patterns + brush->pattern[0] * 8);
3047 astrand 487 SET_FOREGROUND(fgcolour);
3048     SET_BACKGROUND(bgcolour);
3049 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3050     XSetStipple(g_display, g_gc, fill);
3051     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3052 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3053 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3054     XSetTSOrigin(g_display, g_gc, 0, 0);
3055 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3056 jsorg71 373 break;
3057    
3058 matty 24 case 3: /* Pattern */
3059 jsorg71 59 for (i = 0; i != 8; i++)
3060     ipattern[7 - i] = brush->pattern[i];
3061     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
3062 matty 29 SET_FOREGROUND(bgcolour);
3063     SET_BACKGROUND(fgcolour);
3064 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
3065     XSetStipple(g_display, g_gc, fill);
3066     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
3067 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3068 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3069     XSetTSOrigin(g_display, g_gc, 0, 0);
3070 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3071 matty 9 break;
3072    
3073     default:
3074 matty 30 unimpl("brush %d\n", brush->style);
3075 matty 9 }
3076 matty 29
3077     RESET_FUNCTION(opcode);
3078 jsorg71 680
3079     if (g_ownbackstore)
3080     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3081 astrand 1199 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 matty 9 }
3085    
3086 matty 25 void
3087     ui_screenblt(uint8 opcode,
3088     /* dest */ int x, int y, int cx, int cy,
3089     /* src */ int srcx, int srcy)
3090 matty 9 {
3091 matty 29 SET_FUNCTION(opcode);
3092 jsorg71 450 if (g_ownbackstore)
3093 stargo 609 {
3094 astrand 1199 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 stargo 609 }
3098     else
3099     {
3100     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3101     }
3102 astrand 1199
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 matty 29 RESET_FUNCTION(opcode);
3108 matty 9 }
3109    
3110 matty 25 void
3111     ui_memblt(uint8 opcode,
3112     /* dest */ int x, int y, int cx, int cy,
3113 jsorg71 1364 /* src */ RD_HBITMAP src, int srcx, int srcy)
3114 matty 9 {
3115 matty 29 SET_FUNCTION(opcode);
3116 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
3117 astrand 1199 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 jsorg71 450 if (g_ownbackstore)
3121     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
3122 matty 29 RESET_FUNCTION(opcode);
3123 matty 9 }
3124    
3125 matty 25 void
3126     ui_triblt(uint8 opcode,
3127     /* dest */ int x, int y, int cx, int cy,
3128 jsorg71 1364 /* src */ RD_HBITMAP src, int srcx, int srcy,
3129 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3130 matty 9 {
3131     /* This is potentially difficult to do in general. Until someone
3132 matty 10 comes up with a more efficient way of doing it I am using cases. */
3133 matty 9
3134     switch (opcode)
3135     {
3136 matty 24 case 0x69: /* PDSxxn */
3137 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
3138 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
3139 matty 16 break;
3140    
3141 matty 24 case 0xb8: /* PSDPxax */
3142 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
3143 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
3144 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
3145 matty 9 break;
3146    
3147 matty 29 case 0xc0: /* PSa */
3148 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
3149 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
3150 matty 28 break;
3151    
3152 matty 9 default:
3153 matty 30 unimpl("triblt 0x%x\n", opcode);
3154 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
3155 matty 9 }
3156     }
3157    
3158 matty 25 void
3159     ui_line(uint8 opcode,
3160     /* dest */ int startx, int starty, int endx, int endy,
3161 astrand 64 /* pen */ PEN * pen)
3162 matty 9 {
3163 matty 29 SET_FUNCTION(opcode);
3164     SET_FOREGROUND(pen->colour);
3165 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
3166 astrand 1199 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 jsorg71 450 if (g_ownbackstore)
3170     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
3171 matty 29 RESET_FUNCTION(opcode);
3172 matty 9 }
3173    
3174 matty 25 void
3175     ui_rect(
3176     /* dest */ int x, int y, int cx, int cy,
3177     /* brush */ int colour)
3178 matty 9 {
3179 matty 29 SET_FOREGROUND(colour);
3180 matty 31 FILL_RECTANGLE(x, y, cx, cy);
3181 matty 9 }
3182    
3183 jdmeijer 831 void
3184     ui_polygon(uint8 opcode,
3185     /* mode */ uint8 fillmode,
3186 jsorg71 1364 /* dest */ RD_POINT * point, int npoints,
3187 jdmeijer 831 /* 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 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3230 jdmeijer 831 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 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3245 jdmeijer 831 break;
3246    
3247     default:
3248     unimpl("brush %d\n", brush->style);
3249     }
3250    
3251     RESET_FUNCTION(opcode);
3252     }
3253    
3254     void
3255 jdmeijer 844 ui_polyline(uint8 opcode,
3256 jsorg71 1364 /* dest */ RD_POINT * points, int npoints,
3257 jdmeijer 844 /* 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 astrand 1199
3267     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
3268     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
3269    
3270 jdmeijer 844 RESET_FUNCTION(opcode);
3271     }
3272    
3273     void
3274 jdmeijer 831 ui_ellipse(uint8 opcode,
3275     /* mode */ uint8 fillmode,
3276     /* dest */ int x, int y, int cx, int cy,
3277     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
3278     {
3279     uint8 style, i, ipattern[8];
3280     Pixmap fill;
3281    
3282     SET_FUNCTION(opcode);
3283    
3284     if (brush)
3285     style = brush->style;
3286     else
3287     style = 0;
3288    
3289     switch (style)
3290     {
3291     case 0: /* Solid */
3292     SET_FOREGROUND(fgcolour);
3293     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
3294     break;
3295    
3296     case 2: /* Hatch */
3297     fill = (Pixmap) ui_create_glyph(8, 8,
3298     hatch_patterns + brush->pattern[0] * 8);
3299     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 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3308 jdmeijer 831 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 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
3323 jdmeijer 831 break;
3324    
3325     default:
3326     unimpl("brush %d\n", brush->style);
3327     }
3328    
3329     RESET_FUNCTION(opcode);
3330     }
3331    
3332 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
3333 matty 25 void
3334     ui_draw_glyph(int mixmode,
3335     /* dest */ int x, int y, int cx, int cy,
3336 jsorg71 1364 /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3337 astrand 66 int bgcolour, int fgcolour)
3338 matty 9 {
3339 matty 29 SET_FOREGROUND(fgcolour);
3340     SET_BACKGROUND(bgcolour);
3341 matty 9
3342 jsorg71 450 XSetFillStyle(g_display, g_gc,
3343 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3344 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
3345     XSetTSOrigin(g_display, g_gc, x, y);
3346 matty 9
3347 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3348 matty 9
3349 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3350 matty 9 }
3351    
3352 mmihalik 49 #define DO_GLYPH(ttext,idx) \
3353     {\
3354     glyph = cache_get_font (font, ttext[idx]);\
3355     if (!(flags & TEXT2_IMPLICIT_X))\
3356 jsorg71 564 {\
3357     xyoffset = ttext[++idx];\
3358     if ((xyoffset & 0x80))\
3359 mmihalik 49 {\
3360 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3361     y += ttext[idx+1] | (ttext[idx+2] << 8);\
3362 mmihalik 49 else\
3363 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
3364     idx += 2;\
3365 mmihalik 49 }\
3366 jsorg71 564 else\
3367 mmihalik 49 {\
3368 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3369     y += xyoffset;\
3370     else\
3371     x += xyoffset;\
3372 mmihalik 49 }\
3373 jsorg71 564 }\
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 mmihalik 49 }
3385    
3386 matty 25 void
3387 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
3388 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
3389 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3390     int bgcolour, int fgcolour, uint8 * text, uint8 length)
3391 matty 9 {
3392 jdmeijer 843 /* TODO: use brush appropriately */
3393    
3394 matty 10 FONTGLYPH *glyph;
3395 jsorg71 564 int i, j, xyoffset, x1, y1;
3396 mmihalik 49 DATABLOB *entry;
3397 matty 9
3398 matty 29 SET_FOREGROUND(bgcolour);
3399 matty 28
3400 astrand 620 /* 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 matty 9 if (boxcx > 1)
3407 matty 31 {
3408 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3409 matty 31 }
3410 matty 17 else if (mixmode == MIX_OPAQUE)
3411 matty 31 {
3412 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3413 matty 31 }
3414 matty 9
3415 jsorg71 564 SET_FOREGROUND(fgcolour);
3416     SET_BACKGROUND(bgcolour);
3417     XSetFillStyle(g_display, g_gc, FillStippled);
3418    
3419 matty 9 /* Paint text, character by character */
3420 astrand 64 for (i = 0; i < length;)
3421     {
3422     switch (text[i])
3423     {
3424     case 0xff:
3425 astrand 1031 /* At least two bytes needs to follow */
3426 astrand 1029 if (i + 3 > length)
3427 astrand 64 {
3428 astrand 1031 warning("Skipping short 0xff command:");
3429     for (j = 0; j < length; j++)
3430     fprintf(stderr, "%02x ", text[j]);
3431     fprintf(stderr, "\n");
3432 astrand 1029 i = length = 0;
3433     break;
3434 astrand 64 }
3435 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
3436     i += 3;
3437     length -= i;
3438 astrand 64 /* this will move pointer from start to first character after FF command */
3439 astrand 1029 text = &(text[i]);
3440 astrand 64 i = 0;
3441 mmihalik 49 break;
3442 matty 9
3443 astrand 64 case 0xfe:
3444 astrand 1031 /* At least one byte needs to follow */
3445     if (i + 2 > length)
3446 astrand 1029 {
3447 astrand 1031 warning("Skipping short 0xfe command:");
3448     for (j = 0; j < length; j++)
3449     fprintf(stderr, "%02x ", text[j]);
3450     fprintf(stderr, "\n");
3451 astrand 1029 i = length = 0;
3452     break;
3453     }
3454 astrand 64 entry = cache_get_text(text[i + 1]);
3455 astrand 1030 if (entry->data != NULL)
3456 astrand 64 {
3457 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
3458     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3459 astrand 64 {
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 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
3467 matthewc 44 }
3468 astrand 1031 if (i + 2 < length)
3469     i += 3;
3470     else
3471     i += 2;
3472 jsorg71 286 length -= i;
3473     /* this will move pointer from start to first character after FE command */
3474     text = &(text[i]);
3475     i = 0;
3476 astrand 64 break;
3477 matty 17
3478 astrand 64 default:
3479     DO_GLYPH(text, i);
3480     i++;
3481     break;
3482 matty 29 }
3483 mmihalik 49 }
3484 jsorg71 564
3485     XSetFillStyle(g_display, g_gc, FillSolid);
3486    
3487 jsorg71 450 if (g_ownbackstore)
3488 jsorg71 278 {
3489     if (boxcx > 1)
3490 astrand 1199 {
3491 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3492 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
3493 astrand 1199 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 jsorg71 278 else
3500 astrand 1199 {
3501 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3502 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
3503 astrand 1199 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 jsorg71 278 }
3510 matty 9 }
3511    
3512 matty 25 void
3513     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
3514 matty 9 {
3515 matty 28 Pixmap pix;
3516 matty 9 XImage *image;
3517    
3518 jsorg71 450 if (g_ownbackstore)
3519 matty 31 {
3520 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3521 astrand 1306 exit_if_null(image);
3522 matty 31 }
3523     else
3524     {
3525 jsorg71 450 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 astrand 1306 exit_if_null(image);
3529 jsorg71 450 XFreePixmap(g_display, pix);
3530 matty 31 }
3531 matty 28
3532 jsorg71 450 offset *= g_bpp / 8;
3533     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
3534 matty 28
3535     XDestroyImage(image);
3536 matty 9 }
3537    
3538 matty 25 void
3539     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
3540 matty 9 {
3541     XImage *image;
3542 matty 10 uint8 *data;
3543 matty 9
3544 jsorg71 450 offset *= g_bpp / 8;
3545     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3546 matty 10 if (data == NULL)
3547     return;
3548 matty 29
3549 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3550 stargo 1403 (char *) data, cx, cy, g_bpp, 0);
3551 matty 29
3552 jsorg71 450 if (g_ownbackstore)
3553 matty 31 {
3554 jsorg71 450 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 astrand 1199 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 matty 31 }
3560     else
3561     {
3562 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3563 astrand 1199 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 matty 31 }
3567    
3568 matty 9 XFree(image);
3569     }
3570 jsorg71 713
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 astrand 1199
3582    
3583     void
3584 jsorg71 1372 ui_seamless_begin(RD_BOOL hidden)
3585 astrand 1199 {
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 astrand 1443 if (flags & SEAMLESSRDP_CREATE_TOPMOST)
3740     {
3741     /* Make window always-on-top */
3742     ewmh_set_window_above(wnd);
3743     }
3744    
3745 astrand 1199 /* 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 astrand 1447 /* handle the WM_DELETE_WINDOW protocol. */
3753 astrand 1199 XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3754    
3755     sw = xmalloc(sizeof(seamless_window));
3756 ossman_ 1413
3757     memset(sw, 0, sizeof(seamless_window));
3758    
3759 astrand 1199 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 ossman_ 1232 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 ossman_ 1413 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 astrand 1199 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 astrand 1459 XWindowChanges values;
3963     unsigned long restack_serial;
3964 astrand 1199
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 astrand 1453 warning("ui_seamless_restack_window: No information for behind window 0x%lx\n", behind);
3983 astrand 1199 return;
3984     }
3985    
3986 astrand 1459 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 astrand 1199 }
3996     else
3997     {
3998 astrand 1459 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 astrand 1199 }
4004    
4005     sw_restack_window(sw, behind);
4006 astrand 1443
4007     if (flags & SEAMLESSRDP_CREATE_TOPMOST)
4008     {
4009     /* Make window always-on-top */
4010     ewmh_set_window_above(sw->wnd);
4011     }
4012 astrand 1199 }
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     }

  ViewVC Help
Powered by ViewVC 1.1.26