/[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 524 - (show annotations)
Wed Oct 29 06:29:05 2003 UTC (20 years, 6 months ago) by matthewc
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 43427 byte(s)
Hopefully make it work with both RGB and BGR X servers.

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

  ViewVC Help
Powered by ViewVC 1.1.26