/[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 867 - (show annotations)
Wed Mar 23 12:25:54 2005 UTC (19 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 56620 byte(s)
Window-placement patch by <gregmhughes@comcast.net>
small modifications by me, to only set the PPosition sizehint, if the
position was specified on the command-line

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

  ViewVC Help
Powered by ViewVC 1.1.26