/[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 795 - (show annotations)
Wed Nov 3 13:56:52 2004 UTC (19 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 48497 byte(s)
Big serial- and disk-redirection update from
Andreas Flick <Andreas.Flick@unicon-ka.de>

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

  ViewVC Help
Powered by ViewVC 1.1.26