/[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 543 - (show annotations)
Mon Nov 3 13:33:35 2003 UTC (20 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 43378 byte(s)
Re-worked numlock handling: Keeping remote numlock state in sync with local state

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

  ViewVC Help
Powered by ViewVC 1.1.26