/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1193 - (show annotations)
Wed Mar 22 16:20:55 2006 UTC (18 years, 3 months ago) by ossman_
File MIME type: text/plain
File size: 83654 byte(s)
Support for the new HIDE/UNHIDE commands.

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

  ViewVC Help
Powered by ViewVC 1.1.26