/[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 537 - (show annotations)
Fri Oct 31 04:51:10 2003 UTC (20 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 43576 byte(s)
Need unistd.h for select.

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 ui_destroy_cursor(g_null_cursor);
949
950 if (g_IC != NULL)
951 XDestroyIC(g_IC);
952
953 XDestroyWindow(g_display, g_wnd);
954 }
955
956 void
957 xwin_toggle_fullscreen(void)
958 {
959 Pixmap contents = 0;
960
961 if (!g_ownbackstore)
962 {
963 /* need to save contents of window */
964 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
965 XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
966 }
967
968 ui_destroy_window();
969 g_fullscreen = !g_fullscreen;
970 ui_create_window();
971
972 XDefineCursor(g_display, g_wnd, g_current_cursor);
973
974 if (!g_ownbackstore)
975 {
976 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
977 XFreePixmap(g_display, contents);
978 }
979 }
980
981 /* Process all events in Xlib queue
982 Returns 0 after user quit, 1 otherwise */
983 static int
984 xwin_process_events(void)
985 {
986 XEvent xevent;
987 KeySym keysym;
988 uint16 button, flags;
989 uint32 ev_time;
990 key_translation tr;
991 char str[256];
992 Status status;
993 unsigned int state;
994 Window wdummy;
995 int dummy;
996
997 while (XPending(g_display) > 0)
998 {
999 XNextEvent(g_display, &xevent);
1000
1001 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1002 {
1003 DEBUG_KBD(("Filtering event\n"));
1004 continue;
1005 }
1006
1007 flags = 0;
1008
1009 switch (xevent.type)
1010 {
1011 case ClientMessage:
1012 /* the window manager told us to quit */
1013 if ((xevent.xclient.message_type == g_protocol_atom)
1014 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1015 /* Quit */
1016 return 0;
1017 break;
1018
1019 case KeyPress:
1020 g_last_gesturetime = xevent.xkey.time;
1021 if (g_IC != NULL)
1022 /* Multi_key compatible version */
1023 {
1024 XmbLookupString(g_IC,
1025 &xevent.xkey, str, sizeof(str), &keysym,
1026 &status);
1027 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1028 {
1029 error("XmbLookupString failed with status 0x%x\n",
1030 status);
1031 break;
1032 }
1033 }
1034 else
1035 {
1036 /* Plain old XLookupString */
1037 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1038 XLookupString((XKeyEvent *) & xevent,
1039 str, sizeof(str), &keysym, NULL);
1040 }
1041
1042 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1043 get_ksname(keysym)));
1044
1045 ev_time = time(NULL);
1046 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1047 break;
1048
1049 tr = xkeymap_translate_key(keysym,
1050 xevent.xkey.keycode, xevent.xkey.state);
1051
1052 if (tr.scancode == 0)
1053 break;
1054
1055 save_remote_modifiers(tr.scancode);
1056 ensure_remote_modifiers(ev_time, tr);
1057 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1058 restore_remote_modifiers(ev_time, tr.scancode);
1059
1060 break;
1061
1062 case KeyRelease:
1063 g_last_gesturetime = xevent.xkey.time;
1064 XLookupString((XKeyEvent *) & xevent, str,
1065 sizeof(str), &keysym, NULL);
1066
1067 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1068 get_ksname(keysym)));
1069
1070 ev_time = time(NULL);
1071 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1072 break;
1073
1074 tr = xkeymap_translate_key(keysym,
1075 xevent.xkey.keycode, xevent.xkey.state);
1076
1077 if (tr.scancode == 0)
1078 break;
1079
1080 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1081 break;
1082
1083 case ButtonPress:
1084 flags = MOUSE_FLAG_DOWN;
1085 /* fall through */
1086
1087 case ButtonRelease:
1088 g_last_gesturetime = xevent.xbutton.time;
1089 button = xkeymap_translate_button(xevent.xbutton.button);
1090 if (button == 0)
1091 break;
1092
1093 /* If win_button_size is nonzero, enable single app mode */
1094 if (xevent.xbutton.y < g_win_button_size)
1095 {
1096 /* Stop moving window when button is released, regardless of cursor position */
1097 if (g_moving_wnd && (xevent.type == ButtonRelease))
1098 g_moving_wnd = False;
1099
1100 /* Check from right to left: */
1101
1102 if (xevent.xbutton.x >= g_width - g_win_button_size)
1103 {
1104 /* The close button, continue */
1105 ;
1106 }
1107 else if (xevent.xbutton.x >=
1108 g_width - g_win_button_size * 2)
1109 {
1110 /* The maximize/restore button. Do not send to
1111 server. It might be a good idea to change the
1112 cursor or give some other visible indication
1113 that rdesktop inhibited this click */
1114 break;
1115 }
1116 else if (xevent.xbutton.x >=
1117 g_width - g_win_button_size * 3)
1118 {
1119 /* The minimize button. Iconify window. */
1120 XIconifyWindow(g_display, g_wnd,
1121 DefaultScreen(g_display));
1122 break;
1123 }
1124 else if (xevent.xbutton.x <= g_win_button_size)
1125 {
1126 /* The system menu. Ignore. */
1127 break;
1128 }
1129 else
1130 {
1131 /* The title bar. */
1132 if ((xevent.type == ButtonPress) && !g_fullscreen
1133 && g_hide_decorations)
1134 {
1135 g_moving_wnd = True;
1136 g_move_x_offset = xevent.xbutton.x;
1137 g_move_y_offset = xevent.xbutton.y;
1138 }
1139 break;
1140
1141 }
1142 }
1143
1144 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1145 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1146 break;
1147
1148 case MotionNotify:
1149 if (g_moving_wnd)
1150 {
1151 XMoveWindow(g_display, g_wnd,
1152 xevent.xmotion.x_root - g_move_x_offset,
1153 xevent.xmotion.y_root - g_move_y_offset);
1154 break;
1155 }
1156
1157 if (g_fullscreen && !g_focused)
1158 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1159 CurrentTime);
1160 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1161 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1162 break;
1163
1164 case FocusIn:
1165 if (xevent.xfocus.mode == NotifyGrab)
1166 break;
1167 g_focused = True;
1168 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
1169 &dummy, &dummy, &state);
1170 reset_modifier_keys(state);
1171 if (g_grab_keyboard && g_mouse_in_wnd)
1172 XGrabKeyboard(g_display, g_wnd, True,
1173 GrabModeAsync, GrabModeAsync, CurrentTime);
1174 break;
1175
1176 case FocusOut:
1177 if (xevent.xfocus.mode == NotifyUngrab)
1178 break;
1179 g_focused = False;
1180 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1181 XUngrabKeyboard(g_display, CurrentTime);
1182 break;
1183
1184 case EnterNotify:
1185 /* we only register for this event when in fullscreen mode */
1186 /* or grab_keyboard */
1187 g_mouse_in_wnd = True;
1188 if (g_fullscreen)
1189 {
1190 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1191 CurrentTime);
1192 break;
1193 }
1194 if (g_focused)
1195 XGrabKeyboard(g_display, g_wnd, True,
1196 GrabModeAsync, GrabModeAsync, CurrentTime);
1197 break;
1198
1199 case LeaveNotify:
1200 /* we only register for this event when grab_keyboard */
1201 g_mouse_in_wnd = False;
1202 XUngrabKeyboard(g_display, CurrentTime);
1203 break;
1204
1205 case Expose:
1206 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1207 xevent.xexpose.x, xevent.xexpose.y,
1208 xevent.xexpose.width,
1209 xevent.xexpose.height,
1210 xevent.xexpose.x, xevent.xexpose.y);
1211 break;
1212
1213 case MappingNotify:
1214 /* Refresh keyboard mapping if it has changed. This is important for
1215 Xvnc, since it allocates keycodes dynamically */
1216 if (xevent.xmapping.request == MappingKeyboard
1217 || xevent.xmapping.request == MappingModifier)
1218 XRefreshKeyboardMapping(&xevent.xmapping);
1219
1220 if (xevent.xmapping.request == MappingModifier)
1221 {
1222 XFreeModifiermap(g_mod_map);
1223 g_mod_map = XGetModifierMapping(g_display);
1224 }
1225 break;
1226
1227 /* clipboard stuff */
1228 case SelectionNotify:
1229 xclip_handle_SelectionNotify(&xevent.xselection);
1230 break;
1231 case SelectionRequest:
1232 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1233 break;
1234 case SelectionClear:
1235 xclip_handle_SelectionClear();
1236 break;
1237 case PropertyNotify:
1238 xclip_handle_PropertyNotify(&xevent.xproperty);
1239 break;
1240 }
1241 }
1242 /* Keep going */
1243 return 1;
1244 }
1245
1246 /* Returns 0 after user quit, 1 otherwise */
1247 int
1248 ui_select(int rdp_socket)
1249 {
1250 int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1251 fd_set rfds, wfds;
1252
1253 while (True)
1254 {
1255 /* Process any events already waiting */
1256 if (!xwin_process_events())
1257 /* User quit */
1258 return 0;
1259
1260 FD_ZERO(&rfds);
1261 FD_ZERO(&wfds);
1262 FD_SET(rdp_socket, &rfds);
1263 FD_SET(g_x_socket, &rfds);
1264
1265 #ifdef WITH_RDPSND
1266 /* FIXME: there should be an API for registering fds */
1267 if (g_dsp_busy)
1268 {
1269 FD_SET(g_dsp_fd, &wfds);
1270 n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;
1271 }
1272 #endif
1273
1274 switch (select(n, &rfds, &wfds, NULL, NULL))
1275 {
1276 case -1:
1277 error("select: %s\n", strerror(errno));
1278
1279 case 0:
1280 continue;
1281 }
1282
1283 if (FD_ISSET(rdp_socket, &rfds))
1284 return 1;
1285
1286 #ifdef WITH_RDPSND
1287 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1288 wave_out_play();
1289 #endif
1290 }
1291 }
1292
1293 void
1294 ui_move_pointer(int x, int y)
1295 {
1296 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1297 }
1298
1299 HBITMAP
1300 ui_create_bitmap(int width, int height, uint8 * data)
1301 {
1302 XImage *image;
1303 Pixmap bitmap;
1304 uint8 *tdata;
1305 int bitmap_pad;
1306
1307 if (g_server_bpp == 8)
1308 {
1309 bitmap_pad = 8;
1310 }
1311 else
1312 {
1313 bitmap_pad = g_bpp;
1314
1315 if (g_bpp == 24)
1316 bitmap_pad = 32;
1317 }
1318
1319 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1320 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1321 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1322 (char *) tdata, width, height, bitmap_pad, 0);
1323
1324 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1325
1326 XFree(image);
1327 if (!g_owncolmap)
1328 xfree(tdata);
1329 return (HBITMAP) bitmap;
1330 }
1331
1332 void
1333 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1334 {
1335 XImage *image;
1336 uint8 *tdata;
1337 int bitmap_pad;
1338
1339 if (g_server_bpp == 8)
1340 {
1341 bitmap_pad = 8;
1342 }
1343 else
1344 {
1345 bitmap_pad = g_bpp;
1346
1347 if (g_bpp == 24)
1348 bitmap_pad = 32;
1349 }
1350
1351 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1352 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1353 (char *) tdata, width, height, bitmap_pad, 0);
1354
1355 if (g_ownbackstore)
1356 {
1357 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1358 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1359 }
1360 else
1361 {
1362 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1363 }
1364
1365 XFree(image);
1366 if (!g_owncolmap)
1367 xfree(tdata);
1368 }
1369
1370 void
1371 ui_destroy_bitmap(HBITMAP bmp)
1372 {
1373 XFreePixmap(g_display, (Pixmap) bmp);
1374 }
1375
1376 HGLYPH
1377 ui_create_glyph(int width, int height, uint8 * data)
1378 {
1379 XImage *image;
1380 Pixmap bitmap;
1381 int scanline;
1382 GC gc;
1383
1384 scanline = (width + 7) / 8;
1385
1386 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1387 gc = XCreateGC(g_display, bitmap, 0, NULL);
1388
1389 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1390 width, height, 8, scanline);
1391 image->byte_order = MSBFirst;
1392 image->bitmap_bit_order = MSBFirst;
1393 XInitImage(image);
1394
1395 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1396
1397 XFree(image);
1398 XFreeGC(g_display, gc);
1399 return (HGLYPH) bitmap;
1400 }
1401
1402 void
1403 ui_destroy_glyph(HGLYPH glyph)
1404 {
1405 XFreePixmap(g_display, (Pixmap) glyph);
1406 }
1407
1408 HCURSOR
1409 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1410 uint8 * andmask, uint8 * xormask)
1411 {
1412 HGLYPH maskglyph, cursorglyph;
1413 XColor bg, fg;
1414 Cursor xcursor;
1415 uint8 *cursor, *pcursor;
1416 uint8 *mask, *pmask;
1417 uint8 nextbit;
1418 int scanline, offset;
1419 int i, j;
1420
1421 scanline = (width + 7) / 8;
1422 offset = scanline * height;
1423
1424 cursor = (uint8 *) xmalloc(offset);
1425 memset(cursor, 0, offset);
1426
1427 mask = (uint8 *) xmalloc(offset);
1428 memset(mask, 0, offset);
1429
1430 /* approximate AND and XOR masks with a monochrome X pointer */
1431 for (i = 0; i < height; i++)
1432 {
1433 offset -= scanline;
1434 pcursor = &cursor[offset];
1435 pmask = &mask[offset];
1436
1437 for (j = 0; j < scanline; j++)
1438 {
1439 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1440 {
1441 if (xormask[0] || xormask[1] || xormask[2])
1442 {
1443 *pcursor |= (~(*andmask) & nextbit);
1444 *pmask |= nextbit;
1445 }
1446 else
1447 {
1448 *pcursor |= ((*andmask) & nextbit);
1449 *pmask |= (~(*andmask) & nextbit);
1450 }
1451
1452 xormask += 3;
1453 }
1454
1455 andmask++;
1456 pcursor++;
1457 pmask++;
1458 }
1459 }
1460
1461 fg.red = fg.blue = fg.green = 0xffff;
1462 bg.red = bg.blue = bg.green = 0x0000;
1463 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1464
1465 cursorglyph = ui_create_glyph(width, height, cursor);
1466 maskglyph = ui_create_glyph(width, height, mask);
1467
1468 xcursor =
1469 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1470 (Pixmap) maskglyph, &fg, &bg, x, y);
1471
1472 ui_destroy_glyph(maskglyph);
1473 ui_destroy_glyph(cursorglyph);
1474 xfree(mask);
1475 xfree(cursor);
1476 return (HCURSOR) xcursor;
1477 }
1478
1479 void
1480 ui_set_cursor(HCURSOR cursor)
1481 {
1482 g_current_cursor = (Cursor) cursor;
1483 XDefineCursor(g_display, g_wnd, g_current_cursor);
1484 }
1485
1486 void
1487 ui_destroy_cursor(HCURSOR cursor)
1488 {
1489 XFreeCursor(g_display, (Cursor) cursor);
1490 }
1491
1492 void
1493 ui_set_null_cursor(void)
1494 {
1495 ui_set_cursor(g_null_cursor);
1496 }
1497
1498 #define MAKE_XCOLOR(xc,c) \
1499 (xc)->red = ((c)->red << 8) | (c)->red; \
1500 (xc)->green = ((c)->green << 8) | (c)->green; \
1501 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1502 (xc)->flags = DoRed | DoGreen | DoBlue;
1503
1504
1505 HCOLOURMAP
1506 ui_create_colourmap(COLOURMAP * colours)
1507 {
1508 COLOURENTRY *entry;
1509 int i, ncolours = colours->ncolours;
1510 if (!g_owncolmap)
1511 {
1512 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1513 XColor xentry;
1514 XColor xc_cache[256];
1515 uint32 colour;
1516 int colLookup = 256;
1517 for (i = 0; i < ncolours; i++)
1518 {
1519 entry = &colours->colours[i];
1520 MAKE_XCOLOR(&xentry, entry);
1521
1522 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1523 {
1524 /* Allocation failed, find closest match. */
1525 int j = 256;
1526 int nMinDist = 3 * 256 * 256;
1527 long nDist = nMinDist;
1528
1529 /* only get the colors once */
1530 while (colLookup--)
1531 {
1532 xc_cache[colLookup].pixel = colLookup;
1533 xc_cache[colLookup].red = xc_cache[colLookup].green =
1534 xc_cache[colLookup].blue = 0;
1535 xc_cache[colLookup].flags = 0;
1536 XQueryColor(g_display,
1537 DefaultColormap(g_display,
1538 DefaultScreen(g_display)),
1539 &xc_cache[colLookup]);
1540 }
1541 colLookup = 0;
1542
1543 /* approximate the pixel */
1544 while (j--)
1545 {
1546 if (xc_cache[j].flags)
1547 {
1548 nDist = ((long) (xc_cache[j].red >> 8) -
1549 (long) (xentry.red >> 8)) *
1550 ((long) (xc_cache[j].red >> 8) -
1551 (long) (xentry.red >> 8)) +
1552 ((long) (xc_cache[j].green >> 8) -
1553 (long) (xentry.green >> 8)) *
1554 ((long) (xc_cache[j].green >> 8) -
1555 (long) (xentry.green >> 8)) +
1556 ((long) (xc_cache[j].blue >> 8) -
1557 (long) (xentry.blue >> 8)) *
1558 ((long) (xc_cache[j].blue >> 8) -
1559 (long) (xentry.blue >> 8));
1560 }
1561 if (nDist < nMinDist)
1562 {
1563 nMinDist = nDist;
1564 xentry.pixel = j;
1565 }
1566 }
1567 }
1568 colour = xentry.pixel;
1569
1570 /* update our cache */
1571 if (xentry.pixel < 256)
1572 {
1573 xc_cache[xentry.pixel].red = xentry.red;
1574 xc_cache[xentry.pixel].green = xentry.green;
1575 xc_cache[xentry.pixel].blue = xentry.blue;
1576
1577 }
1578
1579 map[i] = 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