/[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 988 - (show annotations)
Thu Aug 25 20:27:45 2005 UTC (18 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 56736 byte(s)
Moved mouse button handling to separate function, handle_button_event. The single app mode has been enhanced: The minimazation now works better.

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

  ViewVC Help
Powered by ViewVC 1.1.26