/[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 1040 - (show annotations)
Tue Jan 24 12:24:40 2006 UTC (18 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 57433 byte(s)
In translate24to32, only read 3 bytes from data buffer. If we are
reading 4 bytes, we are reading beyond the buffer. Fixes valgrind
warnings.

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

  ViewVC Help
Powered by ViewVC 1.1.26