/[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 821 - (show annotations)
Mon Feb 28 01:15:45 2005 UTC (19 years, 2 months ago) by jdmeijer
File MIME type: text/plain
File size: 51755 byte(s)
More optimisations

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 REPEAT4
768 (
769 #ifdef NEED_ALIGN
770 *(out++) = *(data++);
771 *(out++) = *(data++);
772 *(out++) = *(data++);
773 *(out++) = 0;
774 #else
775 *((uint32 *) out) = *((uint32 *) data);
776 out += 4;
777 data += 3;
778 #endif
779 )
780 /* *INDENT-ON* */
781 }
782 else if (g_xserver_be)
783 {
784 while (out < end)
785 {
786 pixel = *(data++) << 16;
787 pixel |= *(data++) << 8;
788 pixel |= *(data++);
789 SPLITCOLOUR24(pixel, pc);
790 value = MAKECOLOUR(pc);
791 BOUT32(out, value);
792 }
793 }
794 else
795 {
796 while (out < end)
797 {
798 pixel = *(data++) << 16;
799 pixel |= *(data++) << 8;
800 pixel |= *(data++);
801 SPLITCOLOUR24(pixel, pc);
802 value = MAKECOLOUR(pc);
803 LOUT32(out, value);
804 }
805 }
806 }
807
808 static uint8 *
809 translate_image(int width, int height, uint8 * data)
810 {
811 int size;
812 uint8 *out;
813 uint8 *end;
814
815 /* if server and xserver bpp match, */
816 /* and arch(endian) matches, no need to translate */
817 /* just return data */
818 if (g_arch_match)
819 {
820 if (g_depth == 15 && g_server_bpp == 15)
821 return data;
822 if (g_depth == 16 && g_server_bpp == 16)
823 return data;
824 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)
825 return data;
826 }
827
828 size = width * height * (g_bpp / 8);
829 out = (uint8 *) xmalloc(size);
830 end = out + size;
831
832 switch (g_server_bpp)
833 {
834 case 24:
835 switch (g_bpp)
836 {
837 case 32:
838 translate24to32(data, out, end);
839 break;
840 case 24:
841 translate24to24(data, out, end);
842 break;
843 case 16:
844 translate24to16(data, out, end);
845 break;
846 }
847 break;
848 case 16:
849 switch (g_bpp)
850 {
851 case 32:
852 translate16to32((uint16 *) data, out, end);
853 break;
854 case 24:
855 translate16to24((uint16 *) data, out, end);
856 break;
857 case 16:
858 translate16to16((uint16 *) data, out, end);
859 break;
860 }
861 break;
862 case 15:
863 switch (g_bpp)
864 {
865 case 32:
866 translate15to32((uint16 *) data, out, end);
867 break;
868 case 24:
869 translate15to24((uint16 *) data, out, end);
870 break;
871 case 16:
872 translate15to16((uint16 *) data, out, end);
873 break;
874 }
875 break;
876 case 8:
877 switch (g_bpp)
878 {
879 case 8:
880 translate8to8(data, out, end);
881 break;
882 case 16:
883 translate8to16(data, out, end);
884 break;
885 case 24:
886 translate8to24(data, out, end);
887 break;
888 case 32:
889 translate8to32(data, out, end);
890 break;
891 }
892 break;
893 }
894 return out;
895 }
896
897 BOOL
898 get_key_state(unsigned int state, uint32 keysym)
899 {
900 int modifierpos, key, keysymMask = 0;
901 int offset;
902
903 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
904
905 if (keycode == NoSymbol)
906 return False;
907
908 for (modifierpos = 0; modifierpos < 8; modifierpos++)
909 {
910 offset = g_mod_map->max_keypermod * modifierpos;
911
912 for (key = 0; key < g_mod_map->max_keypermod; key++)
913 {
914 if (g_mod_map->modifiermap[offset + key] == keycode)
915 keysymMask |= 1 << modifierpos;
916 }
917 }
918
919 return (state & keysymMask) ? True : False;
920 }
921
922 static void
923 calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
924 {
925 *shift_l = ffs(mask) - 1;
926 mask >>= *shift_l;
927 *shift_r = 8 - ffs(mask & ~(mask >> 1));
928 }
929
930 BOOL
931 ui_init(void)
932 {
933 XVisualInfo vi;
934 XPixmapFormatValues *pfm;
935 uint16 test;
936 int i, screen_num, nvisuals;
937 XVisualInfo *vmatches = NULL;
938 XVisualInfo template;
939 Bool TrueColorVisual = False;
940
941 g_display = XOpenDisplay(NULL);
942 if (g_display == NULL)
943 {
944 error("Failed to open display: %s\n", XDisplayName(NULL));
945 return False;
946 }
947
948 screen_num = DefaultScreen(g_display);
949 g_x_socket = ConnectionNumber(g_display);
950 g_screen = ScreenOfDisplay(g_display, screen_num);
951 g_depth = DefaultDepthOfScreen(g_screen);
952
953 /* Search for best TrueColor depth */
954 template.class = TrueColor;
955 vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);
956
957 nvisuals--;
958 while (nvisuals >= 0)
959 {
960 if ((vmatches + nvisuals)->depth > g_depth)
961 {
962 g_depth = (vmatches + nvisuals)->depth;
963 }
964 nvisuals--;
965 TrueColorVisual = True;
966 }
967
968 test = 1;
969 g_host_be = !(BOOL) (*(uint8 *) (&test));
970 g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
971
972 if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))
973 {
974 /* we use a colourmap, so the default visual should do */
975 g_visual = DefaultVisualOfScreen(g_screen);
976 g_depth = DefaultDepthOfScreen(g_screen);
977
978 /* Do not allocate colours on a TrueColor visual */
979 if (g_visual->class == TrueColor)
980 {
981 g_owncolmap = False;
982 }
983 }
984 else
985 {
986 /* need a truecolour visual */
987 if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))
988 {
989 error("The display does not support true colour - high colour support unavailable.\n");
990 return False;
991 }
992
993 g_visual = vi.visual;
994 g_owncolmap = False;
995 calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);
996 calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);
997 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);
998
999 /* if RGB video and everything is little endian */
1000 if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&
1001 !g_xserver_be && !g_host_be)
1002 {
1003 if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&
1004 g_blue_shift_l == 0))
1005 {
1006 g_arch_match = True;
1007 }
1008 }
1009
1010 if (g_arch_match)
1011 {
1012 DEBUG(("Architectures match, enabling little endian optimisations.\n"));
1013 }
1014 }
1015
1016 pfm = XListPixmapFormats(g_display, &i);
1017 if (pfm != NULL)
1018 {
1019 /* Use maximum bpp for this depth - this is generally
1020 desirable, e.g. 24 bits->32 bits. */
1021 while (i--)
1022 {
1023 if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
1024 {
1025 g_bpp = pfm[i].bits_per_pixel;
1026 }
1027 }
1028 XFree(pfm);
1029 }
1030
1031 if (g_bpp < 8)
1032 {
1033 error("Less than 8 bpp not currently supported.\n");
1034 XCloseDisplay(g_display);
1035 return False;
1036 }
1037
1038 if (!g_owncolmap)
1039 {
1040 g_xcolmap =
1041 XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1042 AllocNone);
1043 if (g_depth <= 8)
1044 warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
1045 }
1046
1047 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1048 {
1049 warning("External BackingStore not available, using internal\n");
1050 g_ownbackstore = True;
1051 }
1052
1053 /*
1054 * Determine desktop size
1055 */
1056 if (g_fullscreen)
1057 {
1058 g_width = WidthOfScreen(g_screen);
1059 g_height = HeightOfScreen(g_screen);
1060 }
1061 else if (g_width < 0)
1062 {
1063 /* Percent of screen */
1064 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1065 g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1066 }
1067 else if (g_width == 0)
1068 {
1069 /* Fetch geometry from _NET_WORKAREA */
1070 uint32 x, y, cx, cy;
1071
1072 if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1073 {
1074 g_width = cx;
1075 g_height = cy;
1076 }
1077 else
1078 {
1079 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1080 g_width = 800;
1081 g_height = 600;
1082 }
1083 }
1084
1085 /* make sure width is a multiple of 4 */
1086 g_width = (g_width + 3) & ~3;
1087
1088 g_mod_map = XGetModifierMapping(g_display);
1089
1090 xkeymap_init();
1091
1092 if (g_enable_compose)
1093 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1094
1095 xclip_init();
1096
1097 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));
1098
1099 return True;
1100 }
1101
1102 void
1103 ui_deinit(void)
1104 {
1105 if (g_IM != NULL)
1106 XCloseIM(g_IM);
1107
1108 if (g_null_cursor != NULL)
1109 ui_destroy_cursor(g_null_cursor);
1110
1111 XFreeModifiermap(g_mod_map);
1112
1113 if (g_ownbackstore)
1114 XFreePixmap(g_display, g_backstore);
1115
1116 XFreeGC(g_display, g_gc);
1117 XCloseDisplay(g_display);
1118 g_display = NULL;
1119 }
1120
1121 BOOL
1122 ui_create_window(void)
1123 {
1124 uint8 null_pointer_mask[1] = { 0x80 };
1125 uint8 null_pointer_data[24] = { 0x00 };
1126
1127 XSetWindowAttributes attribs;
1128 XClassHint *classhints;
1129 XSizeHints *sizehints;
1130 int wndwidth, wndheight;
1131 long input_mask, ic_input_mask;
1132 XEvent xevent;
1133
1134 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1135 wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1136
1137 attribs.background_pixel = BlackPixelOfScreen(g_screen);
1138 attribs.border_pixel = WhitePixelOfScreen(g_screen);
1139 attribs.backing_store = g_ownbackstore ? NotUseful : Always;
1140 attribs.override_redirect = g_fullscreen;
1141 attribs.colormap = g_xcolmap;
1142
1143 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1144 wndheight, 0, g_depth, InputOutput, g_visual,
1145 CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1146 CWBorderPixel, &attribs);
1147
1148 if (g_gc == NULL)
1149 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1150
1151 if (g_create_bitmap_gc == NULL)
1152 g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1153
1154 if ((g_ownbackstore) && (g_backstore == 0))
1155 {
1156 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1157
1158 /* clear to prevent rubbish being exposed at startup */
1159 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1160 XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1161 }
1162
1163 XStoreName(g_display, g_wnd, g_title);
1164
1165 if (g_hide_decorations)
1166 mwm_hide_decorations();
1167
1168 classhints = XAllocClassHint();
1169 if (classhints != NULL)
1170 {
1171 classhints->res_name = classhints->res_class = "rdesktop";
1172 XSetClassHint(g_display, g_wnd, classhints);
1173 XFree(classhints);
1174 }
1175
1176 sizehints = XAllocSizeHints();
1177 if (sizehints)
1178 {
1179 sizehints->flags = PMinSize | PMaxSize;
1180 sizehints->min_width = sizehints->max_width = g_width;
1181 sizehints->min_height = sizehints->max_height = g_height;
1182 XSetWMNormalHints(g_display, g_wnd, sizehints);
1183 XFree(sizehints);
1184 }
1185
1186 if (g_embed_wnd)
1187 {
1188 XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1189 }
1190
1191 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1192 VisibilityChangeMask | FocusChangeMask;
1193
1194 if (g_sendmotion)
1195 input_mask |= PointerMotionMask;
1196 if (g_ownbackstore)
1197 input_mask |= ExposureMask;
1198 if (g_fullscreen || g_grab_keyboard)
1199 input_mask |= EnterWindowMask;
1200 if (g_grab_keyboard)
1201 input_mask |= LeaveWindowMask;
1202
1203 if (g_IM != NULL)
1204 {
1205 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1206 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1207
1208 if ((g_IC != NULL)
1209 && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1210 input_mask |= ic_input_mask;
1211 }
1212
1213 XSelectInput(g_display, g_wnd, input_mask);
1214 XMapWindow(g_display, g_wnd);
1215
1216 /* wait for VisibilityNotify */
1217 do
1218 {
1219 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1220 }
1221 while (xevent.type != VisibilityNotify);
1222 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1223
1224 g_focused = False;
1225 g_mouse_in_wnd = False;
1226
1227 /* handle the WM_DELETE_WINDOW protocol */
1228 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1229 g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1230 XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1231
1232 /* create invisible 1x1 cursor to be used as null cursor */
1233 if (g_null_cursor == NULL)
1234 g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1235
1236 return True;
1237 }
1238
1239 void
1240 ui_resize_window()
1241 {
1242 XSizeHints *sizehints;
1243 Pixmap bs;
1244
1245 sizehints = XAllocSizeHints();
1246 if (sizehints)
1247 {
1248 sizehints->flags = PMinSize | PMaxSize;
1249 sizehints->min_width = sizehints->max_width = g_width;
1250 sizehints->min_height = sizehints->max_height = g_height;
1251 XSetWMNormalHints(g_display, g_wnd, sizehints);
1252 XFree(sizehints);
1253 }
1254
1255 if (!(g_fullscreen || g_embed_wnd))
1256 {
1257 XResizeWindow(g_display, g_wnd, g_width, g_height);
1258 }
1259
1260 /* create new backstore pixmap */
1261 if (g_backstore != 0)
1262 {
1263 bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1264 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1265 XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1266 XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1267 XFreePixmap(g_display, g_backstore);
1268 g_backstore = bs;
1269 }
1270 }
1271
1272 void
1273 ui_destroy_window(void)
1274 {
1275 if (g_IC != NULL)
1276 XDestroyIC(g_IC);
1277
1278 XDestroyWindow(g_display, g_wnd);
1279 }
1280
1281 void
1282 xwin_toggle_fullscreen(void)
1283 {
1284 Pixmap contents = 0;
1285
1286 if (!g_ownbackstore)
1287 {
1288 /* need to save contents of window */
1289 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1290 XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1291 }
1292
1293 ui_destroy_window();
1294 g_fullscreen = !g_fullscreen;
1295 ui_create_window();
1296
1297 XDefineCursor(g_display, g_wnd, g_current_cursor);
1298
1299 if (!g_ownbackstore)
1300 {
1301 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1302 XFreePixmap(g_display, contents);
1303 }
1304 }
1305
1306 /* Process all events in Xlib queue
1307 Returns 0 after user quit, 1 otherwise */
1308 static int
1309 xwin_process_events(void)
1310 {
1311 XEvent xevent;
1312 KeySym keysym;
1313 uint16 button, flags;
1314 uint32 ev_time;
1315 key_translation tr;
1316 char str[256];
1317 Status status;
1318
1319 while (XPending(g_display) > 0)
1320 {
1321 XNextEvent(g_display, &xevent);
1322
1323 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1324 {
1325 DEBUG_KBD(("Filtering event\n"));
1326 continue;
1327 }
1328
1329 flags = 0;
1330
1331 switch (xevent.type)
1332 {
1333 case VisibilityNotify:
1334 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1335 break;
1336 case ClientMessage:
1337 /* the window manager told us to quit */
1338 if ((xevent.xclient.message_type == g_protocol_atom)
1339 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1340 /* Quit */
1341 return 0;
1342 break;
1343
1344 case KeyPress:
1345 g_last_gesturetime = xevent.xkey.time;
1346 if (g_IC != NULL)
1347 /* Multi_key compatible version */
1348 {
1349 XmbLookupString(g_IC,
1350 &xevent.xkey, str, sizeof(str), &keysym,
1351 &status);
1352 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1353 {
1354 error("XmbLookupString failed with status 0x%x\n",
1355 status);
1356 break;
1357 }
1358 }
1359 else
1360 {
1361 /* Plain old XLookupString */
1362 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1363 XLookupString((XKeyEvent *) & xevent,
1364 str, sizeof(str), &keysym, NULL);
1365 }
1366
1367 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1368 get_ksname(keysym)));
1369
1370 ev_time = time(NULL);
1371 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1372 break;
1373
1374 tr = xkeymap_translate_key(keysym,
1375 xevent.xkey.keycode, xevent.xkey.state);
1376
1377 if (tr.scancode == 0)
1378 break;
1379
1380 save_remote_modifiers(tr.scancode);
1381 ensure_remote_modifiers(ev_time, tr);
1382 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1383 restore_remote_modifiers(ev_time, tr.scancode);
1384
1385 break;
1386
1387 case KeyRelease:
1388 g_last_gesturetime = xevent.xkey.time;
1389 XLookupString((XKeyEvent *) & xevent, str,
1390 sizeof(str), &keysym, NULL);
1391
1392 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1393 get_ksname(keysym)));
1394
1395 ev_time = time(NULL);
1396 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1397 break;
1398
1399 tr = xkeymap_translate_key(keysym,
1400 xevent.xkey.keycode, xevent.xkey.state);
1401
1402 if (tr.scancode == 0)
1403 break;
1404
1405 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1406 break;
1407
1408 case ButtonPress:
1409 flags = MOUSE_FLAG_DOWN;
1410 /* fall through */
1411
1412 case ButtonRelease:
1413 g_last_gesturetime = xevent.xbutton.time;
1414 button = xkeymap_translate_button(xevent.xbutton.button);
1415 if (button == 0)
1416 break;
1417
1418 /* If win_button_size is nonzero, enable single app mode */
1419 if (xevent.xbutton.y < g_win_button_size)
1420 {
1421 /* Stop moving window when button is released, regardless of cursor position */
1422 if (g_moving_wnd && (xevent.type == ButtonRelease))
1423 g_moving_wnd = False;
1424
1425 /* Check from right to left: */
1426
1427 if (xevent.xbutton.x >= g_width - g_win_button_size)
1428 {
1429 /* The close button, continue */
1430 ;
1431 }
1432 else if (xevent.xbutton.x >=
1433 g_width - g_win_button_size * 2)
1434 {
1435 /* The maximize/restore button. Do not send to
1436 server. It might be a good idea to change the
1437 cursor or give some other visible indication
1438 that rdesktop inhibited this click */
1439 break;
1440 }
1441 else if (xevent.xbutton.x >=
1442 g_width - g_win_button_size * 3)
1443 {
1444 /* The minimize button. Iconify window. */
1445 XIconifyWindow(g_display, g_wnd,
1446 DefaultScreen(g_display));
1447 break;
1448 }
1449 else if (xevent.xbutton.x <= g_win_button_size)
1450 {
1451 /* The system menu. Ignore. */
1452 break;
1453 }
1454 else
1455 {
1456 /* The title bar. */
1457 if ((xevent.type == ButtonPress) && !g_fullscreen
1458 && g_hide_decorations)
1459 {
1460 g_moving_wnd = True;
1461 g_move_x_offset = xevent.xbutton.x;
1462 g_move_y_offset = xevent.xbutton.y;
1463 }
1464 break;
1465
1466 }
1467 }
1468
1469 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1470 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1471 break;
1472
1473 case MotionNotify:
1474 if (g_moving_wnd)
1475 {
1476 XMoveWindow(g_display, g_wnd,
1477 xevent.xmotion.x_root - g_move_x_offset,
1478 xevent.xmotion.y_root - g_move_y_offset);
1479 break;
1480 }
1481
1482 if (g_fullscreen && !g_focused)
1483 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1484 CurrentTime);
1485 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1486 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1487 break;
1488
1489 case FocusIn:
1490 if (xevent.xfocus.mode == NotifyGrab)
1491 break;
1492 g_focused = True;
1493 reset_modifier_keys();
1494 if (g_grab_keyboard && g_mouse_in_wnd)
1495 XGrabKeyboard(g_display, g_wnd, True,
1496 GrabModeAsync, GrabModeAsync, CurrentTime);
1497 break;
1498
1499 case FocusOut:
1500 if (xevent.xfocus.mode == NotifyUngrab)
1501 break;
1502 g_focused = False;
1503 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1504 XUngrabKeyboard(g_display, CurrentTime);
1505 break;
1506
1507 case EnterNotify:
1508 /* we only register for this event when in fullscreen mode */
1509 /* or grab_keyboard */
1510 g_mouse_in_wnd = True;
1511 if (g_fullscreen)
1512 {
1513 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1514 CurrentTime);
1515 break;
1516 }
1517 if (g_focused)
1518 XGrabKeyboard(g_display, g_wnd, True,
1519 GrabModeAsync, GrabModeAsync, CurrentTime);
1520 break;
1521
1522 case LeaveNotify:
1523 /* we only register for this event when grab_keyboard */
1524 g_mouse_in_wnd = False;
1525 XUngrabKeyboard(g_display, CurrentTime);
1526 break;
1527
1528 case Expose:
1529 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1530 xevent.xexpose.x, xevent.xexpose.y,
1531 xevent.xexpose.width,
1532 xevent.xexpose.height,
1533 xevent.xexpose.x, xevent.xexpose.y);
1534 break;
1535
1536 case MappingNotify:
1537 /* Refresh keyboard mapping if it has changed. This is important for
1538 Xvnc, since it allocates keycodes dynamically */
1539 if (xevent.xmapping.request == MappingKeyboard
1540 || xevent.xmapping.request == MappingModifier)
1541 XRefreshKeyboardMapping(&xevent.xmapping);
1542
1543 if (xevent.xmapping.request == MappingModifier)
1544 {
1545 XFreeModifiermap(g_mod_map);
1546 g_mod_map = XGetModifierMapping(g_display);
1547 }
1548 break;
1549
1550 /* clipboard stuff */
1551 case SelectionNotify:
1552 xclip_handle_SelectionNotify(&xevent.xselection);
1553 break;
1554 case SelectionRequest:
1555 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1556 break;
1557 case SelectionClear:
1558 xclip_handle_SelectionClear();
1559 break;
1560 case PropertyNotify:
1561 xclip_handle_PropertyNotify(&xevent.xproperty);
1562 break;
1563 }
1564 }
1565 /* Keep going */
1566 return 1;
1567 }
1568
1569 /* Returns 0 after user quit, 1 otherwise */
1570 int
1571 ui_select(int rdp_socket)
1572 {
1573 int n;
1574 fd_set rfds, wfds;
1575 struct timeval tv;
1576 BOOL s_timeout = False;
1577
1578 while (True)
1579 {
1580 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1581 /* Process any events already waiting */
1582 if (!xwin_process_events())
1583 /* User quit */
1584 return 0;
1585
1586 FD_ZERO(&rfds);
1587 FD_ZERO(&wfds);
1588 FD_SET(rdp_socket, &rfds);
1589 FD_SET(g_x_socket, &rfds);
1590
1591 #ifdef WITH_RDPSND
1592 /* FIXME: there should be an API for registering fds */
1593 if (g_dsp_busy)
1594 {
1595 FD_SET(g_dsp_fd, &wfds);
1596 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1597 }
1598 #endif
1599 /* default timeout */
1600 tv.tv_sec = 60;
1601 tv.tv_usec = 0;
1602
1603 /* add redirection handles */
1604 rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1605
1606 n++;
1607
1608 switch (select(n, &rfds, &wfds, NULL, &tv))
1609 {
1610 case -1:
1611 error("select: %s\n", strerror(errno));
1612
1613 case 0:
1614 /* Abort serial read calls */
1615 if (s_timeout)
1616 rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1617 continue;
1618 }
1619
1620 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1621
1622 if (FD_ISSET(rdp_socket, &rfds))
1623 return 1;
1624
1625 #ifdef WITH_RDPSND
1626 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1627 wave_out_play();
1628 #endif
1629 }
1630 }
1631
1632 void
1633 ui_move_pointer(int x, int y)
1634 {
1635 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1636 }
1637
1638 HBITMAP
1639 ui_create_bitmap(int width, int height, uint8 * data)
1640 {
1641 XImage *image;
1642 Pixmap bitmap;
1643 uint8 *tdata;
1644 int bitmap_pad;
1645
1646 if (g_server_bpp == 8)
1647 {
1648 bitmap_pad = 8;
1649 }
1650 else
1651 {
1652 bitmap_pad = g_bpp;
1653
1654 if (g_bpp == 24)
1655 bitmap_pad = 32;
1656 }
1657
1658 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1659 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1660 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1661 (char *) tdata, width, height, bitmap_pad, 0);
1662
1663 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1664
1665 XFree(image);
1666 if (tdata != data)
1667 xfree(tdata);
1668 return (HBITMAP) bitmap;
1669 }
1670
1671 void
1672 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1673 {
1674 XImage *image;
1675 uint8 *tdata;
1676 int bitmap_pad;
1677
1678 if (g_server_bpp == 8)
1679 {
1680 bitmap_pad = 8;
1681 }
1682 else
1683 {
1684 bitmap_pad = g_bpp;
1685
1686 if (g_bpp == 24)
1687 bitmap_pad = 32;
1688 }
1689
1690 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1691 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1692 (char *) tdata, width, height, bitmap_pad, 0);
1693
1694 if (g_ownbackstore)
1695 {
1696 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1697 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1698 }
1699 else
1700 {
1701 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1702 }
1703
1704 XFree(image);
1705 if (tdata != data)
1706 xfree(tdata);
1707 }
1708
1709 void
1710 ui_destroy_bitmap(HBITMAP bmp)
1711 {
1712 XFreePixmap(g_display, (Pixmap) bmp);
1713 }
1714
1715 HGLYPH
1716 ui_create_glyph(int width, int height, uint8 * data)
1717 {
1718 XImage *image;
1719 Pixmap bitmap;
1720 int scanline;
1721
1722 scanline = (width + 7) / 8;
1723
1724 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1725 if (g_create_glyph_gc == 0)
1726 g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1727
1728 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1729 width, height, 8, scanline);
1730 image->byte_order = MSBFirst;
1731 image->bitmap_bit_order = MSBFirst;
1732 XInitImage(image);
1733
1734 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1735
1736 XFree(image);
1737 return (HGLYPH) bitmap;
1738 }
1739
1740 void
1741 ui_destroy_glyph(HGLYPH glyph)
1742 {
1743 XFreePixmap(g_display, (Pixmap) glyph);
1744 }
1745
1746 HCURSOR
1747 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1748 uint8 * andmask, uint8 * xormask)
1749 {
1750 HGLYPH maskglyph, cursorglyph;
1751 XColor bg, fg;
1752 Cursor xcursor;
1753 uint8 *cursor, *pcursor;
1754 uint8 *mask, *pmask;
1755 uint8 nextbit;
1756 int scanline, offset;
1757 int i, j;
1758
1759 scanline = (width + 7) / 8;
1760 offset = scanline * height;
1761
1762 cursor = (uint8 *) xmalloc(offset);
1763 memset(cursor, 0, offset);
1764
1765 mask = (uint8 *) xmalloc(offset);
1766 memset(mask, 0, offset);
1767
1768 /* approximate AND and XOR masks with a monochrome X pointer */
1769 for (i = 0; i < height; i++)
1770 {
1771 offset -= scanline;
1772 pcursor = &cursor[offset];
1773 pmask = &mask[offset];
1774
1775 for (j = 0; j < scanline; j++)
1776 {
1777 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1778 {
1779 if (xormask[0] || xormask[1] || xormask[2])
1780 {
1781 *pcursor |= (~(*andmask) & nextbit);
1782 *pmask |= nextbit;
1783 }
1784 else
1785 {
1786 *pcursor |= ((*andmask) & nextbit);
1787 *pmask |= (~(*andmask) & nextbit);
1788 }
1789
1790 xormask += 3;
1791 }
1792
1793 andmask++;
1794 pcursor++;
1795 pmask++;
1796 }
1797 }
1798
1799 fg.red = fg.blue = fg.green = 0xffff;
1800 bg.red = bg.blue = bg.green = 0x0000;
1801 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1802
1803 cursorglyph = ui_create_glyph(width, height, cursor);
1804 maskglyph = ui_create_glyph(width, height, mask);
1805
1806 xcursor =
1807 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1808 (Pixmap) maskglyph, &fg, &bg, x, y);
1809
1810 ui_destroy_glyph(maskglyph);
1811 ui_destroy_glyph(cursorglyph);
1812 xfree(mask);
1813 xfree(cursor);
1814 return (HCURSOR) xcursor;
1815 }
1816
1817 void
1818 ui_set_cursor(HCURSOR cursor)
1819 {
1820 g_current_cursor = (Cursor) cursor;
1821 XDefineCursor(g_display, g_wnd, g_current_cursor);
1822 }
1823
1824 void
1825 ui_destroy_cursor(HCURSOR cursor)
1826 {
1827 XFreeCursor(g_display, (Cursor) cursor);
1828 }
1829
1830 void
1831 ui_set_null_cursor(void)
1832 {
1833 ui_set_cursor(g_null_cursor);
1834 }
1835
1836 #define MAKE_XCOLOR(xc,c) \
1837 (xc)->red = ((c)->red << 8) | (c)->red; \
1838 (xc)->green = ((c)->green << 8) | (c)->green; \
1839 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1840 (xc)->flags = DoRed | DoGreen | DoBlue;
1841
1842
1843 HCOLOURMAP
1844 ui_create_colourmap(COLOURMAP * colours)
1845 {
1846 COLOURENTRY *entry;
1847 int i, ncolours = colours->ncolours;
1848 if (!g_owncolmap)
1849 {
1850 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1851 XColor xentry;
1852 XColor xc_cache[256];
1853 uint32 colour;
1854 int colLookup = 256;
1855 for (i = 0; i < ncolours; i++)
1856 {
1857 entry = &colours->colours[i];
1858 MAKE_XCOLOR(&xentry, entry);
1859
1860 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1861 {
1862 /* Allocation failed, find closest match. */
1863 int j = 256;
1864 int nMinDist = 3 * 256 * 256;
1865 long nDist = nMinDist;
1866
1867 /* only get the colors once */
1868 while (colLookup--)
1869 {
1870 xc_cache[colLookup].pixel = colLookup;
1871 xc_cache[colLookup].red = xc_cache[colLookup].green =
1872 xc_cache[colLookup].blue = 0;
1873 xc_cache[colLookup].flags = 0;
1874 XQueryColor(g_display,
1875 DefaultColormap(g_display,
1876 DefaultScreen(g_display)),
1877 &xc_cache[colLookup]);
1878 }
1879 colLookup = 0;
1880
1881 /* approximate the pixel */
1882 while (j--)
1883 {
1884 if (xc_cache[j].flags)
1885 {
1886 nDist = ((long) (xc_cache[j].red >> 8) -
1887 (long) (xentry.red >> 8)) *
1888 ((long) (xc_cache[j].red >> 8) -
1889 (long) (xentry.red >> 8)) +
1890 ((long) (xc_cache[j].green >> 8) -
1891 (long) (xentry.green >> 8)) *
1892 ((long) (xc_cache[j].green >> 8) -
1893 (long) (xentry.green >> 8)) +
1894 ((long) (xc_cache[j].blue >> 8) -
1895 (long) (xentry.blue >> 8)) *
1896 ((long) (xc_cache[j].blue >> 8) -
1897 (long) (xentry.blue >> 8));
1898 }
1899 if (nDist < nMinDist)
1900 {
1901 nMinDist = nDist;
1902 xentry.pixel = j;
1903 }
1904 }
1905 }
1906 colour = xentry.pixel;
1907
1908 /* update our cache */
1909 if (xentry.pixel < 256)
1910 {
1911 xc_cache[xentry.pixel].red = xentry.red;
1912 xc_cache[xentry.pixel].green = xentry.green;
1913 xc_cache[xentry.pixel].blue = xentry.blue;
1914
1915 }
1916
1917 map[i] = colour;
1918 }
1919 return map;
1920 }
1921 else
1922 {
1923 XColor *xcolours, *xentry;
1924 Colormap map;
1925
1926 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1927 for (i = 0; i < ncolours; i++)
1928 {
1929 entry = &colours->colours[i];
1930 xentry = &xcolours[i];
1931 xentry->pixel = i;
1932 MAKE_XCOLOR(xentry, entry);
1933 }
1934
1935 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1936 XStoreColors(g_display, map, xcolours, ncolours);
1937
1938 xfree(xcolours);
1939 return (HCOLOURMAP) map;
1940 }
1941 }
1942
1943 void
1944 ui_destroy_colourmap(HCOLOURMAP map)
1945 {
1946 if (!g_owncolmap)
1947 xfree(map);
1948 else
1949 XFreeColormap(g_display, (Colormap) map);
1950 }
1951
1952 void
1953 ui_set_colourmap(HCOLOURMAP map)
1954 {
1955 if (!g_owncolmap)
1956 {
1957 if (g_colmap)
1958 xfree(g_colmap);
1959
1960 g_colmap = (uint32 *) map;
1961 }
1962 else
1963 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1964 }
1965
1966 void
1967 ui_set_clip(int x, int y, int cx, int cy)
1968 {
1969 XRectangle rect;
1970
1971 rect.x = x;
1972 rect.y = y;
1973 rect.width = cx;
1974 rect.height = cy;
1975 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1976 }
1977
1978 void
1979 ui_reset_clip(void)
1980 {
1981 XRectangle rect;
1982
1983 rect.x = 0;
1984 rect.y = 0;
1985 rect.width = g_width;
1986 rect.height = g_height;
1987 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1988 }
1989
1990 void
1991 ui_bell(void)
1992 {
1993 XBell(g_display, 0);
1994 }
1995
1996 void
1997 ui_destblt(uint8 opcode,
1998 /* dest */ int x, int y, int cx, int cy)
1999 {
2000 SET_FUNCTION(opcode);
2001 FILL_RECTANGLE(x, y, cx, cy);
2002 RESET_FUNCTION(opcode);
2003 }
2004
2005 static uint8 hatch_patterns[] = {
2006 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2007 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2008 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2009 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2010 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2011 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2012 };
2013
2014 void
2015 ui_patblt(uint8 opcode,
2016 /* dest */ int x, int y, int cx, int cy,
2017 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2018 {
2019 Pixmap fill;
2020 uint8 i, ipattern[8];
2021
2022 SET_FUNCTION(opcode);
2023
2024 switch (brush->style)
2025 {
2026 case 0: /* Solid */
2027 SET_FOREGROUND(fgcolour);
2028 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2029 break;
2030
2031 case 2: /* Hatch */
2032 fill = (Pixmap) ui_create_glyph(8, 8,
2033 hatch_patterns + brush->pattern[0] * 8);
2034 SET_FOREGROUND(fgcolour);
2035 SET_BACKGROUND(bgcolour);
2036 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2037 XSetStipple(g_display, g_gc, fill);
2038 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2039 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2040 XSetFillStyle(g_display, g_gc, FillSolid);
2041 XSetTSOrigin(g_display, g_gc, 0, 0);
2042 ui_destroy_glyph((HGLYPH) fill);
2043 break;
2044
2045 case 3: /* Pattern */
2046 for (i = 0; i != 8; i++)
2047 ipattern[7 - i] = brush->pattern[i];
2048 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2049 SET_FOREGROUND(bgcolour);
2050 SET_BACKGROUND(fgcolour);
2051 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2052 XSetStipple(g_display, g_gc, fill);
2053 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2054 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2055 XSetFillStyle(g_display, g_gc, FillSolid);
2056 XSetTSOrigin(g_display, g_gc, 0, 0);
2057 ui_destroy_glyph((HGLYPH) fill);
2058 break;
2059
2060 default:
2061 unimpl("brush %d\n", brush->style);
2062 }
2063
2064 RESET_FUNCTION(opcode);
2065
2066 if (g_ownbackstore)
2067 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2068 }
2069
2070 void
2071 ui_screenblt(uint8 opcode,
2072 /* dest */ int x, int y, int cx, int cy,
2073 /* src */ int srcx, int srcy)
2074 {
2075 SET_FUNCTION(opcode);
2076 if (g_ownbackstore)
2077 {
2078 if (g_Unobscured)
2079 {
2080 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2081 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2082 y);
2083 }
2084 else
2085 {
2086 XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2087 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2088 y);
2089 }
2090 }
2091 else
2092 {
2093 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2094 }
2095 RESET_FUNCTION(opcode);
2096 }
2097
2098 void
2099 ui_memblt(uint8 opcode,
2100 /* dest */ int x, int y, int cx, int cy,
2101 /* src */ HBITMAP src, int srcx, int srcy)
2102 {
2103 SET_FUNCTION(opcode);
2104 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2105 if (g_ownbackstore)
2106 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2107 RESET_FUNCTION(opcode);
2108 }
2109
2110 void
2111 ui_triblt(uint8 opcode,
2112 /* dest */ int x, int y, int cx, int cy,
2113 /* src */ HBITMAP src, int srcx, int srcy,
2114 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2115 {
2116 /* This is potentially difficult to do in general. Until someone
2117 comes up with a more efficient way of doing it I am using cases. */
2118
2119 switch (opcode)
2120 {
2121 case 0x69: /* PDSxxn */
2122 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2123 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2124 break;
2125
2126 case 0xb8: /* PSDPxax */
2127 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2128 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2129 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2130 break;
2131
2132 case 0xc0: /* PSa */
2133 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2134 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2135 break;
2136
2137 default:
2138 unimpl("triblt 0x%x\n", opcode);
2139 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2140 }
2141 }
2142
2143 void
2144 ui_line(uint8 opcode,
2145 /* dest */ int startx, int starty, int endx, int endy,
2146 /* pen */ PEN * pen)
2147 {
2148 SET_FUNCTION(opcode);
2149 SET_FOREGROUND(pen->colour);
2150 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2151 if (g_ownbackstore)
2152 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2153 RESET_FUNCTION(opcode);
2154 }
2155
2156 void
2157 ui_rect(
2158 /* dest */ int x, int y, int cx, int cy,
2159 /* brush */ int colour)
2160 {
2161 SET_FOREGROUND(colour);
2162 FILL_RECTANGLE(x, y, cx, cy);
2163 }
2164
2165 /* warning, this function only draws on wnd or backstore, not both */
2166 void
2167 ui_draw_glyph(int mixmode,
2168 /* dest */ int x, int y, int cx, int cy,
2169 /* src */ HGLYPH glyph, int srcx, int srcy,
2170 int bgcolour, int fgcolour)
2171 {
2172 SET_FOREGROUND(fgcolour);
2173 SET_BACKGROUND(bgcolour);
2174
2175 XSetFillStyle(g_display, g_gc,
2176 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2177 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2178 XSetTSOrigin(g_display, g_gc, x, y);
2179
2180 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2181
2182 XSetFillStyle(g_display, g_gc, FillSolid);
2183 }
2184
2185 #define DO_GLYPH(ttext,idx) \
2186 {\
2187 glyph = cache_get_font (font, ttext[idx]);\
2188 if (!(flags & TEXT2_IMPLICIT_X))\
2189 {\
2190 xyoffset = ttext[++idx];\
2191 if ((xyoffset & 0x80))\
2192 {\
2193 if (flags & TEXT2_VERTICAL)\
2194 y += ttext[idx+1] | (ttext[idx+2] << 8);\
2195 else\
2196 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2197 idx += 2;\
2198 }\
2199 else\
2200 {\
2201 if (flags & TEXT2_VERTICAL)\
2202 y += xyoffset;\
2203 else\
2204 x += xyoffset;\
2205 }\
2206 }\
2207 if (glyph != NULL)\
2208 {\
2209 x1 = x + glyph->offset;\
2210 y1 = y + glyph->baseline;\
2211 XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2212 XSetTSOrigin(g_display, g_gc, x1, y1);\
2213 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2214 if (flags & TEXT2_IMPLICIT_X)\
2215 x += glyph->width;\
2216 }\
2217 }
2218
2219 void
2220 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
2221 int clipx, int clipy, int clipcx, int clipcy,
2222 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
2223 int fgcolour, uint8 * text, uint8 length)
2224 {
2225 FONTGLYPH *glyph;
2226 int i, j, xyoffset, x1, y1;
2227 DATABLOB *entry;
2228
2229 SET_FOREGROUND(bgcolour);
2230
2231 /* Sometimes, the boxcx value is something really large, like
2232 32691. This makes XCopyArea fail with Xvnc. The code below
2233 is a quick fix. */
2234 if (boxx + boxcx > g_width)
2235 boxcx = g_width - boxx;
2236
2237 if (boxcx > 1)
2238 {
2239 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2240 }
2241 else if (mixmode == MIX_OPAQUE)
2242 {
2243 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2244 }
2245
2246 SET_FOREGROUND(fgcolour);
2247 SET_BACKGROUND(bgcolour);
2248 XSetFillStyle(g_display, g_gc, FillStippled);
2249
2250 /* Paint text, character by character */
2251 for (i = 0; i < length;)
2252 {
2253 switch (text[i])
2254 {
2255 case 0xff:
2256 if (i + 2 < length)
2257 cache_put_text(text[i + 1], text, text[i + 2]);
2258 else
2259 {
2260 error("this shouldn't be happening\n");
2261 exit(1);
2262 }
2263 /* this will move pointer from start to first character after FF command */
2264 length -= i + 3;
2265 text = &(text[i + 3]);
2266 i = 0;
2267 break;
2268
2269 case 0xfe:
2270 entry = cache_get_text(text[i + 1]);
2271 if (entry != NULL)
2272 {
2273 if ((((uint8 *) (entry->data))[1] ==
2274 0) && (!(flags & TEXT2_IMPLICIT_X)))
2275 {
2276 if (flags & TEXT2_VERTICAL)
2277 y += text[i + 2];
2278 else
2279 x += text[i + 2];
2280 }
2281 for (j = 0; j < entry->size; j++)
2282 DO_GLYPH(((uint8 *) (entry->data)), j);
2283 }
2284 if (i + 2 < length)
2285 i += 3;
2286 else
2287 i += 2;
2288 length -= i;
2289 /* this will move pointer from start to first character after FE command */
2290 text = &(text[i]);
2291 i = 0;
2292 break;
2293
2294 default:
2295 DO_GLYPH(text, i);
2296 i++;
2297 break;
2298 }
2299 }
2300
2301 XSetFillStyle(g_display, g_gc, FillSolid);
2302
2303 if (g_ownbackstore)
2304 {
2305 if (boxcx > 1)
2306 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2307 boxy, boxcx, boxcy, boxx, boxy);
2308 else
2309 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2310 clipy, clipcx, clipcy, clipx, clipy);
2311 }
2312 }
2313
2314 void
2315 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2316 {
2317 Pixmap pix;
2318 XImage *image;
2319
2320 if (g_ownbackstore)
2321 {
2322 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2323 }
2324 else
2325 {
2326 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2327 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2328 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2329 XFreePixmap(g_display, pix);
2330 }
2331
2332 offset *= g_bpp / 8;
2333 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2334
2335 XDestroyImage(image);
2336 }
2337
2338 void
2339 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2340 {
2341 XImage *image;
2342 uint8 *data;
2343
2344 offset *= g_bpp / 8;
2345 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2346 if (data == NULL)
2347 return;
2348
2349 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2350 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2351
2352 if (g_ownbackstore)
2353 {
2354 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2355 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2356 }
2357 else
2358 {
2359 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2360 }
2361
2362 XFree(image);
2363 }
2364
2365 /* these do nothing here but are used in uiports */
2366 void
2367 ui_begin_update(void)
2368 {
2369 }
2370
2371 void
2372 ui_end_update(void)
2373 {
2374 }

  ViewVC Help
Powered by ViewVC 1.1.26