/[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 1370 - (show annotations)
Thu Jan 4 23:38:35 2007 UTC (17 years, 4 months ago) by stargo
File MIME type: text/plain
File size: 84108 byte(s)
allow inclusion of Xproto.h by renaming their BOOL to XPROTO_BOOL

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

  ViewVC Help
Powered by ViewVC 1.1.26