/[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 1469 - (hide annotations)
Thu Apr 24 14:13:28 2008 UTC (16 years ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 95817 byte(s)
Indented

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

  ViewVC Help
Powered by ViewVC 1.1.26