/[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 1057 - (show annotations)
Tue Mar 7 08:17:40 2006 UTC (18 years, 2 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 62674 byte(s)
* If fullscreen mode, set g_using_full_workarea = True;

* When using -g workarea, if workarea fetch fails, do not set
  g_using_full_workarea. Fall back to size of entire screen, instead
  of 800x600.

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

  ViewVC Help
Powered by ViewVC 1.1.26