/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1403 - (show annotations)
Thu Apr 12 16:04:25 2007 UTC (17 years, 1 month ago) by stargo
File MIME type: text/plain
File size: 84180 byte(s)
[PATCH] rdesktop segfault with libx11-6 1.0.3-7 by Mark Heily <mark@heily.com>

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

  ViewVC Help
Powered by ViewVC 1.1.26