/[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 1022 - (show annotations)
Thu Sep 29 03:34:33 2005 UTC (18 years, 7 months ago) by jsorg71
File MIME type: text/plain
File size: 56852 byte(s)
ellipse fix for non copy rop

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

  ViewVC Help
Powered by ViewVC 1.1.26