/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 788 - (show annotations)
Thu Oct 21 08:43:22 2004 UTC (19 years, 7 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 48557 byte(s)
null_pointer_data must actually be 24 bytes. Fixes another Valgrind
warning.

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 /* TODO: if tv.tv_sec just times out
1439 * we will segfault.
1440 * FIXME:
1441 */
1442 //s_timeout = True;
1443 //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1444 continue;
1445 }
1446
1447 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1448
1449 if (FD_ISSET(rdp_socket, &rfds))
1450 return 1;
1451
1452 #ifdef WITH_RDPSND
1453 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1454 wave_out_play();
1455 #endif
1456 }
1457 }
1458
1459 void
1460 ui_move_pointer(int x, int y)
1461 {
1462 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1463 }
1464
1465 HBITMAP
1466 ui_create_bitmap(int width, int height, uint8 * data)
1467 {
1468 XImage *image;
1469 Pixmap bitmap;
1470 uint8 *tdata;
1471 int bitmap_pad;
1472
1473 if (g_server_bpp == 8)
1474 {
1475 bitmap_pad = 8;
1476 }
1477 else
1478 {
1479 bitmap_pad = g_bpp;
1480
1481 if (g_bpp == 24)
1482 bitmap_pad = 32;
1483 }
1484
1485 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1486 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1487 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1488 (char *) tdata, width, height, bitmap_pad, 0);
1489
1490 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1491
1492 XFree(image);
1493 if (tdata != data)
1494 xfree(tdata);
1495 return (HBITMAP) bitmap;
1496 }
1497
1498 void
1499 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1500 {
1501 XImage *image;
1502 uint8 *tdata;
1503 int bitmap_pad;
1504
1505 if (g_server_bpp == 8)
1506 {
1507 bitmap_pad = 8;
1508 }
1509 else
1510 {
1511 bitmap_pad = g_bpp;
1512
1513 if (g_bpp == 24)
1514 bitmap_pad = 32;
1515 }
1516
1517 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1518 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1519 (char *) tdata, width, height, bitmap_pad, 0);
1520
1521 if (g_ownbackstore)
1522 {
1523 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1524 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1525 }
1526 else
1527 {
1528 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1529 }
1530
1531 XFree(image);
1532 if (tdata != data)
1533 xfree(tdata);
1534 }
1535
1536 void
1537 ui_destroy_bitmap(HBITMAP bmp)
1538 {
1539 XFreePixmap(g_display, (Pixmap) bmp);
1540 }
1541
1542 HGLYPH
1543 ui_create_glyph(int width, int height, uint8 * data)
1544 {
1545 XImage *image;
1546 Pixmap bitmap;
1547 int scanline;
1548
1549 scanline = (width + 7) / 8;
1550
1551 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1552 if (g_create_glyph_gc == 0)
1553 g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1554
1555 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1556 width, height, 8, scanline);
1557 image->byte_order = MSBFirst;
1558 image->bitmap_bit_order = MSBFirst;
1559 XInitImage(image);
1560
1561 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1562
1563 XFree(image);
1564 return (HGLYPH) bitmap;
1565 }
1566
1567 void
1568 ui_destroy_glyph(HGLYPH glyph)
1569 {
1570 XFreePixmap(g_display, (Pixmap) glyph);
1571 }
1572
1573 HCURSOR
1574 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1575 uint8 * andmask, uint8 * xormask)
1576 {
1577 HGLYPH maskglyph, cursorglyph;
1578 XColor bg, fg;
1579 Cursor xcursor;
1580 uint8 *cursor, *pcursor;
1581 uint8 *mask, *pmask;
1582 uint8 nextbit;
1583 int scanline, offset;
1584 int i, j;
1585
1586 scanline = (width + 7) / 8;
1587 offset = scanline * height;
1588
1589 cursor = (uint8 *) xmalloc(offset);
1590 memset(cursor, 0, offset);
1591
1592 mask = (uint8 *) xmalloc(offset);
1593 memset(mask, 0, offset);
1594
1595 /* approximate AND and XOR masks with a monochrome X pointer */
1596 for (i = 0; i < height; i++)
1597 {
1598 offset -= scanline;
1599 pcursor = &cursor[offset];
1600 pmask = &mask[offset];
1601
1602 for (j = 0; j < scanline; j++)
1603 {
1604 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1605 {
1606 if (xormask[0] || xormask[1] || xormask[2])
1607 {
1608 *pcursor |= (~(*andmask) & nextbit);
1609 *pmask |= nextbit;
1610 }
1611 else
1612 {
1613 *pcursor |= ((*andmask) & nextbit);
1614 *pmask |= (~(*andmask) & nextbit);
1615 }
1616
1617 xormask += 3;
1618 }
1619
1620 andmask++;
1621 pcursor++;
1622 pmask++;
1623 }
1624 }
1625
1626 fg.red = fg.blue = fg.green = 0xffff;
1627 bg.red = bg.blue = bg.green = 0x0000;
1628 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1629
1630 cursorglyph = ui_create_glyph(width, height, cursor);
1631 maskglyph = ui_create_glyph(width, height, mask);
1632
1633 xcursor =
1634 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1635 (Pixmap) maskglyph, &fg, &bg, x, y);
1636
1637 ui_destroy_glyph(maskglyph);
1638 ui_destroy_glyph(cursorglyph);
1639 xfree(mask);
1640 xfree(cursor);
1641 return (HCURSOR) xcursor;
1642 }
1643
1644 void
1645 ui_set_cursor(HCURSOR cursor)
1646 {
1647 g_current_cursor = (Cursor) cursor;
1648 XDefineCursor(g_display, g_wnd, g_current_cursor);
1649 }
1650
1651 void
1652 ui_destroy_cursor(HCURSOR cursor)
1653 {
1654 XFreeCursor(g_display, (Cursor) cursor);
1655 }
1656
1657 void
1658 ui_set_null_cursor(void)
1659 {
1660 ui_set_cursor(g_null_cursor);
1661 }
1662
1663 #define MAKE_XCOLOR(xc,c) \
1664 (xc)->red = ((c)->red << 8) | (c)->red; \
1665 (xc)->green = ((c)->green << 8) | (c)->green; \
1666 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1667 (xc)->flags = DoRed | DoGreen | DoBlue;
1668
1669
1670 HCOLOURMAP
1671 ui_create_colourmap(COLOURMAP * colours)
1672 {
1673 COLOURENTRY *entry;
1674 int i, ncolours = colours->ncolours;
1675 if (!g_owncolmap)
1676 {
1677 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1678 XColor xentry;
1679 XColor xc_cache[256];
1680 uint32 colour;
1681 int colLookup = 256;
1682 for (i = 0; i < ncolours; i++)
1683 {
1684 entry = &colours->colours[i];
1685 MAKE_XCOLOR(&xentry, entry);
1686
1687 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1688 {
1689 /* Allocation failed, find closest match. */
1690 int j = 256;
1691 int nMinDist = 3 * 256 * 256;
1692 long nDist = nMinDist;
1693
1694 /* only get the colors once */
1695 while (colLookup--)
1696 {
1697 xc_cache[colLookup].pixel = colLookup;
1698 xc_cache[colLookup].red = xc_cache[colLookup].green =
1699 xc_cache[colLookup].blue = 0;
1700 xc_cache[colLookup].flags = 0;
1701 XQueryColor(g_display,
1702 DefaultColormap(g_display,
1703 DefaultScreen(g_display)),
1704 &xc_cache[colLookup]);
1705 }
1706 colLookup = 0;
1707
1708 /* approximate the pixel */
1709 while (j--)
1710 {
1711 if (xc_cache[j].flags)
1712 {
1713 nDist = ((long) (xc_cache[j].red >> 8) -
1714 (long) (xentry.red >> 8)) *
1715 ((long) (xc_cache[j].red >> 8) -
1716 (long) (xentry.red >> 8)) +
1717 ((long) (xc_cache[j].green >> 8) -
1718 (long) (xentry.green >> 8)) *
1719 ((long) (xc_cache[j].green >> 8) -
1720 (long) (xentry.green >> 8)) +
1721 ((long) (xc_cache[j].blue >> 8) -
1722 (long) (xentry.blue >> 8)) *
1723 ((long) (xc_cache[j].blue >> 8) -
1724 (long) (xentry.blue >> 8));
1725 }
1726 if (nDist < nMinDist)
1727 {
1728 nMinDist = nDist;
1729 xentry.pixel = j;
1730 }
1731 }
1732 }
1733 colour = xentry.pixel;
1734
1735 /* update our cache */
1736 if (xentry.pixel < 256)
1737 {
1738 xc_cache[xentry.pixel].red = xentry.red;
1739 xc_cache[xentry.pixel].green = xentry.green;
1740 xc_cache[xentry.pixel].blue = xentry.blue;
1741
1742 }
1743
1744 map[i] = colour;
1745 }
1746 return map;
1747 }
1748 else
1749 {
1750 XColor *xcolours, *xentry;
1751 Colormap map;
1752
1753 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1754 for (i = 0; i < ncolours; i++)
1755 {
1756 entry = &colours->colours[i];
1757 xentry = &xcolours[i];
1758 xentry->pixel = i;
1759 MAKE_XCOLOR(xentry, entry);
1760 }
1761
1762 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1763 XStoreColors(g_display, map, xcolours, ncolours);
1764
1765 xfree(xcolours);
1766 return (HCOLOURMAP) map;
1767 }
1768 }
1769
1770 void
1771 ui_destroy_colourmap(HCOLOURMAP map)
1772 {
1773 if (!g_owncolmap)
1774 xfree(map);
1775 else
1776 XFreeColormap(g_display, (Colormap) map);
1777 }
1778
1779 void
1780 ui_set_colourmap(HCOLOURMAP map)
1781 {
1782 if (!g_owncolmap)
1783 {
1784 if (g_colmap)
1785 xfree(g_colmap);
1786
1787 g_colmap = (uint32 *) map;
1788 }
1789 else
1790 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1791 }
1792
1793 void
1794 ui_set_clip(int x, int y, int cx, int cy)
1795 {
1796 XRectangle rect;
1797
1798 rect.x = x;
1799 rect.y = y;
1800 rect.width = cx;
1801 rect.height = cy;
1802 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1803 }
1804
1805 void
1806 ui_reset_clip(void)
1807 {
1808 XRectangle rect;
1809
1810 rect.x = 0;
1811 rect.y = 0;
1812 rect.width = g_width;
1813 rect.height = g_height;
1814 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1815 }
1816
1817 void
1818 ui_bell(void)
1819 {
1820 XBell(g_display, 0);
1821 }
1822
1823 void
1824 ui_destblt(uint8 opcode,
1825 /* dest */ int x, int y, int cx, int cy)
1826 {
1827 SET_FUNCTION(opcode);
1828 FILL_RECTANGLE(x, y, cx, cy);
1829 RESET_FUNCTION(opcode);
1830 }
1831
1832 static uint8 hatch_patterns[] = {
1833 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1834 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1835 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1836 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1837 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1838 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1839 };
1840
1841 void
1842 ui_patblt(uint8 opcode,
1843 /* dest */ int x, int y, int cx, int cy,
1844 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1845 {
1846 Pixmap fill;
1847 uint8 i, ipattern[8];
1848
1849 SET_FUNCTION(opcode);
1850
1851 switch (brush->style)
1852 {
1853 case 0: /* Solid */
1854 SET_FOREGROUND(fgcolour);
1855 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1856 break;
1857
1858 case 2: /* Hatch */
1859 fill = (Pixmap) ui_create_glyph(8, 8,
1860 hatch_patterns + brush->pattern[0] * 8);
1861 SET_FOREGROUND(fgcolour);
1862 SET_BACKGROUND(bgcolour);
1863 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1864 XSetStipple(g_display, g_gc, fill);
1865 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1866 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1867 XSetFillStyle(g_display, g_gc, FillSolid);
1868 XSetTSOrigin(g_display, g_gc, 0, 0);
1869 ui_destroy_glyph((HGLYPH) fill);
1870 break;
1871
1872 case 3: /* Pattern */
1873 for (i = 0; i != 8; i++)
1874 ipattern[7 - i] = brush->pattern[i];
1875 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1876 SET_FOREGROUND(bgcolour);
1877 SET_BACKGROUND(fgcolour);
1878 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1879 XSetStipple(g_display, g_gc, fill);
1880 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1881 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1882 XSetFillStyle(g_display, g_gc, FillSolid);
1883 XSetTSOrigin(g_display, g_gc, 0, 0);
1884 ui_destroy_glyph((HGLYPH) fill);
1885 break;
1886
1887 default:
1888 unimpl("brush %d\n", brush->style);
1889 }
1890
1891 RESET_FUNCTION(opcode);
1892
1893 if (g_ownbackstore)
1894 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1895 }
1896
1897 void
1898 ui_screenblt(uint8 opcode,
1899 /* dest */ int x, int y, int cx, int cy,
1900 /* src */ int srcx, int srcy)
1901 {
1902 SET_FUNCTION(opcode);
1903 if (g_ownbackstore)
1904 {
1905 if (g_Unobscured)
1906 {
1907 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1908 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1909 y);
1910 }
1911 else
1912 {
1913 XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1914 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1915 y);
1916 }
1917 }
1918 else
1919 {
1920 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1921 }
1922 RESET_FUNCTION(opcode);
1923 }
1924
1925 void
1926 ui_memblt(uint8 opcode,
1927 /* dest */ int x, int y, int cx, int cy,
1928 /* src */ HBITMAP src, int srcx, int srcy)
1929 {
1930 SET_FUNCTION(opcode);
1931 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1932 if (g_ownbackstore)
1933 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1934 RESET_FUNCTION(opcode);
1935 }
1936
1937 void
1938 ui_triblt(uint8 opcode,
1939 /* dest */ int x, int y, int cx, int cy,
1940 /* src */ HBITMAP src, int srcx, int srcy,
1941 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1942 {
1943 /* This is potentially difficult to do in general. Until someone
1944 comes up with a more efficient way of doing it I am using cases. */
1945
1946 switch (opcode)
1947 {
1948 case 0x69: /* PDSxxn */
1949 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1950 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1951 break;
1952
1953 case 0xb8: /* PSDPxax */
1954 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1955 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1956 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1957 break;
1958
1959 case 0xc0: /* PSa */
1960 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1961 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1962 break;
1963
1964 default:
1965 unimpl("triblt 0x%x\n", opcode);
1966 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1967 }
1968 }
1969
1970 void
1971 ui_line(uint8 opcode,
1972 /* dest */ int startx, int starty, int endx, int endy,
1973 /* pen */ PEN * pen)
1974 {
1975 SET_FUNCTION(opcode);
1976 SET_FOREGROUND(pen->colour);
1977 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1978 if (g_ownbackstore)
1979 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1980 RESET_FUNCTION(opcode);
1981 }
1982
1983 void
1984 ui_rect(
1985 /* dest */ int x, int y, int cx, int cy,
1986 /* brush */ int colour)
1987 {
1988 SET_FOREGROUND(colour);
1989 FILL_RECTANGLE(x, y, cx, cy);
1990 }
1991
1992 /* warning, this function only draws on wnd or backstore, not both */
1993 void
1994 ui_draw_glyph(int mixmode,
1995 /* dest */ int x, int y, int cx, int cy,
1996 /* src */ HGLYPH glyph, int srcx, int srcy,
1997 int bgcolour, int fgcolour)
1998 {
1999 SET_FOREGROUND(fgcolour);
2000 SET_BACKGROUND(bgcolour);
2001
2002 XSetFillStyle(g_display, g_gc,
2003 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2004 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2005 XSetTSOrigin(g_display, g_gc, x, y);
2006
2007 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2008
2009 XSetFillStyle(g_display, g_gc, FillSolid);
2010 }
2011
2012 #define DO_GLYPH(ttext,idx) \
2013 {\
2014 glyph = cache_get_font (font, ttext[idx]);\
2015 if (!(flags & TEXT2_IMPLICIT_X))\
2016 {\
2017 xyoffset = ttext[++idx];\
2018 if ((xyoffset & 0x80))\
2019 {\
2020 if (flags & TEXT2_VERTICAL)\
2021 y += ttext[idx+1] | (ttext[idx+2] << 8);\
2022 else\
2023 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2024 idx += 2;\
2025 }\
2026 else\
2027 {\
2028 if (flags & TEXT2_VERTICAL)\
2029 y += xyoffset;\
2030 else\
2031 x += xyoffset;\
2032 }\
2033 }\
2034 if (glyph != NULL)\
2035 {\
2036 x1 = x + glyph->offset;\
2037 y1 = y + glyph->baseline;\
2038 XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2039 XSetTSOrigin(g_display, g_gc, x1, y1);\
2040 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2041 if (flags & TEXT2_IMPLICIT_X)\
2042 x += glyph->width;\
2043 }\
2044 }
2045
2046 void
2047 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
2048 int clipx, int clipy, int clipcx, int clipcy,
2049 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
2050 int fgcolour, uint8 * text, uint8 length)
2051 {
2052 FONTGLYPH *glyph;
2053 int i, j, xyoffset, x1, y1;
2054 DATABLOB *entry;
2055
2056 SET_FOREGROUND(bgcolour);
2057
2058 /* Sometimes, the boxcx value is something really large, like
2059 32691. This makes XCopyArea fail with Xvnc. The code below
2060 is a quick fix. */
2061 if (boxx + boxcx > g_width)
2062 boxcx = g_width - boxx;
2063
2064 if (boxcx > 1)
2065 {
2066 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2067 }
2068 else if (mixmode == MIX_OPAQUE)
2069 {
2070 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2071 }
2072
2073 SET_FOREGROUND(fgcolour);
2074 SET_BACKGROUND(bgcolour);
2075 XSetFillStyle(g_display, g_gc, FillStippled);
2076
2077 /* Paint text, character by character */
2078 for (i = 0; i < length;)
2079 {
2080 switch (text[i])
2081 {
2082 case 0xff:
2083 if (i + 2 < length)
2084 cache_put_text(text[i + 1], text, text[i + 2]);
2085 else
2086 {
2087 error("this shouldn't be happening\n");
2088 exit(1);
2089 }
2090 /* this will move pointer from start to first character after FF command */
2091 length -= i + 3;
2092 text = &(text[i + 3]);
2093 i = 0;
2094 break;
2095
2096 case 0xfe:
2097 entry = cache_get_text(text[i + 1]);
2098 if (entry != NULL)
2099 {
2100 if ((((uint8 *) (entry->data))[1] ==
2101 0) && (!(flags & TEXT2_IMPLICIT_X)))
2102 {
2103 if (flags & TEXT2_VERTICAL)
2104 y += text[i + 2];
2105 else
2106 x += text[i + 2];
2107 }
2108 for (j = 0; j < entry->size; j++)
2109 DO_GLYPH(((uint8 *) (entry->data)), j);
2110 }
2111 if (i + 2 < length)
2112 i += 3;
2113 else
2114 i += 2;
2115 length -= i;
2116 /* this will move pointer from start to first character after FE command */
2117 text = &(text[i]);
2118 i = 0;
2119 break;
2120
2121 default:
2122 DO_GLYPH(text, i);
2123 i++;
2124 break;
2125 }
2126 }
2127
2128 XSetFillStyle(g_display, g_gc, FillSolid);
2129
2130 if (g_ownbackstore)
2131 {
2132 if (boxcx > 1)
2133 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2134 boxy, boxcx, boxcy, boxx, boxy);
2135 else
2136 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2137 clipy, clipcx, clipcy, clipx, clipy);
2138 }
2139 }
2140
2141 void
2142 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2143 {
2144 Pixmap pix;
2145 XImage *image;
2146
2147 if (g_ownbackstore)
2148 {
2149 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2150 }
2151 else
2152 {
2153 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2154 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2155 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2156 XFreePixmap(g_display, pix);
2157 }
2158
2159 offset *= g_bpp / 8;
2160 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2161
2162 XDestroyImage(image);
2163 }
2164
2165 void
2166 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2167 {
2168 XImage *image;
2169 uint8 *data;
2170
2171 offset *= g_bpp / 8;
2172 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2173 if (data == NULL)
2174 return;
2175
2176 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2177 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2178
2179 if (g_ownbackstore)
2180 {
2181 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2182 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2183 }
2184 else
2185 {
2186 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2187 }
2188
2189 XFree(image);
2190 }
2191
2192 /* these do nothing here but are used in uiports */
2193 void
2194 ui_begin_update(void)
2195 {
2196 }
2197
2198 void
2199 ui_end_update(void)
2200 {
2201 }

  ViewVC Help
Powered by ViewVC 1.1.26