/[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 822 - (show annotations)
Mon Feb 28 22:38:24 2005 UTC (19 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 51773 byte(s)
compile fix for older gcc

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

  ViewVC Help
Powered by ViewVC 1.1.26