/[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 1246 - (show annotations)
Tue Jul 11 17:22:24 2006 UTC (17 years, 10 months ago) by stargo
File MIME type: text/plain
File size: 84213 byte(s)
set screen-number in XGetVisualInfo (patch 1417414 by Jeremy Smith)

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