/[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 887 - (show annotations)
Sat Apr 16 11:57:19 2005 UTC (19 years, 1 month ago) by stargo
File MIME type: text/plain
File size: 56652 byte(s)
Handle RDP recv queue even in RDP send queue is full.
Patch from James Cameron <james.cameron@hp.com>
This closes Debian Bug #246461.

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
83 #ifdef WITH_RDPSND
84 extern int g_dsp_fd;
85 extern BOOL g_dsp_busy;
86 extern BOOL g_rdpsnd;
87 #endif
88
89 /* MWM decorations */
90 #define MWM_HINTS_DECORATIONS (1L << 1)
91 #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
92 typedef struct
93 {
94 uint32 flags;
95 uint32 functions;
96 uint32 decorations;
97 sint32 inputMode;
98 uint32 status;
99 }
100 PropMotifWmHints;
101
102 typedef struct
103 {
104 uint32 red;
105 uint32 green;
106 uint32 blue;
107 }
108 PixelColour;
109
110
111 #define FILL_RECTANGLE(x,y,cx,cy)\
112 { \
113 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
114 if (g_ownbackstore) \
115 XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
116 }
117
118 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
119 { \
120 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
121 }
122
123 #define FILL_POLYGON(p,np)\
124 { \
125 XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
126 if (g_ownbackstore) \
127 XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
128 }
129
130 #define DRAW_ELLIPSE(x,y,cx,cy,m)\
131 { \
132 switch (m) \
133 { \
134 case 0: /* Outline */ \
135 XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
136 if (g_ownbackstore) \
137 XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
138 break; \
139 case 1: /* Filled */ \
140 XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \
141 cx, cy, 0, 360*64); \
142 if (g_ownbackstore) \
143 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \
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 *((uint32 *) out) = *((uint32 *) data);
806 out += 4;
807 data += 3;
808 )
809 #endif
810 /* *INDENT-ON* */
811 }
812 else if (g_xserver_be)
813 {
814 while (out < end)
815 {
816 pixel = *(data++) << 16;
817 pixel |= *(data++) << 8;
818 pixel |= *(data++);
819 SPLITCOLOUR24(pixel, pc);
820 value = MAKECOLOUR(pc);
821 BOUT32(out, value);
822 }
823 }
824 else
825 {
826 while (out < end)
827 {
828 pixel = *(data++) << 16;
829 pixel |= *(data++) << 8;
830 pixel |= *(data++);
831 SPLITCOLOUR24(pixel, pc);
832 value = MAKECOLOUR(pc);
833 LOUT32(out, value);
834 }
835 }
836 }
837
838 static uint8 *
839 translate_image(int width, int height, uint8 * data)
840 {
841 int size;
842 uint8 *out;
843 uint8 *end;
844
845 /* if server and xserver bpp match, */
846 /* and arch(endian) matches, no need to translate */
847 /* just return data */
848 if (g_arch_match)
849 {
850 if (g_depth == 15 && g_server_bpp == 15)
851 return data;
852 if (g_depth == 16 && g_server_bpp == 16)
853 return data;
854 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)
855 return data;
856 }
857
858 size = width * height * (g_bpp / 8);
859 out = (uint8 *) xmalloc(size);
860 end = out + size;
861
862 switch (g_server_bpp)
863 {
864 case 24:
865 switch (g_bpp)
866 {
867 case 32:
868 translate24to32(data, out, end);
869 break;
870 case 24:
871 translate24to24(data, out, end);
872 break;
873 case 16:
874 translate24to16(data, out, end);
875 break;
876 }
877 break;
878 case 16:
879 switch (g_bpp)
880 {
881 case 32:
882 translate16to32((uint16 *) data, out, end);
883 break;
884 case 24:
885 translate16to24((uint16 *) data, out, end);
886 break;
887 case 16:
888 translate16to16((uint16 *) data, out, end);
889 break;
890 }
891 break;
892 case 15:
893 switch (g_bpp)
894 {
895 case 32:
896 translate15to32((uint16 *) data, out, end);
897 break;
898 case 24:
899 translate15to24((uint16 *) data, out, end);
900 break;
901 case 16:
902 translate15to16((uint16 *) data, out, end);
903 break;
904 }
905 break;
906 case 8:
907 switch (g_bpp)
908 {
909 case 8:
910 translate8to8(data, out, end);
911 break;
912 case 16:
913 translate8to16(data, out, end);
914 break;
915 case 24:
916 translate8to24(data, out, end);
917 break;
918 case 32:
919 translate8to32(data, out, end);
920 break;
921 }
922 break;
923 }
924 return out;
925 }
926
927 BOOL
928 get_key_state(unsigned int state, uint32 keysym)
929 {
930 int modifierpos, key, keysymMask = 0;
931 int offset;
932
933 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
934
935 if (keycode == NoSymbol)
936 return False;
937
938 for (modifierpos = 0; modifierpos < 8; modifierpos++)
939 {
940 offset = g_mod_map->max_keypermod * modifierpos;
941
942 for (key = 0; key < g_mod_map->max_keypermod; key++)
943 {
944 if (g_mod_map->modifiermap[offset + key] == keycode)
945 keysymMask |= 1 << modifierpos;
946 }
947 }
948
949 return (state & keysymMask) ? True : False;
950 }
951
952 static void
953 calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
954 {
955 *shift_l = ffs(mask) - 1;
956 mask >>= *shift_l;
957 *shift_r = 8 - ffs(mask & ~(mask >> 1));
958 }
959
960 BOOL
961 ui_init(void)
962 {
963 XVisualInfo vi;
964 XPixmapFormatValues *pfm;
965 uint16 test;
966 int i, screen_num, nvisuals;
967 XVisualInfo *vmatches = NULL;
968 XVisualInfo template;
969 Bool TrueColorVisual = False;
970
971 g_display = XOpenDisplay(NULL);
972 if (g_display == NULL)
973 {
974 error("Failed to open display: %s\n", XDisplayName(NULL));
975 return False;
976 }
977
978 screen_num = DefaultScreen(g_display);
979 g_x_socket = ConnectionNumber(g_display);
980 g_screen = ScreenOfDisplay(g_display, screen_num);
981 g_depth = DefaultDepthOfScreen(g_screen);
982
983 /* Search for best TrueColor depth */
984 template.class = TrueColor;
985 vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);
986
987 nvisuals--;
988 while (nvisuals >= 0)
989 {
990 if ((vmatches + nvisuals)->depth > g_depth)
991 {
992 g_depth = (vmatches + nvisuals)->depth;
993 }
994 nvisuals--;
995 TrueColorVisual = True;
996 }
997
998 test = 1;
999 g_host_be = !(BOOL) (*(uint8 *) (&test));
1000 g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1001
1002 if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))
1003 {
1004 /* we use a colourmap, so the default visual should do */
1005 g_visual = DefaultVisualOfScreen(g_screen);
1006 g_depth = DefaultDepthOfScreen(g_screen);
1007
1008 /* Do not allocate colours on a TrueColor visual */
1009 if (g_visual->class == TrueColor)
1010 {
1011 g_owncolmap = False;
1012 }
1013 }
1014 else
1015 {
1016 /* need a truecolour visual */
1017 if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))
1018 {
1019 error("The display does not support true colour - high colour support unavailable.\n");
1020 return False;
1021 }
1022
1023 g_visual = vi.visual;
1024 g_owncolmap = False;
1025 calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);
1026 calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1027 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);
1028
1029 /* if RGB video and everything is little endian */
1030 if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&
1031 !g_xserver_be && !g_host_be)
1032 {
1033 if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&
1034 g_blue_shift_l == 0))
1035 {
1036 g_arch_match = True;
1037 }
1038 }
1039
1040 if (g_arch_match)
1041 {
1042 DEBUG(("Architectures match, enabling little endian optimisations.\n"));
1043 }
1044 }
1045
1046 pfm = XListPixmapFormats(g_display, &i);
1047 if (pfm != NULL)
1048 {
1049 /* Use maximum bpp for this depth - this is generally
1050 desirable, e.g. 24 bits->32 bits. */
1051 while (i--)
1052 {
1053 if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
1054 {
1055 g_bpp = pfm[i].bits_per_pixel;
1056 }
1057 }
1058 XFree(pfm);
1059 }
1060
1061 if (g_bpp < 8)
1062 {
1063 error("Less than 8 bpp not currently supported.\n");
1064 XCloseDisplay(g_display);
1065 return False;
1066 }
1067
1068 if (!g_owncolmap)
1069 {
1070 g_xcolmap =
1071 XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1072 AllocNone);
1073 if (g_depth <= 8)
1074 warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
1075 }
1076
1077 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1078 {
1079 warning("External BackingStore not available, using internal\n");
1080 g_ownbackstore = True;
1081 }
1082
1083 /*
1084 * Determine desktop size
1085 */
1086 if (g_fullscreen)
1087 {
1088 g_width = WidthOfScreen(g_screen);
1089 g_height = HeightOfScreen(g_screen);
1090 }
1091 else if (g_width < 0)
1092 {
1093 /* Percent of screen */
1094 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1095 g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1096 }
1097 else if (g_width == 0)
1098 {
1099 /* Fetch geometry from _NET_WORKAREA */
1100 uint32 x, y, cx, cy;
1101
1102 if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1103 {
1104 g_width = cx;
1105 g_height = cy;
1106 }
1107 else
1108 {
1109 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1110 g_width = 800;
1111 g_height = 600;
1112 }
1113 }
1114
1115 /* make sure width is a multiple of 4 */
1116 g_width = (g_width + 3) & ~3;
1117
1118 g_mod_map = XGetModifierMapping(g_display);
1119
1120 xkeymap_init();
1121
1122 if (g_enable_compose)
1123 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1124
1125 xclip_init();
1126
1127 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));
1128
1129 return True;
1130 }
1131
1132 void
1133 ui_deinit(void)
1134 {
1135 if (g_IM != NULL)
1136 XCloseIM(g_IM);
1137
1138 if (g_null_cursor != NULL)
1139 ui_destroy_cursor(g_null_cursor);
1140
1141 XFreeModifiermap(g_mod_map);
1142
1143 if (g_ownbackstore)
1144 XFreePixmap(g_display, g_backstore);
1145
1146 XFreeGC(g_display, g_gc);
1147 XCloseDisplay(g_display);
1148 g_display = NULL;
1149 }
1150
1151 BOOL
1152 ui_create_window(void)
1153 {
1154 uint8 null_pointer_mask[1] = { 0x80 };
1155 uint8 null_pointer_data[24] = { 0x00 };
1156
1157 XSetWindowAttributes attribs;
1158 XClassHint *classhints;
1159 XSizeHints *sizehints;
1160 int wndwidth, wndheight;
1161 long input_mask, ic_input_mask;
1162 XEvent xevent;
1163
1164 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1165 wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1166
1167 /* Handle -x-y portion of geometry string */
1168 if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1169 g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1170 if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1171 g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1172
1173 attribs.background_pixel = BlackPixelOfScreen(g_screen);
1174 attribs.border_pixel = WhitePixelOfScreen(g_screen);
1175 attribs.backing_store = g_ownbackstore ? NotUseful : Always;
1176 attribs.override_redirect = g_fullscreen;
1177 attribs.colormap = g_xcolmap;
1178
1179 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1180 wndheight, 0, g_depth, InputOutput, g_visual,
1181 CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1182 CWBorderPixel, &attribs);
1183
1184 if (g_gc == NULL)
1185 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1186
1187 if (g_create_bitmap_gc == NULL)
1188 g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1189
1190 if ((g_ownbackstore) && (g_backstore == 0))
1191 {
1192 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1193
1194 /* clear to prevent rubbish being exposed at startup */
1195 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1196 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1197 }
1198
1199 XStoreName(g_display, g_wnd, g_title);
1200
1201 if (g_hide_decorations)
1202 mwm_hide_decorations();
1203
1204 classhints = XAllocClassHint();
1205 if (classhints != NULL)
1206 {
1207 classhints->res_name = classhints->res_class = "rdesktop";
1208 XSetClassHint(g_display, g_wnd, classhints);
1209 XFree(classhints);
1210 }
1211
1212 sizehints = XAllocSizeHints();
1213 if (sizehints)
1214 {
1215 sizehints->flags = PMinSize | PMaxSize;
1216 if (g_pos)
1217 sizehints->flags |= PPosition;
1218 sizehints->min_width = sizehints->max_width = g_width;
1219 sizehints->min_height = sizehints->max_height = g_height;
1220 XSetWMNormalHints(g_display, g_wnd, sizehints);
1221 XFree(sizehints);
1222 }
1223
1224 if (g_embed_wnd)
1225 {
1226 XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1227 }
1228
1229 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1230 VisibilityChangeMask | FocusChangeMask;
1231
1232 if (g_sendmotion)
1233 input_mask |= PointerMotionMask;
1234 if (g_ownbackstore)
1235 input_mask |= ExposureMask;
1236 if (g_fullscreen || g_grab_keyboard)
1237 input_mask |= EnterWindowMask;
1238 if (g_grab_keyboard)
1239 input_mask |= LeaveWindowMask;
1240
1241 if (g_IM != NULL)
1242 {
1243 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1244 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1245
1246 if ((g_IC != NULL)
1247 && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1248 input_mask |= ic_input_mask;
1249 }
1250
1251 XSelectInput(g_display, g_wnd, input_mask);
1252 XMapWindow(g_display, g_wnd);
1253
1254 /* wait for VisibilityNotify */
1255 do
1256 {
1257 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1258 }
1259 while (xevent.type != VisibilityNotify);
1260 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1261
1262 g_focused = False;
1263 g_mouse_in_wnd = False;
1264
1265 /* handle the WM_DELETE_WINDOW protocol */
1266 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1267 g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1268 XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1269
1270 /* create invisible 1x1 cursor to be used as null cursor */
1271 if (g_null_cursor == NULL)
1272 g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1273
1274 return True;
1275 }
1276
1277 void
1278 ui_resize_window()
1279 {
1280 XSizeHints *sizehints;
1281 Pixmap bs;
1282
1283 sizehints = XAllocSizeHints();
1284 if (sizehints)
1285 {
1286 sizehints->flags = PMinSize | PMaxSize;
1287 sizehints->min_width = sizehints->max_width = g_width;
1288 sizehints->min_height = sizehints->max_height = g_height;
1289 XSetWMNormalHints(g_display, g_wnd, sizehints);
1290 XFree(sizehints);
1291 }
1292
1293 if (!(g_fullscreen || g_embed_wnd))
1294 {
1295 XResizeWindow(g_display, g_wnd, g_width, g_height);
1296 }
1297
1298 /* create new backstore pixmap */
1299 if (g_backstore != 0)
1300 {
1301 bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1302 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1303 XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1304 XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1305 XFreePixmap(g_display, g_backstore);
1306 g_backstore = bs;
1307 }
1308 }
1309
1310 void
1311 ui_destroy_window(void)
1312 {
1313 if (g_IC != NULL)
1314 XDestroyIC(g_IC);
1315
1316 XDestroyWindow(g_display, g_wnd);
1317 }
1318
1319 void
1320 xwin_toggle_fullscreen(void)
1321 {
1322 Pixmap contents = 0;
1323
1324 if (!g_ownbackstore)
1325 {
1326 /* need to save contents of window */
1327 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1328 XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1329 }
1330
1331 ui_destroy_window();
1332 g_fullscreen = !g_fullscreen;
1333 ui_create_window();
1334
1335 XDefineCursor(g_display, g_wnd, g_current_cursor);
1336
1337 if (!g_ownbackstore)
1338 {
1339 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1340 XFreePixmap(g_display, contents);
1341 }
1342 }
1343
1344 /* Process events in Xlib queue
1345 Returns 0 after user quit, 1 otherwise */
1346 static int
1347 xwin_process_events(void)
1348 {
1349 XEvent xevent;
1350 KeySym keysym;
1351 uint16 button, flags;
1352 uint32 ev_time;
1353 key_translation tr;
1354 char str[256];
1355 Status status;
1356 int events = 0;
1357
1358 while ((XPending(g_display) > 0) && events++ < 20)
1359 {
1360 XNextEvent(g_display, &xevent);
1361
1362 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1363 {
1364 DEBUG_KBD(("Filtering event\n"));
1365 continue;
1366 }
1367
1368 flags = 0;
1369
1370 switch (xevent.type)
1371 {
1372 case VisibilityNotify:
1373 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1374 break;
1375 case ClientMessage:
1376 /* the window manager told us to quit */
1377 if ((xevent.xclient.message_type == g_protocol_atom)
1378 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1379 /* Quit */
1380 return 0;
1381 break;
1382
1383 case KeyPress:
1384 g_last_gesturetime = xevent.xkey.time;
1385 if (g_IC != NULL)
1386 /* Multi_key compatible version */
1387 {
1388 XmbLookupString(g_IC,
1389 &xevent.xkey, str, sizeof(str), &keysym,
1390 &status);
1391 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1392 {
1393 error("XmbLookupString failed with status 0x%x\n",
1394 status);
1395 break;
1396 }
1397 }
1398 else
1399 {
1400 /* Plain old XLookupString */
1401 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1402 XLookupString((XKeyEvent *) & xevent,
1403 str, sizeof(str), &keysym, NULL);
1404 }
1405
1406 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1407 get_ksname(keysym)));
1408
1409 ev_time = time(NULL);
1410 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1411 break;
1412
1413 tr = xkeymap_translate_key(keysym,
1414 xevent.xkey.keycode, xevent.xkey.state);
1415
1416 if (tr.scancode == 0)
1417 break;
1418
1419 save_remote_modifiers(tr.scancode);
1420 ensure_remote_modifiers(ev_time, tr);
1421 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1422 restore_remote_modifiers(ev_time, tr.scancode);
1423
1424 break;
1425
1426 case KeyRelease:
1427 g_last_gesturetime = xevent.xkey.time;
1428 XLookupString((XKeyEvent *) & xevent, str,
1429 sizeof(str), &keysym, NULL);
1430
1431 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1432 get_ksname(keysym)));
1433
1434 ev_time = time(NULL);
1435 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1436 break;
1437
1438 tr = xkeymap_translate_key(keysym,
1439 xevent.xkey.keycode, xevent.xkey.state);
1440
1441 if (tr.scancode == 0)
1442 break;
1443
1444 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1445 break;
1446
1447 case ButtonPress:
1448 flags = MOUSE_FLAG_DOWN;
1449 /* fall through */
1450
1451 case ButtonRelease:
1452 g_last_gesturetime = xevent.xbutton.time;
1453 button = xkeymap_translate_button(xevent.xbutton.button);
1454 if (button == 0)
1455 break;
1456
1457 /* If win_button_size is nonzero, enable single app mode */
1458 if (xevent.xbutton.y < g_win_button_size)
1459 {
1460 /* Stop moving window when button is released, regardless of cursor position */
1461 if (g_moving_wnd && (xevent.type == ButtonRelease))
1462 g_moving_wnd = False;
1463
1464 /* Check from right to left: */
1465
1466 if (xevent.xbutton.x >= g_width - g_win_button_size)
1467 {
1468 /* The close button, continue */
1469 ;
1470 }
1471 else if (xevent.xbutton.x >=
1472 g_width - g_win_button_size * 2)
1473 {
1474 /* The maximize/restore button. Do not send to
1475 server. It might be a good idea to change the
1476 cursor or give some other visible indication
1477 that rdesktop inhibited this click */
1478 break;
1479 }
1480 else if (xevent.xbutton.x >=
1481 g_width - g_win_button_size * 3)
1482 {
1483 /* The minimize button. Iconify window. */
1484 XIconifyWindow(g_display, g_wnd,
1485 DefaultScreen(g_display));
1486 break;
1487 }
1488 else if (xevent.xbutton.x <= g_win_button_size)
1489 {
1490 /* The system menu. Ignore. */
1491 break;
1492 }
1493 else
1494 {
1495 /* The title bar. */
1496 if ((xevent.type == ButtonPress) && !g_fullscreen
1497 && g_hide_decorations)
1498 {
1499 g_moving_wnd = True;
1500 g_move_x_offset = xevent.xbutton.x;
1501 g_move_y_offset = xevent.xbutton.y;
1502 }
1503 break;
1504
1505 }
1506 }
1507
1508 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1509 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1510 break;
1511
1512 case MotionNotify:
1513 if (g_moving_wnd)
1514 {
1515 XMoveWindow(g_display, g_wnd,
1516 xevent.xmotion.x_root - g_move_x_offset,
1517 xevent.xmotion.y_root - g_move_y_offset);
1518 break;
1519 }
1520
1521 if (g_fullscreen && !g_focused)
1522 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1523 CurrentTime);
1524 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1525 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1526 break;
1527
1528 case FocusIn:
1529 if (xevent.xfocus.mode == NotifyGrab)
1530 break;
1531 g_focused = True;
1532 reset_modifier_keys();
1533 if (g_grab_keyboard && g_mouse_in_wnd)
1534 XGrabKeyboard(g_display, g_wnd, True,
1535 GrabModeAsync, GrabModeAsync, CurrentTime);
1536 break;
1537
1538 case FocusOut:
1539 if (xevent.xfocus.mode == NotifyUngrab)
1540 break;
1541 g_focused = False;
1542 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1543 XUngrabKeyboard(g_display, CurrentTime);
1544 break;
1545
1546 case EnterNotify:
1547 /* we only register for this event when in fullscreen mode */
1548 /* or grab_keyboard */
1549 g_mouse_in_wnd = True;
1550 if (g_fullscreen)
1551 {
1552 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1553 CurrentTime);
1554 break;
1555 }
1556 if (g_focused)
1557 XGrabKeyboard(g_display, g_wnd, True,
1558 GrabModeAsync, GrabModeAsync, CurrentTime);
1559 break;
1560
1561 case LeaveNotify:
1562 /* we only register for this event when grab_keyboard */
1563 g_mouse_in_wnd = False;
1564 XUngrabKeyboard(g_display, CurrentTime);
1565 break;
1566
1567 case Expose:
1568 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1569 xevent.xexpose.x, xevent.xexpose.y,
1570 xevent.xexpose.width,
1571 xevent.xexpose.height,
1572 xevent.xexpose.x, xevent.xexpose.y);
1573 break;
1574
1575 case MappingNotify:
1576 /* Refresh keyboard mapping if it has changed. This is important for
1577 Xvnc, since it allocates keycodes dynamically */
1578 if (xevent.xmapping.request == MappingKeyboard
1579 || xevent.xmapping.request == MappingModifier)
1580 XRefreshKeyboardMapping(&xevent.xmapping);
1581
1582 if (xevent.xmapping.request == MappingModifier)
1583 {
1584 XFreeModifiermap(g_mod_map);
1585 g_mod_map = XGetModifierMapping(g_display);
1586 }
1587 break;
1588
1589 /* clipboard stuff */
1590 case SelectionNotify:
1591 xclip_handle_SelectionNotify(&xevent.xselection);
1592 break;
1593 case SelectionRequest:
1594 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1595 break;
1596 case SelectionClear:
1597 xclip_handle_SelectionClear();
1598 break;
1599 case PropertyNotify:
1600 xclip_handle_PropertyNotify(&xevent.xproperty);
1601 break;
1602 }
1603 }
1604 /* Keep going */
1605 return 1;
1606 }
1607
1608 /* Returns 0 after user quit, 1 otherwise */
1609 int
1610 ui_select(int rdp_socket)
1611 {
1612 int n;
1613 fd_set rfds, wfds;
1614 struct timeval tv;
1615 BOOL s_timeout = False;
1616
1617 while (True)
1618 {
1619 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1620 /* Process any events already waiting */
1621 if (!xwin_process_events())
1622 /* User quit */
1623 return 0;
1624
1625 FD_ZERO(&rfds);
1626 FD_ZERO(&wfds);
1627 FD_SET(rdp_socket, &rfds);
1628 FD_SET(g_x_socket, &rfds);
1629
1630 #ifdef WITH_RDPSND
1631 /* FIXME: there should be an API for registering fds */
1632 if (g_dsp_busy)
1633 {
1634 FD_SET(g_dsp_fd, &wfds);
1635 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1636 }
1637 #endif
1638 /* default timeout */
1639 tv.tv_sec = 60;
1640 tv.tv_usec = 0;
1641
1642 /* add redirection handles */
1643 rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1644
1645 n++;
1646
1647 switch (select(n, &rfds, &wfds, NULL, &tv))
1648 {
1649 case -1:
1650 error("select: %s\n", strerror(errno));
1651
1652 case 0:
1653 /* Abort serial read calls */
1654 if (s_timeout)
1655 rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1656 continue;
1657 }
1658
1659 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1660
1661 if (FD_ISSET(rdp_socket, &rfds))
1662 return 1;
1663
1664 #ifdef WITH_RDPSND
1665 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1666 wave_out_play();
1667 #endif
1668 }
1669 }
1670
1671 void
1672 ui_move_pointer(int x, int y)
1673 {
1674 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1675 }
1676
1677 HBITMAP
1678 ui_create_bitmap(int width, int height, uint8 * data)
1679 {
1680 XImage *image;
1681 Pixmap bitmap;
1682 uint8 *tdata;
1683 int bitmap_pad;
1684
1685 if (g_server_bpp == 8)
1686 {
1687 bitmap_pad = 8;
1688 }
1689 else
1690 {
1691 bitmap_pad = g_bpp;
1692
1693 if (g_bpp == 24)
1694 bitmap_pad = 32;
1695 }
1696
1697 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1698 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1699 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1700 (char *) tdata, width, height, bitmap_pad, 0);
1701
1702 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1703
1704 XFree(image);
1705 if (tdata != data)
1706 xfree(tdata);
1707 return (HBITMAP) bitmap;
1708 }
1709
1710 void
1711 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1712 {
1713 XImage *image;
1714 uint8 *tdata;
1715 int bitmap_pad;
1716
1717 if (g_server_bpp == 8)
1718 {
1719 bitmap_pad = 8;
1720 }
1721 else
1722 {
1723 bitmap_pad = g_bpp;
1724
1725 if (g_bpp == 24)
1726 bitmap_pad = 32;
1727 }
1728
1729 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1730 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1731 (char *) tdata, width, height, bitmap_pad, 0);
1732
1733 if (g_ownbackstore)
1734 {
1735 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1736 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1737 }
1738 else
1739 {
1740 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1741 }
1742
1743 XFree(image);
1744 if (tdata != data)
1745 xfree(tdata);
1746 }
1747
1748 void
1749 ui_destroy_bitmap(HBITMAP bmp)
1750 {
1751 XFreePixmap(g_display, (Pixmap) bmp);
1752 }
1753
1754 HGLYPH
1755 ui_create_glyph(int width, int height, uint8 * data)
1756 {
1757 XImage *image;
1758 Pixmap bitmap;
1759 int scanline;
1760
1761 scanline = (width + 7) / 8;
1762
1763 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1764 if (g_create_glyph_gc == 0)
1765 g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1766
1767 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1768 width, height, 8, scanline);
1769 image->byte_order = MSBFirst;
1770 image->bitmap_bit_order = MSBFirst;
1771 XInitImage(image);
1772
1773 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1774
1775 XFree(image);
1776 return (HGLYPH) bitmap;
1777 }
1778
1779 void
1780 ui_destroy_glyph(HGLYPH glyph)
1781 {
1782 XFreePixmap(g_display, (Pixmap) glyph);
1783 }
1784
1785 HCURSOR
1786 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1787 uint8 * andmask, uint8 * xormask)
1788 {
1789 HGLYPH maskglyph, cursorglyph;
1790 XColor bg, fg;
1791 Cursor xcursor;
1792 uint8 *cursor, *pcursor;
1793 uint8 *mask, *pmask;
1794 uint8 nextbit;
1795 int scanline, offset;
1796 int i, j;
1797
1798 scanline = (width + 7) / 8;
1799 offset = scanline * height;
1800
1801 cursor = (uint8 *) xmalloc(offset);
1802 memset(cursor, 0, offset);
1803
1804 mask = (uint8 *) xmalloc(offset);
1805 memset(mask, 0, offset);
1806
1807 /* approximate AND and XOR masks with a monochrome X pointer */
1808 for (i = 0; i < height; i++)
1809 {
1810 offset -= scanline;
1811 pcursor = &cursor[offset];
1812 pmask = &mask[offset];
1813
1814 for (j = 0; j < scanline; j++)
1815 {
1816 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1817 {
1818 if (xormask[0] || xormask[1] || xormask[2])
1819 {
1820 *pcursor |= (~(*andmask) & nextbit);
1821 *pmask |= nextbit;
1822 }
1823 else
1824 {
1825 *pcursor |= ((*andmask) & nextbit);
1826 *pmask |= (~(*andmask) & nextbit);
1827 }
1828
1829 xormask += 3;
1830 }
1831
1832 andmask++;
1833 pcursor++;
1834 pmask++;
1835 }
1836 }
1837
1838 fg.red = fg.blue = fg.green = 0xffff;
1839 bg.red = bg.blue = bg.green = 0x0000;
1840 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1841
1842 cursorglyph = ui_create_glyph(width, height, cursor);
1843 maskglyph = ui_create_glyph(width, height, mask);
1844
1845 xcursor =
1846 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1847 (Pixmap) maskglyph, &fg, &bg, x, y);
1848
1849 ui_destroy_glyph(maskglyph);
1850 ui_destroy_glyph(cursorglyph);
1851 xfree(mask);
1852 xfree(cursor);
1853 return (HCURSOR) xcursor;
1854 }
1855
1856 void
1857 ui_set_cursor(HCURSOR cursor)
1858 {
1859 g_current_cursor = (Cursor) cursor;
1860 XDefineCursor(g_display, g_wnd, g_current_cursor);
1861 }
1862
1863 void
1864 ui_destroy_cursor(HCURSOR cursor)
1865 {
1866 XFreeCursor(g_display, (Cursor) cursor);
1867 }
1868
1869 void
1870 ui_set_null_cursor(void)
1871 {
1872 ui_set_cursor(g_null_cursor);
1873 }
1874
1875 #define MAKE_XCOLOR(xc,c) \
1876 (xc)->red = ((c)->red << 8) | (c)->red; \
1877 (xc)->green = ((c)->green << 8) | (c)->green; \
1878 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1879 (xc)->flags = DoRed | DoGreen | DoBlue;
1880
1881
1882 HCOLOURMAP
1883 ui_create_colourmap(COLOURMAP * colours)
1884 {
1885 COLOURENTRY *entry;
1886 int i, ncolours = colours->ncolours;
1887 if (!g_owncolmap)
1888 {
1889 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1890 XColor xentry;
1891 XColor xc_cache[256];
1892 uint32 colour;
1893 int colLookup = 256;
1894 for (i = 0; i < ncolours; i++)
1895 {
1896 entry = &colours->colours[i];
1897 MAKE_XCOLOR(&xentry, entry);
1898
1899 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1900 {
1901 /* Allocation failed, find closest match. */
1902 int j = 256;
1903 int nMinDist = 3 * 256 * 256;
1904 long nDist = nMinDist;
1905
1906 /* only get the colors once */
1907 while (colLookup--)
1908 {
1909 xc_cache[colLookup].pixel = colLookup;
1910 xc_cache[colLookup].red = xc_cache[colLookup].green =
1911 xc_cache[colLookup].blue = 0;
1912 xc_cache[colLookup].flags = 0;
1913 XQueryColor(g_display,
1914 DefaultColormap(g_display,
1915 DefaultScreen(g_display)),
1916 &xc_cache[colLookup]);
1917 }
1918 colLookup = 0;
1919
1920 /* approximate the pixel */
1921 while (j--)
1922 {
1923 if (xc_cache[j].flags)
1924 {
1925 nDist = ((long) (xc_cache[j].red >> 8) -
1926 (long) (xentry.red >> 8)) *
1927 ((long) (xc_cache[j].red >> 8) -
1928 (long) (xentry.red >> 8)) +
1929 ((long) (xc_cache[j].green >> 8) -
1930 (long) (xentry.green >> 8)) *
1931 ((long) (xc_cache[j].green >> 8) -
1932 (long) (xentry.green >> 8)) +
1933 ((long) (xc_cache[j].blue >> 8) -
1934 (long) (xentry.blue >> 8)) *
1935 ((long) (xc_cache[j].blue >> 8) -
1936 (long) (xentry.blue >> 8));
1937 }
1938 if (nDist < nMinDist)
1939 {
1940 nMinDist = nDist;
1941 xentry.pixel = j;
1942 }
1943 }
1944 }
1945 colour = xentry.pixel;
1946
1947 /* update our cache */
1948 if (xentry.pixel < 256)
1949 {
1950 xc_cache[xentry.pixel].red = xentry.red;
1951 xc_cache[xentry.pixel].green = xentry.green;
1952 xc_cache[xentry.pixel].blue = xentry.blue;
1953
1954 }
1955
1956 map[i] = colour;
1957 }
1958 return map;
1959 }
1960 else
1961 {
1962 XColor *xcolours, *xentry;
1963 Colormap map;
1964
1965 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1966 for (i = 0; i < ncolours; i++)
1967 {
1968 entry = &colours->colours[i];
1969 xentry = &xcolours[i];
1970 xentry->pixel = i;
1971 MAKE_XCOLOR(xentry, entry);
1972 }
1973
1974 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1975 XStoreColors(g_display, map, xcolours, ncolours);
1976
1977 xfree(xcolours);
1978 return (HCOLOURMAP) map;
1979 }
1980 }
1981
1982 void
1983 ui_destroy_colourmap(HCOLOURMAP map)
1984 {
1985 if (!g_owncolmap)
1986 xfree(map);
1987 else
1988 XFreeColormap(g_display, (Colormap) map);
1989 }
1990
1991 void
1992 ui_set_colourmap(HCOLOURMAP map)
1993 {
1994 if (!g_owncolmap)
1995 {
1996 if (g_colmap)
1997 xfree(g_colmap);
1998
1999 g_colmap = (uint32 *) map;
2000 }
2001 else
2002 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2003 }
2004
2005 void
2006 ui_set_clip(int x, int y, int cx, int cy)
2007 {
2008 XRectangle rect;
2009
2010 rect.x = x;
2011 rect.y = y;
2012 rect.width = cx;
2013 rect.height = cy;
2014 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2015 }
2016
2017 void
2018 ui_reset_clip(void)
2019 {
2020 XRectangle rect;
2021
2022 rect.x = 0;
2023 rect.y = 0;
2024 rect.width = g_width;
2025 rect.height = g_height;
2026 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2027 }
2028
2029 void
2030 ui_bell(void)
2031 {
2032 XBell(g_display, 0);
2033 }
2034
2035 void
2036 ui_destblt(uint8 opcode,
2037 /* dest */ int x, int y, int cx, int cy)
2038 {
2039 SET_FUNCTION(opcode);
2040 FILL_RECTANGLE(x, y, cx, cy);
2041 RESET_FUNCTION(opcode);
2042 }
2043
2044 static uint8 hatch_patterns[] = {
2045 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2046 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2047 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2048 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2049 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2050 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2051 };
2052
2053 void
2054 ui_patblt(uint8 opcode,
2055 /* dest */ int x, int y, int cx, int cy,
2056 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2057 {
2058 Pixmap fill;
2059 uint8 i, ipattern[8];
2060
2061 SET_FUNCTION(opcode);
2062
2063 switch (brush->style)
2064 {
2065 case 0: /* Solid */
2066 SET_FOREGROUND(fgcolour);
2067 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2068 break;
2069
2070 case 2: /* Hatch */
2071 fill = (Pixmap) ui_create_glyph(8, 8,
2072 hatch_patterns + brush->pattern[0] * 8);
2073 SET_FOREGROUND(fgcolour);
2074 SET_BACKGROUND(bgcolour);
2075 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2076 XSetStipple(g_display, g_gc, fill);
2077 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2078 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2079 XSetFillStyle(g_display, g_gc, FillSolid);
2080 XSetTSOrigin(g_display, g_gc, 0, 0);
2081 ui_destroy_glyph((HGLYPH) fill);
2082 break;
2083
2084 case 3: /* Pattern */
2085 for (i = 0; i != 8; i++)
2086 ipattern[7 - i] = brush->pattern[i];
2087 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2088 SET_FOREGROUND(bgcolour);
2089 SET_BACKGROUND(fgcolour);
2090 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2091 XSetStipple(g_display, g_gc, fill);
2092 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2093 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2094 XSetFillStyle(g_display, g_gc, FillSolid);
2095 XSetTSOrigin(g_display, g_gc, 0, 0);
2096 ui_destroy_glyph((HGLYPH) fill);
2097 break;
2098
2099 default:
2100 unimpl("brush %d\n", brush->style);
2101 }
2102
2103 RESET_FUNCTION(opcode);
2104
2105 if (g_ownbackstore)
2106 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2107 }
2108
2109 void
2110 ui_screenblt(uint8 opcode,
2111 /* dest */ int x, int y, int cx, int cy,
2112 /* src */ int srcx, int srcy)
2113 {
2114 SET_FUNCTION(opcode);
2115 if (g_ownbackstore)
2116 {
2117 if (g_Unobscured)
2118 {
2119 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2120 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2121 y);
2122 }
2123 else
2124 {
2125 XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2126 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2127 y);
2128 }
2129 }
2130 else
2131 {
2132 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2133 }
2134 RESET_FUNCTION(opcode);
2135 }
2136
2137 void
2138 ui_memblt(uint8 opcode,
2139 /* dest */ int x, int y, int cx, int cy,
2140 /* src */ HBITMAP src, int srcx, int srcy)
2141 {
2142 SET_FUNCTION(opcode);
2143 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2144 if (g_ownbackstore)
2145 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2146 RESET_FUNCTION(opcode);
2147 }
2148
2149 void
2150 ui_triblt(uint8 opcode,
2151 /* dest */ int x, int y, int cx, int cy,
2152 /* src */ HBITMAP src, int srcx, int srcy,
2153 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2154 {
2155 /* This is potentially difficult to do in general. Until someone
2156 comes up with a more efficient way of doing it I am using cases. */
2157
2158 switch (opcode)
2159 {
2160 case 0x69: /* PDSxxn */
2161 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2162 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2163 break;
2164
2165 case 0xb8: /* PSDPxax */
2166 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2167 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2168 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2169 break;
2170
2171 case 0xc0: /* PSa */
2172 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2173 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2174 break;
2175
2176 default:
2177 unimpl("triblt 0x%x\n", opcode);
2178 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2179 }
2180 }
2181
2182 void
2183 ui_line(uint8 opcode,
2184 /* dest */ int startx, int starty, int endx, int endy,
2185 /* pen */ PEN * pen)
2186 {
2187 SET_FUNCTION(opcode);
2188 SET_FOREGROUND(pen->colour);
2189 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2190 if (g_ownbackstore)
2191 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2192 RESET_FUNCTION(opcode);
2193 }
2194
2195 void
2196 ui_rect(
2197 /* dest */ int x, int y, int cx, int cy,
2198 /* brush */ int colour)
2199 {
2200 SET_FOREGROUND(colour);
2201 FILL_RECTANGLE(x, y, cx, cy);
2202 }
2203
2204 void
2205 ui_polygon(uint8 opcode,
2206 /* mode */ uint8 fillmode,
2207 /* dest */ POINT * point, int npoints,
2208 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2209 {
2210 uint8 style, i, ipattern[8];
2211 Pixmap fill;
2212
2213 SET_FUNCTION(opcode);
2214
2215 switch (fillmode)
2216 {
2217 case ALTERNATE:
2218 XSetFillRule(g_display, g_gc, EvenOddRule);
2219 break;
2220 case WINDING:
2221 XSetFillRule(g_display, g_gc, WindingRule);
2222 break;
2223 default:
2224 unimpl("fill mode %d\n", fillmode);
2225 }
2226
2227 if (brush)
2228 style = brush->style;
2229 else
2230 style = 0;
2231
2232 switch (style)
2233 {
2234 case 0: /* Solid */
2235 SET_FOREGROUND(fgcolour);
2236 FILL_POLYGON((XPoint *) point, npoints);
2237 break;
2238
2239 case 2: /* Hatch */
2240 fill = (Pixmap) ui_create_glyph(8, 8,
2241 hatch_patterns + brush->pattern[0] * 8);
2242 SET_FOREGROUND(fgcolour);
2243 SET_BACKGROUND(bgcolour);
2244 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2245 XSetStipple(g_display, g_gc, fill);
2246 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2247 FILL_POLYGON((XPoint *) point, npoints);
2248 XSetFillStyle(g_display, g_gc, FillSolid);
2249 XSetTSOrigin(g_display, g_gc, 0, 0);
2250 ui_destroy_glyph((HGLYPH) fill);
2251 break;
2252
2253 case 3: /* Pattern */
2254 for (i = 0; i != 8; i++)
2255 ipattern[7 - i] = brush->pattern[i];
2256 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2257 SET_FOREGROUND(bgcolour);
2258 SET_BACKGROUND(fgcolour);
2259 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2260 XSetStipple(g_display, g_gc, fill);
2261 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2262 FILL_POLYGON((XPoint *) point, npoints);
2263 XSetFillStyle(g_display, g_gc, FillSolid);
2264 XSetTSOrigin(g_display, g_gc, 0, 0);
2265 ui_destroy_glyph((HGLYPH) fill);
2266 break;
2267
2268 default:
2269 unimpl("brush %d\n", brush->style);
2270 }
2271
2272 RESET_FUNCTION(opcode);
2273 }
2274
2275 void
2276 ui_polyline(uint8 opcode,
2277 /* dest */ POINT * points, int npoints,
2278 /* pen */ PEN * pen)
2279 {
2280 /* TODO: set join style */
2281 SET_FUNCTION(opcode);
2282 SET_FOREGROUND(pen->colour);
2283 XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2284 if (g_ownbackstore)
2285 XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2286 CoordModePrevious);
2287 RESET_FUNCTION(opcode);
2288 }
2289
2290 void
2291 ui_ellipse(uint8 opcode,
2292 /* mode */ uint8 fillmode,
2293 /* dest */ int x, int y, int cx, int cy,
2294 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2295 {
2296 uint8 style, i, ipattern[8];
2297 Pixmap fill;
2298
2299 SET_FUNCTION(opcode);
2300
2301 if (brush)
2302 style = brush->style;
2303 else
2304 style = 0;
2305
2306 switch (style)
2307 {
2308 case 0: /* Solid */
2309 SET_FOREGROUND(fgcolour);
2310 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2311 break;
2312
2313 case 2: /* Hatch */
2314 fill = (Pixmap) ui_create_glyph(8, 8,
2315 hatch_patterns + brush->pattern[0] * 8);
2316 SET_FOREGROUND(fgcolour);
2317 SET_BACKGROUND(bgcolour);
2318 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2319 XSetStipple(g_display, g_gc, fill);
2320 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2321 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2322 XSetFillStyle(g_display, g_gc, FillSolid);
2323 XSetTSOrigin(g_display, g_gc, 0, 0);
2324 ui_destroy_glyph((HGLYPH) fill);
2325 break;
2326
2327 case 3: /* Pattern */
2328 for (i = 0; i != 8; i++)
2329 ipattern[7 - i] = brush->pattern[i];
2330 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2331 SET_FOREGROUND(bgcolour);
2332 SET_BACKGROUND(fgcolour);
2333 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2334 XSetStipple(g_display, g_gc, fill);
2335 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2336 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2337 XSetFillStyle(g_display, g_gc, FillSolid);
2338 XSetTSOrigin(g_display, g_gc, 0, 0);
2339 ui_destroy_glyph((HGLYPH) fill);
2340 break;
2341
2342 default:
2343 unimpl("brush %d\n", brush->style);
2344 }
2345
2346 RESET_FUNCTION(opcode);
2347 }
2348
2349 /* warning, this function only draws on wnd or backstore, not both */
2350 void
2351 ui_draw_glyph(int mixmode,
2352 /* dest */ int x, int y, int cx, int cy,
2353 /* src */ HGLYPH glyph, int srcx, int srcy,
2354 int bgcolour, int fgcolour)
2355 {
2356 SET_FOREGROUND(fgcolour);
2357 SET_BACKGROUND(bgcolour);
2358
2359 XSetFillStyle(g_display, g_gc,
2360 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2361 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2362 XSetTSOrigin(g_display, g_gc, x, y);
2363
2364 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2365
2366 XSetFillStyle(g_display, g_gc, FillSolid);
2367 }
2368
2369 #define DO_GLYPH(ttext,idx) \
2370 {\
2371 glyph = cache_get_font (font, ttext[idx]);\
2372 if (!(flags & TEXT2_IMPLICIT_X))\
2373 {\
2374 xyoffset = ttext[++idx];\
2375 if ((xyoffset & 0x80))\
2376 {\
2377 if (flags & TEXT2_VERTICAL)\
2378 y += ttext[idx+1] | (ttext[idx+2] << 8);\
2379 else\
2380 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2381 idx += 2;\
2382 }\
2383 else\
2384 {\
2385 if (flags & TEXT2_VERTICAL)\
2386 y += xyoffset;\
2387 else\
2388 x += xyoffset;\
2389 }\
2390 }\
2391 if (glyph != NULL)\
2392 {\
2393 x1 = x + glyph->offset;\
2394 y1 = y + glyph->baseline;\
2395 XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2396 XSetTSOrigin(g_display, g_gc, x1, y1);\
2397 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2398 if (flags & TEXT2_IMPLICIT_X)\
2399 x += glyph->width;\
2400 }\
2401 }
2402
2403 void
2404 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2405 int clipx, int clipy, int clipcx, int clipcy,
2406 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2407 int bgcolour, int fgcolour, uint8 * text, uint8 length)
2408 {
2409 /* TODO: use brush appropriately */
2410
2411 FONTGLYPH *glyph;
2412 int i, j, xyoffset, x1, y1;
2413 DATABLOB *entry;
2414
2415 SET_FOREGROUND(bgcolour);
2416
2417 /* Sometimes, the boxcx value is something really large, like
2418 32691. This makes XCopyArea fail with Xvnc. The code below
2419 is a quick fix. */
2420 if (boxx + boxcx > g_width)
2421 boxcx = g_width - boxx;
2422
2423 if (boxcx > 1)
2424 {
2425 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2426 }
2427 else if (mixmode == MIX_OPAQUE)
2428 {
2429 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2430 }
2431
2432 SET_FOREGROUND(fgcolour);
2433 SET_BACKGROUND(bgcolour);
2434 XSetFillStyle(g_display, g_gc, FillStippled);
2435
2436 /* Paint text, character by character */
2437 for (i = 0; i < length;)
2438 {
2439 switch (text[i])
2440 {
2441 case 0xff:
2442 if (i + 2 < length)
2443 cache_put_text(text[i + 1], text, text[i + 2]);
2444 else
2445 {
2446 error("this shouldn't be happening\n");
2447 exit(1);
2448 }
2449 /* this will move pointer from start to first character after FF command */
2450 length -= i + 3;
2451 text = &(text[i + 3]);
2452 i = 0;
2453 break;
2454
2455 case 0xfe:
2456 entry = cache_get_text(text[i + 1]);
2457 if (entry != NULL)
2458 {
2459 if ((((uint8 *) (entry->data))[1] ==
2460 0) && (!(flags & TEXT2_IMPLICIT_X)))
2461 {
2462 if (flags & TEXT2_VERTICAL)
2463 y += text[i + 2];
2464 else
2465 x += text[i + 2];
2466 }
2467 for (j = 0; j < entry->size; j++)
2468 DO_GLYPH(((uint8 *) (entry->data)), j);
2469 }
2470 if (i + 2 < length)
2471 i += 3;
2472 else
2473 i += 2;
2474 length -= i;
2475 /* this will move pointer from start to first character after FE command */
2476 text = &(text[i]);
2477 i = 0;
2478 break;
2479
2480 default:
2481 DO_GLYPH(text, i);
2482 i++;
2483 break;
2484 }
2485 }
2486
2487 XSetFillStyle(g_display, g_gc, FillSolid);
2488
2489 if (g_ownbackstore)
2490 {
2491 if (boxcx > 1)
2492 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2493 boxy, boxcx, boxcy, boxx, boxy);
2494 else
2495 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2496 clipy, clipcx, clipcy, clipx, clipy);
2497 }
2498 }
2499
2500 void
2501 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2502 {
2503 Pixmap pix;
2504 XImage *image;
2505
2506 if (g_ownbackstore)
2507 {
2508 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2509 }
2510 else
2511 {
2512 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2513 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2514 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2515 XFreePixmap(g_display, pix);
2516 }
2517
2518 offset *= g_bpp / 8;
2519 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2520
2521 XDestroyImage(image);
2522 }
2523
2524 void
2525 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2526 {
2527 XImage *image;
2528 uint8 *data;
2529
2530 offset *= g_bpp / 8;
2531 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2532 if (data == NULL)
2533 return;
2534
2535 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2536 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2537
2538 if (g_ownbackstore)
2539 {
2540 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2541 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2542 }
2543 else
2544 {
2545 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2546 }
2547
2548 XFree(image);
2549 }
2550
2551 /* these do nothing here but are used in uiports */
2552 void
2553 ui_begin_update(void)
2554 {
2555 }
2556
2557 void
2558 ui_end_update(void)
2559 {
2560 }

  ViewVC Help
Powered by ViewVC 1.1.26