/[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 976 - (show annotations)
Thu Aug 4 13:39:57 2005 UTC (18 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 56471 byte(s)
Protection against recursive sequences

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 | StructureNotifyMask;
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 char str[256];
1354 Status status;
1355 int events = 0;
1356
1357 while ((XPending(g_display) > 0) && events++ < 20)
1358 {
1359 XNextEvent(g_display, &xevent);
1360
1361 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1362 {
1363 DEBUG_KBD(("Filtering event\n"));
1364 continue;
1365 }
1366
1367 flags = 0;
1368
1369 switch (xevent.type)
1370 {
1371 case VisibilityNotify:
1372 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1373 break;
1374 case ClientMessage:
1375 /* the window manager told us to quit */
1376 if ((xevent.xclient.message_type == g_protocol_atom)
1377 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1378 /* Quit */
1379 return 0;
1380 break;
1381
1382 case KeyPress:
1383 g_last_gesturetime = xevent.xkey.time;
1384 if (g_IC != NULL)
1385 /* Multi_key compatible version */
1386 {
1387 XmbLookupString(g_IC,
1388 &xevent.xkey, str, sizeof(str), &keysym,
1389 &status);
1390 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1391 {
1392 error("XmbLookupString failed with status 0x%x\n",
1393 status);
1394 break;
1395 }
1396 }
1397 else
1398 {
1399 /* Plain old XLookupString */
1400 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1401 XLookupString((XKeyEvent *) & xevent,
1402 str, sizeof(str), &keysym, NULL);
1403 }
1404
1405 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1406 get_ksname(keysym)));
1407
1408 ev_time = time(NULL);
1409 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1410 break;
1411
1412 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1413 ev_time, True, 0);
1414 break;
1415
1416 case KeyRelease:
1417 g_last_gesturetime = xevent.xkey.time;
1418 XLookupString((XKeyEvent *) & xevent, str,
1419 sizeof(str), &keysym, NULL);
1420
1421 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1422 get_ksname(keysym)));
1423
1424 ev_time = time(NULL);
1425 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1426 break;
1427
1428 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1429 ev_time, False, 0);
1430 break;
1431
1432 case ButtonPress:
1433 flags = MOUSE_FLAG_DOWN;
1434 /* fall through */
1435
1436 case ButtonRelease:
1437 g_last_gesturetime = xevent.xbutton.time;
1438 button = xkeymap_translate_button(xevent.xbutton.button);
1439 if (button == 0)
1440 break;
1441
1442 /* If win_button_size is nonzero, enable single app mode */
1443 if (xevent.xbutton.y < g_win_button_size)
1444 {
1445 /* Stop moving window when button is released, regardless of cursor position */
1446 if (g_moving_wnd && (xevent.type == ButtonRelease))
1447 g_moving_wnd = False;
1448
1449 /* Check from right to left: */
1450
1451 if (xevent.xbutton.x >= g_width - g_win_button_size)
1452 {
1453 /* The close button, continue */
1454 ;
1455 }
1456 else if (xevent.xbutton.x >=
1457 g_width - g_win_button_size * 2)
1458 {
1459 /* The maximize/restore button. Do not send to
1460 server. It might be a good idea to change the
1461 cursor or give some other visible indication
1462 that rdesktop inhibited this click */
1463 break;
1464 }
1465 else if (xevent.xbutton.x >=
1466 g_width - g_win_button_size * 3)
1467 {
1468 /* The minimize button. Iconify window. */
1469 XIconifyWindow(g_display, g_wnd,
1470 DefaultScreen(g_display));
1471 break;
1472 }
1473 else if (xevent.xbutton.x <= g_win_button_size)
1474 {
1475 /* The system menu. Ignore. */
1476 break;
1477 }
1478 else
1479 {
1480 /* The title bar. */
1481 if ((xevent.type == ButtonPress) && !g_fullscreen
1482 && g_hide_decorations)
1483 {
1484 g_moving_wnd = True;
1485 g_move_x_offset = xevent.xbutton.x;
1486 g_move_y_offset = xevent.xbutton.y;
1487 }
1488 break;
1489
1490 }
1491 }
1492
1493 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1494 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1495 break;
1496
1497 case MotionNotify:
1498 if (g_moving_wnd)
1499 {
1500 XMoveWindow(g_display, g_wnd,
1501 xevent.xmotion.x_root - g_move_x_offset,
1502 xevent.xmotion.y_root - g_move_y_offset);
1503 break;
1504 }
1505
1506 if (g_fullscreen && !g_focused)
1507 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1508 CurrentTime);
1509 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1510 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1511 break;
1512
1513 case FocusIn:
1514 if (xevent.xfocus.mode == NotifyGrab)
1515 break;
1516 g_focused = True;
1517 reset_modifier_keys();
1518 if (g_grab_keyboard && g_mouse_in_wnd)
1519 XGrabKeyboard(g_display, g_wnd, True,
1520 GrabModeAsync, GrabModeAsync, CurrentTime);
1521 break;
1522
1523 case FocusOut:
1524 if (xevent.xfocus.mode == NotifyUngrab)
1525 break;
1526 g_focused = False;
1527 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1528 XUngrabKeyboard(g_display, CurrentTime);
1529 break;
1530
1531 case EnterNotify:
1532 /* we only register for this event when in fullscreen mode */
1533 /* or grab_keyboard */
1534 g_mouse_in_wnd = True;
1535 if (g_fullscreen)
1536 {
1537 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1538 CurrentTime);
1539 break;
1540 }
1541 if (g_focused)
1542 XGrabKeyboard(g_display, g_wnd, True,
1543 GrabModeAsync, GrabModeAsync, CurrentTime);
1544 break;
1545
1546 case LeaveNotify:
1547 /* we only register for this event when grab_keyboard */
1548 g_mouse_in_wnd = False;
1549 XUngrabKeyboard(g_display, CurrentTime);
1550 break;
1551
1552 case Expose:
1553 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1554 xevent.xexpose.x, xevent.xexpose.y,
1555 xevent.xexpose.width,
1556 xevent.xexpose.height,
1557 xevent.xexpose.x, xevent.xexpose.y);
1558 break;
1559
1560 case MappingNotify:
1561 /* Refresh keyboard mapping if it has changed. This is important for
1562 Xvnc, since it allocates keycodes dynamically */
1563 if (xevent.xmapping.request == MappingKeyboard
1564 || xevent.xmapping.request == MappingModifier)
1565 XRefreshKeyboardMapping(&xevent.xmapping);
1566
1567 if (xevent.xmapping.request == MappingModifier)
1568 {
1569 XFreeModifiermap(g_mod_map);
1570 g_mod_map = XGetModifierMapping(g_display);
1571 }
1572 break;
1573
1574 /* clipboard stuff */
1575 case SelectionNotify:
1576 xclip_handle_SelectionNotify(&xevent.xselection);
1577 break;
1578 case SelectionRequest:
1579 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1580 break;
1581 case SelectionClear:
1582 xclip_handle_SelectionClear();
1583 break;
1584 case PropertyNotify:
1585 xclip_handle_PropertyNotify(&xevent.xproperty);
1586 break;
1587 case MapNotify:
1588 rdp_send_client_window_status(1);
1589 break;
1590 case UnmapNotify:
1591 rdp_send_client_window_status(0);
1592 break;
1593 }
1594 }
1595 /* Keep going */
1596 return 1;
1597 }
1598
1599 /* Returns 0 after user quit, 1 otherwise */
1600 int
1601 ui_select(int rdp_socket)
1602 {
1603 int n;
1604 fd_set rfds, wfds;
1605 struct timeval tv;
1606 BOOL s_timeout = False;
1607
1608 while (True)
1609 {
1610 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1611 /* Process any events already waiting */
1612 if (!xwin_process_events())
1613 /* User quit */
1614 return 0;
1615
1616 FD_ZERO(&rfds);
1617 FD_ZERO(&wfds);
1618 FD_SET(rdp_socket, &rfds);
1619 FD_SET(g_x_socket, &rfds);
1620
1621 #ifdef WITH_RDPSND
1622 /* FIXME: there should be an API for registering fds */
1623 if (g_dsp_busy)
1624 {
1625 FD_SET(g_dsp_fd, &wfds);
1626 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1627 }
1628 #endif
1629 /* default timeout */
1630 tv.tv_sec = 60;
1631 tv.tv_usec = 0;
1632
1633 /* add redirection handles */
1634 rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1635
1636 n++;
1637
1638 switch (select(n, &rfds, &wfds, NULL, &tv))
1639 {
1640 case -1:
1641 error("select: %s\n", strerror(errno));
1642
1643 case 0:
1644 /* Abort serial read calls */
1645 if (s_timeout)
1646 rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1647 continue;
1648 }
1649
1650 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1651
1652 if (FD_ISSET(rdp_socket, &rfds))
1653 return 1;
1654
1655 #ifdef WITH_RDPSND
1656 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1657 wave_out_play();
1658 #endif
1659 }
1660 }
1661
1662 void
1663 ui_move_pointer(int x, int y)
1664 {
1665 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1666 }
1667
1668 HBITMAP
1669 ui_create_bitmap(int width, int height, uint8 * data)
1670 {
1671 XImage *image;
1672 Pixmap bitmap;
1673 uint8 *tdata;
1674 int bitmap_pad;
1675
1676 if (g_server_bpp == 8)
1677 {
1678 bitmap_pad = 8;
1679 }
1680 else
1681 {
1682 bitmap_pad = g_bpp;
1683
1684 if (g_bpp == 24)
1685 bitmap_pad = 32;
1686 }
1687
1688 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1689 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1690 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1691 (char *) tdata, width, height, bitmap_pad, 0);
1692
1693 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1694
1695 XFree(image);
1696 if (tdata != data)
1697 xfree(tdata);
1698 return (HBITMAP) bitmap;
1699 }
1700
1701 void
1702 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1703 {
1704 XImage *image;
1705 uint8 *tdata;
1706 int bitmap_pad;
1707
1708 if (g_server_bpp == 8)
1709 {
1710 bitmap_pad = 8;
1711 }
1712 else
1713 {
1714 bitmap_pad = g_bpp;
1715
1716 if (g_bpp == 24)
1717 bitmap_pad = 32;
1718 }
1719
1720 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1721 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1722 (char *) tdata, width, height, bitmap_pad, 0);
1723
1724 if (g_ownbackstore)
1725 {
1726 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1727 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1728 }
1729 else
1730 {
1731 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1732 }
1733
1734 XFree(image);
1735 if (tdata != data)
1736 xfree(tdata);
1737 }
1738
1739 void
1740 ui_destroy_bitmap(HBITMAP bmp)
1741 {
1742 XFreePixmap(g_display, (Pixmap) bmp);
1743 }
1744
1745 HGLYPH
1746 ui_create_glyph(int width, int height, uint8 * data)
1747 {
1748 XImage *image;
1749 Pixmap bitmap;
1750 int scanline;
1751
1752 scanline = (width + 7) / 8;
1753
1754 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1755 if (g_create_glyph_gc == 0)
1756 g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1757
1758 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1759 width, height, 8, scanline);
1760 image->byte_order = MSBFirst;
1761 image->bitmap_bit_order = MSBFirst;
1762 XInitImage(image);
1763
1764 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1765
1766 XFree(image);
1767 return (HGLYPH) bitmap;
1768 }
1769
1770 void
1771 ui_destroy_glyph(HGLYPH glyph)
1772 {
1773 XFreePixmap(g_display, (Pixmap) glyph);
1774 }
1775
1776 HCURSOR
1777 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1778 uint8 * andmask, uint8 * xormask)
1779 {
1780 HGLYPH maskglyph, cursorglyph;
1781 XColor bg, fg;
1782 Cursor xcursor;
1783 uint8 *cursor, *pcursor;
1784 uint8 *mask, *pmask;
1785 uint8 nextbit;
1786 int scanline, offset;
1787 int i, j;
1788
1789 scanline = (width + 7) / 8;
1790 offset = scanline * height;
1791
1792 cursor = (uint8 *) xmalloc(offset);
1793 memset(cursor, 0, offset);
1794
1795 mask = (uint8 *) xmalloc(offset);
1796 memset(mask, 0, offset);
1797
1798 /* approximate AND and XOR masks with a monochrome X pointer */
1799 for (i = 0; i < height; i++)
1800 {
1801 offset -= scanline;
1802 pcursor = &cursor[offset];
1803 pmask = &mask[offset];
1804
1805 for (j = 0; j < scanline; j++)
1806 {
1807 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1808 {
1809 if (xormask[0] || xormask[1] || xormask[2])
1810 {
1811 *pcursor |= (~(*andmask) & nextbit);
1812 *pmask |= nextbit;
1813 }
1814 else
1815 {
1816 *pcursor |= ((*andmask) & nextbit);
1817 *pmask |= (~(*andmask) & nextbit);
1818 }
1819
1820 xormask += 3;
1821 }
1822
1823 andmask++;
1824 pcursor++;
1825 pmask++;
1826 }
1827 }
1828
1829 fg.red = fg.blue = fg.green = 0xffff;
1830 bg.red = bg.blue = bg.green = 0x0000;
1831 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1832
1833 cursorglyph = ui_create_glyph(width, height, cursor);
1834 maskglyph = ui_create_glyph(width, height, mask);
1835
1836 xcursor =
1837 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1838 (Pixmap) maskglyph, &fg, &bg, x, y);
1839
1840 ui_destroy_glyph(maskglyph);
1841 ui_destroy_glyph(cursorglyph);
1842 xfree(mask);
1843 xfree(cursor);
1844 return (HCURSOR) xcursor;
1845 }
1846
1847 void
1848 ui_set_cursor(HCURSOR cursor)
1849 {
1850 g_current_cursor = (Cursor) cursor;
1851 XDefineCursor(g_display, g_wnd, g_current_cursor);
1852 }
1853
1854 void
1855 ui_destroy_cursor(HCURSOR cursor)
1856 {
1857 XFreeCursor(g_display, (Cursor) cursor);
1858 }
1859
1860 void
1861 ui_set_null_cursor(void)
1862 {
1863 ui_set_cursor(g_null_cursor);
1864 }
1865
1866 #define MAKE_XCOLOR(xc,c) \
1867 (xc)->red = ((c)->red << 8) | (c)->red; \
1868 (xc)->green = ((c)->green << 8) | (c)->green; \
1869 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1870 (xc)->flags = DoRed | DoGreen | DoBlue;
1871
1872
1873 HCOLOURMAP
1874 ui_create_colourmap(COLOURMAP * colours)
1875 {
1876 COLOURENTRY *entry;
1877 int i, ncolours = colours->ncolours;
1878 if (!g_owncolmap)
1879 {
1880 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1881 XColor xentry;
1882 XColor xc_cache[256];
1883 uint32 colour;
1884 int colLookup = 256;
1885 for (i = 0; i < ncolours; i++)
1886 {
1887 entry = &colours->colours[i];
1888 MAKE_XCOLOR(&xentry, entry);
1889
1890 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1891 {
1892 /* Allocation failed, find closest match. */
1893 int j = 256;
1894 int nMinDist = 3 * 256 * 256;
1895 long nDist = nMinDist;
1896
1897 /* only get the colors once */
1898 while (colLookup--)
1899 {
1900 xc_cache[colLookup].pixel = colLookup;
1901 xc_cache[colLookup].red = xc_cache[colLookup].green =
1902 xc_cache[colLookup].blue = 0;
1903 xc_cache[colLookup].flags = 0;
1904 XQueryColor(g_display,
1905 DefaultColormap(g_display,
1906 DefaultScreen(g_display)),
1907 &xc_cache[colLookup]);
1908 }
1909 colLookup = 0;
1910
1911 /* approximate the pixel */
1912 while (j--)
1913 {
1914 if (xc_cache[j].flags)
1915 {
1916 nDist = ((long) (xc_cache[j].red >> 8) -
1917 (long) (xentry.red >> 8)) *
1918 ((long) (xc_cache[j].red >> 8) -
1919 (long) (xentry.red >> 8)) +
1920 ((long) (xc_cache[j].green >> 8) -
1921 (long) (xentry.green >> 8)) *
1922 ((long) (xc_cache[j].green >> 8) -
1923 (long) (xentry.green >> 8)) +
1924 ((long) (xc_cache[j].blue >> 8) -
1925 (long) (xentry.blue >> 8)) *
1926 ((long) (xc_cache[j].blue >> 8) -
1927 (long) (xentry.blue >> 8));
1928 }
1929 if (nDist < nMinDist)
1930 {
1931 nMinDist = nDist;
1932 xentry.pixel = j;
1933 }
1934 }
1935 }
1936 colour = xentry.pixel;
1937
1938 /* update our cache */
1939 if (xentry.pixel < 256)
1940 {
1941 xc_cache[xentry.pixel].red = xentry.red;
1942 xc_cache[xentry.pixel].green = xentry.green;
1943 xc_cache[xentry.pixel].blue = xentry.blue;
1944
1945 }
1946
1947 map[i] = colour;
1948 }
1949 return map;
1950 }
1951 else
1952 {
1953 XColor *xcolours, *xentry;
1954 Colormap map;
1955
1956 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1957 for (i = 0; i < ncolours; i++)
1958 {
1959 entry = &colours->colours[i];
1960 xentry = &xcolours[i];
1961 xentry->pixel = i;
1962 MAKE_XCOLOR(xentry, entry);
1963 }
1964
1965 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1966 XStoreColors(g_display, map, xcolours, ncolours);
1967
1968 xfree(xcolours);
1969 return (HCOLOURMAP) map;
1970 }
1971 }
1972
1973 void
1974 ui_destroy_colourmap(HCOLOURMAP map)
1975 {
1976 if (!g_owncolmap)
1977 xfree(map);
1978 else
1979 XFreeColormap(g_display, (Colormap) map);
1980 }
1981
1982 void
1983 ui_set_colourmap(HCOLOURMAP map)
1984 {
1985 if (!g_owncolmap)
1986 {
1987 if (g_colmap)
1988 xfree(g_colmap);
1989
1990 g_colmap = (uint32 *) map;
1991 }
1992 else
1993 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1994 }
1995
1996 void
1997 ui_set_clip(int x, int y, int cx, int cy)
1998 {
1999 XRectangle rect;
2000
2001 rect.x = x;
2002 rect.y = y;
2003 rect.width = cx;
2004 rect.height = cy;
2005 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2006 }
2007
2008 void
2009 ui_reset_clip(void)
2010 {
2011 XRectangle rect;
2012
2013 rect.x = 0;
2014 rect.y = 0;
2015 rect.width = g_width;
2016 rect.height = g_height;
2017 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2018 }
2019
2020 void
2021 ui_bell(void)
2022 {
2023 XBell(g_display, 0);
2024 }
2025
2026 void
2027 ui_destblt(uint8 opcode,
2028 /* dest */ int x, int y, int cx, int cy)
2029 {
2030 SET_FUNCTION(opcode);
2031 FILL_RECTANGLE(x, y, cx, cy);
2032 RESET_FUNCTION(opcode);
2033 }
2034
2035 static uint8 hatch_patterns[] = {
2036 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2037 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2038 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2039 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2040 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2041 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2042 };
2043
2044 void
2045 ui_patblt(uint8 opcode,
2046 /* dest */ int x, int y, int cx, int cy,
2047 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2048 {
2049 Pixmap fill;
2050 uint8 i, ipattern[8];
2051
2052 SET_FUNCTION(opcode);
2053
2054 switch (brush->style)
2055 {
2056 case 0: /* Solid */
2057 SET_FOREGROUND(fgcolour);
2058 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2059 break;
2060
2061 case 2: /* Hatch */
2062 fill = (Pixmap) ui_create_glyph(8, 8,
2063 hatch_patterns + brush->pattern[0] * 8);
2064 SET_FOREGROUND(fgcolour);
2065 SET_BACKGROUND(bgcolour);
2066 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2067 XSetStipple(g_display, g_gc, fill);
2068 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2069 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2070 XSetFillStyle(g_display, g_gc, FillSolid);
2071 XSetTSOrigin(g_display, g_gc, 0, 0);
2072 ui_destroy_glyph((HGLYPH) fill);
2073 break;
2074
2075 case 3: /* Pattern */
2076 for (i = 0; i != 8; i++)
2077 ipattern[7 - i] = brush->pattern[i];
2078 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2079 SET_FOREGROUND(bgcolour);
2080 SET_BACKGROUND(fgcolour);
2081 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2082 XSetStipple(g_display, g_gc, fill);
2083 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2084 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2085 XSetFillStyle(g_display, g_gc, FillSolid);
2086 XSetTSOrigin(g_display, g_gc, 0, 0);
2087 ui_destroy_glyph((HGLYPH) fill);
2088 break;
2089
2090 default:
2091 unimpl("brush %d\n", brush->style);
2092 }
2093
2094 RESET_FUNCTION(opcode);
2095
2096 if (g_ownbackstore)
2097 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2098 }
2099
2100 void
2101 ui_screenblt(uint8 opcode,
2102 /* dest */ int x, int y, int cx, int cy,
2103 /* src */ int srcx, int srcy)
2104 {
2105 SET_FUNCTION(opcode);
2106 if (g_ownbackstore)
2107 {
2108 if (g_Unobscured)
2109 {
2110 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2111 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2112 y);
2113 }
2114 else
2115 {
2116 XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2117 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2118 y);
2119 }
2120 }
2121 else
2122 {
2123 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2124 }
2125 RESET_FUNCTION(opcode);
2126 }
2127
2128 void
2129 ui_memblt(uint8 opcode,
2130 /* dest */ int x, int y, int cx, int cy,
2131 /* src */ HBITMAP src, int srcx, int srcy)
2132 {
2133 SET_FUNCTION(opcode);
2134 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2135 if (g_ownbackstore)
2136 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2137 RESET_FUNCTION(opcode);
2138 }
2139
2140 void
2141 ui_triblt(uint8 opcode,
2142 /* dest */ int x, int y, int cx, int cy,
2143 /* src */ HBITMAP src, int srcx, int srcy,
2144 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2145 {
2146 /* This is potentially difficult to do in general. Until someone
2147 comes up with a more efficient way of doing it I am using cases. */
2148
2149 switch (opcode)
2150 {
2151 case 0x69: /* PDSxxn */
2152 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2153 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2154 break;
2155
2156 case 0xb8: /* PSDPxax */
2157 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2158 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2159 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2160 break;
2161
2162 case 0xc0: /* PSa */
2163 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2164 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2165 break;
2166
2167 default:
2168 unimpl("triblt 0x%x\n", opcode);
2169 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2170 }
2171 }
2172
2173 void
2174 ui_line(uint8 opcode,
2175 /* dest */ int startx, int starty, int endx, int endy,
2176 /* pen */ PEN * pen)
2177 {
2178 SET_FUNCTION(opcode);
2179 SET_FOREGROUND(pen->colour);
2180 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2181 if (g_ownbackstore)
2182 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2183 RESET_FUNCTION(opcode);
2184 }
2185
2186 void
2187 ui_rect(
2188 /* dest */ int x, int y, int cx, int cy,
2189 /* brush */ int colour)
2190 {
2191 SET_FOREGROUND(colour);
2192 FILL_RECTANGLE(x, y, cx, cy);
2193 }
2194
2195 void
2196 ui_polygon(uint8 opcode,
2197 /* mode */ uint8 fillmode,
2198 /* dest */ POINT * point, int npoints,
2199 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2200 {
2201 uint8 style, i, ipattern[8];
2202 Pixmap fill;
2203
2204 SET_FUNCTION(opcode);
2205
2206 switch (fillmode)
2207 {
2208 case ALTERNATE:
2209 XSetFillRule(g_display, g_gc, EvenOddRule);
2210 break;
2211 case WINDING:
2212 XSetFillRule(g_display, g_gc, WindingRule);
2213 break;
2214 default:
2215 unimpl("fill mode %d\n", fillmode);
2216 }
2217
2218 if (brush)
2219 style = brush->style;
2220 else
2221 style = 0;
2222
2223 switch (style)
2224 {
2225 case 0: /* Solid */
2226 SET_FOREGROUND(fgcolour);
2227 FILL_POLYGON((XPoint *) point, npoints);
2228 break;
2229
2230 case 2: /* Hatch */
2231 fill = (Pixmap) ui_create_glyph(8, 8,
2232 hatch_patterns + brush->pattern[0] * 8);
2233 SET_FOREGROUND(fgcolour);
2234 SET_BACKGROUND(bgcolour);
2235 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2236 XSetStipple(g_display, g_gc, fill);
2237 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2238 FILL_POLYGON((XPoint *) point, npoints);
2239 XSetFillStyle(g_display, g_gc, FillSolid);
2240 XSetTSOrigin(g_display, g_gc, 0, 0);
2241 ui_destroy_glyph((HGLYPH) fill);
2242 break;
2243
2244 case 3: /* Pattern */
2245 for (i = 0; i != 8; i++)
2246 ipattern[7 - i] = brush->pattern[i];
2247 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2248 SET_FOREGROUND(bgcolour);
2249 SET_BACKGROUND(fgcolour);
2250 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2251 XSetStipple(g_display, g_gc, fill);
2252 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2253 FILL_POLYGON((XPoint *) point, npoints);
2254 XSetFillStyle(g_display, g_gc, FillSolid);
2255 XSetTSOrigin(g_display, g_gc, 0, 0);
2256 ui_destroy_glyph((HGLYPH) fill);
2257 break;
2258
2259 default:
2260 unimpl("brush %d\n", brush->style);
2261 }
2262
2263 RESET_FUNCTION(opcode);
2264 }
2265
2266 void
2267 ui_polyline(uint8 opcode,
2268 /* dest */ POINT * points, int npoints,
2269 /* pen */ PEN * pen)
2270 {
2271 /* TODO: set join style */
2272 SET_FUNCTION(opcode);
2273 SET_FOREGROUND(pen->colour);
2274 XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2275 if (g_ownbackstore)
2276 XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2277 CoordModePrevious);
2278 RESET_FUNCTION(opcode);
2279 }
2280
2281 void
2282 ui_ellipse(uint8 opcode,
2283 /* mode */ uint8 fillmode,
2284 /* dest */ int x, int y, int cx, int cy,
2285 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2286 {
2287 uint8 style, i, ipattern[8];
2288 Pixmap fill;
2289
2290 SET_FUNCTION(opcode);
2291
2292 if (brush)
2293 style = brush->style;
2294 else
2295 style = 0;
2296
2297 switch (style)
2298 {
2299 case 0: /* Solid */
2300 SET_FOREGROUND(fgcolour);
2301 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2302 break;
2303
2304 case 2: /* Hatch */
2305 fill = (Pixmap) ui_create_glyph(8, 8,
2306 hatch_patterns + brush->pattern[0] * 8);
2307 SET_FOREGROUND(fgcolour);
2308 SET_BACKGROUND(bgcolour);
2309 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2310 XSetStipple(g_display, g_gc, fill);
2311 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2312 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2313 XSetFillStyle(g_display, g_gc, FillSolid);
2314 XSetTSOrigin(g_display, g_gc, 0, 0);
2315 ui_destroy_glyph((HGLYPH) fill);
2316 break;
2317
2318 case 3: /* Pattern */
2319 for (i = 0; i != 8; i++)
2320 ipattern[7 - i] = brush->pattern[i];
2321 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2322 SET_FOREGROUND(bgcolour);
2323 SET_BACKGROUND(fgcolour);
2324 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2325 XSetStipple(g_display, g_gc, fill);
2326 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2327 DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2328 XSetFillStyle(g_display, g_gc, FillSolid);
2329 XSetTSOrigin(g_display, g_gc, 0, 0);
2330 ui_destroy_glyph((HGLYPH) fill);
2331 break;
2332
2333 default:
2334 unimpl("brush %d\n", brush->style);
2335 }
2336
2337 RESET_FUNCTION(opcode);
2338 }
2339
2340 /* warning, this function only draws on wnd or backstore, not both */
2341 void
2342 ui_draw_glyph(int mixmode,
2343 /* dest */ int x, int y, int cx, int cy,
2344 /* src */ HGLYPH glyph, int srcx, int srcy,
2345 int bgcolour, int fgcolour)
2346 {
2347 SET_FOREGROUND(fgcolour);
2348 SET_BACKGROUND(bgcolour);
2349
2350 XSetFillStyle(g_display, g_gc,
2351 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2352 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2353 XSetTSOrigin(g_display, g_gc, x, y);
2354
2355 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2356
2357 XSetFillStyle(g_display, g_gc, FillSolid);
2358 }
2359
2360 #define DO_GLYPH(ttext,idx) \
2361 {\
2362 glyph = cache_get_font (font, ttext[idx]);\
2363 if (!(flags & TEXT2_IMPLICIT_X))\
2364 {\
2365 xyoffset = ttext[++idx];\
2366 if ((xyoffset & 0x80))\
2367 {\
2368 if (flags & TEXT2_VERTICAL)\
2369 y += ttext[idx+1] | (ttext[idx+2] << 8);\
2370 else\
2371 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2372 idx += 2;\
2373 }\
2374 else\
2375 {\
2376 if (flags & TEXT2_VERTICAL)\
2377 y += xyoffset;\
2378 else\
2379 x += xyoffset;\
2380 }\
2381 }\
2382 if (glyph != NULL)\
2383 {\
2384 x1 = x + glyph->offset;\
2385 y1 = y + glyph->baseline;\
2386 XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2387 XSetTSOrigin(g_display, g_gc, x1, y1);\
2388 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2389 if (flags & TEXT2_IMPLICIT_X)\
2390 x += glyph->width;\
2391 }\
2392 }
2393
2394 void
2395 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2396 int clipx, int clipy, int clipcx, int clipcy,
2397 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2398 int bgcolour, int fgcolour, uint8 * text, uint8 length)
2399 {
2400 /* TODO: use brush appropriately */
2401
2402 FONTGLYPH *glyph;
2403 int i, j, xyoffset, x1, y1;
2404 DATABLOB *entry;
2405
2406 SET_FOREGROUND(bgcolour);
2407
2408 /* Sometimes, the boxcx value is something really large, like
2409 32691. This makes XCopyArea fail with Xvnc. The code below
2410 is a quick fix. */
2411 if (boxx + boxcx > g_width)
2412 boxcx = g_width - boxx;
2413
2414 if (boxcx > 1)
2415 {
2416 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2417 }
2418 else if (mixmode == MIX_OPAQUE)
2419 {
2420 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2421 }
2422
2423 SET_FOREGROUND(fgcolour);
2424 SET_BACKGROUND(bgcolour);
2425 XSetFillStyle(g_display, g_gc, FillStippled);
2426
2427 /* Paint text, character by character */
2428 for (i = 0; i < length;)
2429 {
2430 switch (text[i])
2431 {
2432 case 0xff:
2433 if (i + 2 < length)
2434 cache_put_text(text[i + 1], text, text[i + 2]);
2435 else
2436 {
2437 error("this shouldn't be happening\n");
2438 exit(1);
2439 }
2440 /* this will move pointer from start to first character after FF command */
2441 length -= i + 3;
2442 text = &(text[i + 3]);
2443 i = 0;
2444 break;
2445
2446 case 0xfe:
2447 entry = cache_get_text(text[i + 1]);
2448 if (entry != NULL)
2449 {
2450 if ((((uint8 *) (entry->data))[1] ==
2451 0) && (!(flags & TEXT2_IMPLICIT_X)))
2452 {
2453 if (flags & TEXT2_VERTICAL)
2454 y += text[i + 2];
2455 else
2456 x += text[i + 2];
2457 }
2458 for (j = 0; j < entry->size; j++)
2459 DO_GLYPH(((uint8 *) (entry->data)), j);
2460 }
2461 if (i + 2 < length)
2462 i += 3;
2463 else
2464 i += 2;
2465 length -= i;
2466 /* this will move pointer from start to first character after FE command */
2467 text = &(text[i]);
2468 i = 0;
2469 break;
2470
2471 default:
2472 DO_GLYPH(text, i);
2473 i++;
2474 break;
2475 }
2476 }
2477
2478 XSetFillStyle(g_display, g_gc, FillSolid);
2479
2480 if (g_ownbackstore)
2481 {
2482 if (boxcx > 1)
2483 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2484 boxy, boxcx, boxcy, boxx, boxy);
2485 else
2486 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2487 clipy, clipcx, clipcy, clipx, clipy);
2488 }
2489 }
2490
2491 void
2492 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2493 {
2494 Pixmap pix;
2495 XImage *image;
2496
2497 if (g_ownbackstore)
2498 {
2499 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2500 }
2501 else
2502 {
2503 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2504 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2505 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2506 XFreePixmap(g_display, pix);
2507 }
2508
2509 offset *= g_bpp / 8;
2510 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2511
2512 XDestroyImage(image);
2513 }
2514
2515 void
2516 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2517 {
2518 XImage *image;
2519 uint8 *data;
2520
2521 offset *= g_bpp / 8;
2522 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2523 if (data == NULL)
2524 return;
2525
2526 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2527 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2528
2529 if (g_ownbackstore)
2530 {
2531 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2532 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2533 }
2534 else
2535 {
2536 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2537 }
2538
2539 XFree(image);
2540 }
2541
2542 /* these do nothing here but are used in uiports */
2543 void
2544 ui_begin_update(void)
2545 {
2546 }
2547
2548 void
2549 ui_end_update(void)
2550 {
2551 }

  ViewVC Help
Powered by ViewVC 1.1.26