/[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 991 - (show annotations)
Fri Aug 26 07:01:02 2005 UTC (18 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 56893 byte(s)
Disable moving in single-app mode when window is occupying entire
workarea.

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

  ViewVC Help
Powered by ViewVC 1.1.26