/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1042 - (show annotations)
Tue Jan 24 12:40:24 2006 UTC (18 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 62212 byte(s)
Applied patch #1390148 from Ilya Konstantinov: Refactoring of color depth code.

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

  ViewVC Help
Powered by ViewVC 1.1.26