/[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 1107 - (show annotations)
Fri Mar 10 14:09:16 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 73292 byte(s)
Checking return value from seamless_get_window_* everywhere

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

  ViewVC Help
Powered by ViewVC 1.1.26