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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1463 - (hide annotations)
Fri Mar 28 11:36:15 2008 UTC (16 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 95531 byte(s)
Moved call to seamless_restack_test from ui_init to end of
ui_create_window. This seems to fix problems the WTS disconnecting the
session due to "DATA ENCRYPTION" errors. At this point, it's unknown
why this patch fixes the problem, but ui_create_window is a good place
for seamless_restack_test() in any case.

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

  ViewVC Help
Powered by ViewVC 1.1.26