/[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 636 - (show annotations)
Sat Mar 13 12:08:18 2004 UTC (20 years, 2 months ago) by stargo
File MIME type: text/plain
File size: 45271 byte(s)
XEmbed-patch by Arend van Beelen jr. <arend@auton.nl>

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

  ViewVC Help
Powered by ViewVC 1.1.26