/[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 542 - (show annotations)
Mon Nov 3 13:22:09 2003 UTC (20 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 43538 byte(s)
Indent fixes

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 unsigned int state;
992 Window wdummy;
993 int dummy;
994
995 while (XPending(g_display) > 0)
996 {
997 XNextEvent(g_display, &xevent);
998
999 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1000 {
1001 DEBUG_KBD(("Filtering event\n"));
1002 continue;
1003 }
1004
1005 flags = 0;
1006
1007 switch (xevent.type)
1008 {
1009 case ClientMessage:
1010 /* the window manager told us to quit */
1011 if ((xevent.xclient.message_type == g_protocol_atom)
1012 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1013 /* Quit */
1014 return 0;
1015 break;
1016
1017 case KeyPress:
1018 g_last_gesturetime = xevent.xkey.time;
1019 if (g_IC != NULL)
1020 /* Multi_key compatible version */
1021 {
1022 XmbLookupString(g_IC,
1023 &xevent.xkey, str, sizeof(str), &keysym,
1024 &status);
1025 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1026 {
1027 error("XmbLookupString failed with status 0x%x\n",
1028 status);
1029 break;
1030 }
1031 }
1032 else
1033 {
1034 /* Plain old XLookupString */
1035 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1036 XLookupString((XKeyEvent *) & xevent,
1037 str, sizeof(str), &keysym, NULL);
1038 }
1039
1040 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1041 get_ksname(keysym)));
1042
1043 ev_time = time(NULL);
1044 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1045 break;
1046
1047 tr = xkeymap_translate_key(keysym,
1048 xevent.xkey.keycode, xevent.xkey.state);
1049
1050 if (tr.scancode == 0)
1051 break;
1052
1053 save_remote_modifiers(tr.scancode);
1054 ensure_remote_modifiers(ev_time, tr);
1055 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1056 restore_remote_modifiers(ev_time, tr.scancode);
1057
1058 break;
1059
1060 case KeyRelease:
1061 g_last_gesturetime = xevent.xkey.time;
1062 XLookupString((XKeyEvent *) & xevent, str,
1063 sizeof(str), &keysym, NULL);
1064
1065 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1066 get_ksname(keysym)));
1067
1068 ev_time = time(NULL);
1069 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1070 break;
1071
1072 tr = xkeymap_translate_key(keysym,
1073 xevent.xkey.keycode, xevent.xkey.state);
1074
1075 if (tr.scancode == 0)
1076 break;
1077
1078 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1079 break;
1080
1081 case ButtonPress:
1082 flags = MOUSE_FLAG_DOWN;
1083 /* fall through */
1084
1085 case ButtonRelease:
1086 g_last_gesturetime = xevent.xbutton.time;
1087 button = xkeymap_translate_button(xevent.xbutton.button);
1088 if (button == 0)
1089 break;
1090
1091 /* If win_button_size is nonzero, enable single app mode */
1092 if (xevent.xbutton.y < g_win_button_size)
1093 {
1094 /* Stop moving window when button is released, regardless of cursor position */
1095 if (g_moving_wnd && (xevent.type == ButtonRelease))
1096 g_moving_wnd = False;
1097
1098 /* Check from right to left: */
1099
1100 if (xevent.xbutton.x >= g_width - g_win_button_size)
1101 {
1102 /* The close button, continue */
1103 ;
1104 }
1105 else if (xevent.xbutton.x >=
1106 g_width - g_win_button_size * 2)
1107 {
1108 /* The maximize/restore button. Do not send to
1109 server. It might be a good idea to change the
1110 cursor or give some other visible indication
1111 that rdesktop inhibited this click */
1112 break;
1113 }
1114 else if (xevent.xbutton.x >=
1115 g_width - g_win_button_size * 3)
1116 {
1117 /* The minimize button. Iconify window. */
1118 XIconifyWindow(g_display, g_wnd,
1119 DefaultScreen(g_display));
1120 break;
1121 }
1122 else if (xevent.xbutton.x <= g_win_button_size)
1123 {
1124 /* The system menu. Ignore. */
1125 break;
1126 }
1127 else
1128 {
1129 /* The title bar. */
1130 if ((xevent.type == ButtonPress) && !g_fullscreen
1131 && g_hide_decorations)
1132 {
1133 g_moving_wnd = True;
1134 g_move_x_offset = xevent.xbutton.x;
1135 g_move_y_offset = xevent.xbutton.y;
1136 }
1137 break;
1138
1139 }
1140 }
1141
1142 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1143 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1144 break;
1145
1146 case MotionNotify:
1147 if (g_moving_wnd)
1148 {
1149 XMoveWindow(g_display, g_wnd,
1150 xevent.xmotion.x_root - g_move_x_offset,
1151 xevent.xmotion.y_root - g_move_y_offset);
1152 break;
1153 }
1154
1155 if (g_fullscreen && !g_focused)
1156 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1157 CurrentTime);
1158 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1159 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1160 break;
1161
1162 case FocusIn:
1163 if (xevent.xfocus.mode == NotifyGrab)
1164 break;
1165 g_focused = True;
1166 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
1167 &dummy, &dummy, &state);
1168 reset_modifier_keys(state);
1169 if (g_grab_keyboard && g_mouse_in_wnd)
1170 XGrabKeyboard(g_display, g_wnd, True,
1171 GrabModeAsync, GrabModeAsync, CurrentTime);
1172 break;
1173
1174 case FocusOut:
1175 if (xevent.xfocus.mode == NotifyUngrab)
1176 break;
1177 g_focused = False;
1178 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1179 XUngrabKeyboard(g_display, CurrentTime);
1180 break;
1181
1182 case EnterNotify:
1183 /* we only register for this event when in fullscreen mode */
1184 /* or grab_keyboard */
1185 g_mouse_in_wnd = True;
1186 if (g_fullscreen)
1187 {
1188 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1189 CurrentTime);
1190 break;
1191 }
1192 if (g_focused)
1193 XGrabKeyboard(g_display, g_wnd, True,
1194 GrabModeAsync, GrabModeAsync, CurrentTime);
1195 break;
1196
1197 case LeaveNotify:
1198 /* we only register for this event when grab_keyboard */
1199 g_mouse_in_wnd = False;
1200 XUngrabKeyboard(g_display, CurrentTime);
1201 break;
1202
1203 case Expose:
1204 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1205 xevent.xexpose.x, xevent.xexpose.y,
1206 xevent.xexpose.width,
1207 xevent.xexpose.height,
1208 xevent.xexpose.x, xevent.xexpose.y);
1209 break;
1210
1211 case MappingNotify:
1212 /* Refresh keyboard mapping if it has changed. This is important for
1213 Xvnc, since it allocates keycodes dynamically */
1214 if (xevent.xmapping.request == MappingKeyboard
1215 || xevent.xmapping.request == MappingModifier)
1216 XRefreshKeyboardMapping(&xevent.xmapping);
1217
1218 if (xevent.xmapping.request == MappingModifier)
1219 {
1220 XFreeModifiermap(g_mod_map);
1221 g_mod_map = XGetModifierMapping(g_display);
1222 }
1223 break;
1224
1225 /* clipboard stuff */
1226 case SelectionNotify:
1227 xclip_handle_SelectionNotify(&xevent.xselection);
1228 break;
1229 case SelectionRequest:
1230 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1231 break;
1232 case SelectionClear:
1233 xclip_handle_SelectionClear();
1234 break;
1235 case PropertyNotify:
1236 xclip_handle_PropertyNotify(&xevent.xproperty);
1237 break;
1238 }
1239 }
1240 /* Keep going */
1241 return 1;
1242 }
1243
1244 /* Returns 0 after user quit, 1 otherwise */
1245 int
1246 ui_select(int rdp_socket)
1247 {
1248 int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1249 fd_set rfds, wfds;
1250
1251 while (True)
1252 {
1253 /* Process any events already waiting */
1254 if (!xwin_process_events())
1255 /* User quit */
1256 return 0;
1257
1258 FD_ZERO(&rfds);
1259 FD_ZERO(&wfds);
1260 FD_SET(rdp_socket, &rfds);
1261 FD_SET(g_x_socket, &rfds);
1262
1263 #ifdef WITH_RDPSND
1264 /* FIXME: there should be an API for registering fds */
1265 if (g_dsp_busy)
1266 {
1267 FD_SET(g_dsp_fd, &wfds);
1268 n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;
1269 }
1270 #endif
1271
1272 switch (select(n, &rfds, &wfds, NULL, NULL))
1273 {
1274 case -1:
1275 error("select: %s\n", strerror(errno));
1276
1277 case 0:
1278 continue;
1279 }
1280
1281 if (FD_ISSET(rdp_socket, &rfds))
1282 return 1;
1283
1284 #ifdef WITH_RDPSND
1285 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1286 wave_out_play();
1287 #endif
1288 }
1289 }
1290
1291 void
1292 ui_move_pointer(int x, int y)
1293 {
1294 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1295 }
1296
1297 HBITMAP
1298 ui_create_bitmap(int width, int height, uint8 * data)
1299 {
1300 XImage *image;
1301 Pixmap bitmap;
1302 uint8 *tdata;
1303 int bitmap_pad;
1304
1305 if (g_server_bpp == 8)
1306 {
1307 bitmap_pad = 8;
1308 }
1309 else
1310 {
1311 bitmap_pad = g_bpp;
1312
1313 if (g_bpp == 24)
1314 bitmap_pad = 32;
1315 }
1316
1317 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1318 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1319 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1320 (char *) tdata, width, height, bitmap_pad, 0);
1321
1322 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1323
1324 XFree(image);
1325 if (!g_owncolmap)
1326 xfree(tdata);
1327 return (HBITMAP) bitmap;
1328 }
1329
1330 void
1331 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1332 {
1333 XImage *image;
1334 uint8 *tdata;
1335 int bitmap_pad;
1336
1337 if (g_server_bpp == 8)
1338 {
1339 bitmap_pad = 8;
1340 }
1341 else
1342 {
1343 bitmap_pad = g_bpp;
1344
1345 if (g_bpp == 24)
1346 bitmap_pad = 32;
1347 }
1348
1349 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1350 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1351 (char *) tdata, width, height, bitmap_pad, 0);
1352
1353 if (g_ownbackstore)
1354 {
1355 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1356 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1357 }
1358 else
1359 {
1360 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1361 }
1362
1363 XFree(image);
1364 if (!g_owncolmap)
1365 xfree(tdata);
1366 }
1367
1368 void
1369 ui_destroy_bitmap(HBITMAP bmp)
1370 {
1371 XFreePixmap(g_display, (Pixmap) bmp);
1372 }
1373
1374 HGLYPH
1375 ui_create_glyph(int width, int height, uint8 * data)
1376 {
1377 XImage *image;
1378 Pixmap bitmap;
1379 int scanline;
1380 GC gc;
1381
1382 scanline = (width + 7) / 8;
1383
1384 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1385 gc = XCreateGC(g_display, bitmap, 0, NULL);
1386
1387 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1388 width, height, 8, scanline);
1389 image->byte_order = MSBFirst;
1390 image->bitmap_bit_order = MSBFirst;
1391 XInitImage(image);
1392
1393 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1394
1395 XFree(image);
1396 XFreeGC(g_display, gc);
1397 return (HGLYPH) bitmap;
1398 }
1399
1400 void
1401 ui_destroy_glyph(HGLYPH glyph)
1402 {
1403 XFreePixmap(g_display, (Pixmap) glyph);
1404 }
1405
1406 HCURSOR
1407 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1408 uint8 * andmask, uint8 * xormask)
1409 {
1410 HGLYPH maskglyph, cursorglyph;
1411 XColor bg, fg;
1412 Cursor xcursor;
1413 uint8 *cursor, *pcursor;
1414 uint8 *mask, *pmask;
1415 uint8 nextbit;
1416 int scanline, offset;
1417 int i, j;
1418
1419 scanline = (width + 7) / 8;
1420 offset = scanline * height;
1421
1422 cursor = (uint8 *) xmalloc(offset);
1423 memset(cursor, 0, offset);
1424
1425 mask = (uint8 *) xmalloc(offset);
1426 memset(mask, 0, offset);
1427
1428 /* approximate AND and XOR masks with a monochrome X pointer */
1429 for (i = 0; i < height; i++)
1430 {
1431 offset -= scanline;
1432 pcursor = &cursor[offset];
1433 pmask = &mask[offset];
1434
1435 for (j = 0; j < scanline; j++)
1436 {
1437 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1438 {
1439 if (xormask[0] || xormask[1] || xormask[2])
1440 {
1441 *pcursor |= (~(*andmask) & nextbit);
1442 *pmask |= nextbit;
1443 }
1444 else
1445 {
1446 *pcursor |= ((*andmask) & nextbit);
1447 *pmask |= (~(*andmask) & nextbit);
1448 }
1449
1450 xormask += 3;
1451 }
1452
1453 andmask++;
1454 pcursor++;
1455 pmask++;
1456 }
1457 }
1458
1459 fg.red = fg.blue = fg.green = 0xffff;
1460 bg.red = bg.blue = bg.green = 0x0000;
1461 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1462
1463 cursorglyph = ui_create_glyph(width, height, cursor);
1464 maskglyph = ui_create_glyph(width, height, mask);
1465
1466 xcursor =
1467 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1468 (Pixmap) maskglyph, &fg, &bg, x, y);
1469
1470 ui_destroy_glyph(maskglyph);
1471 ui_destroy_glyph(cursorglyph);
1472 xfree(mask);
1473 xfree(cursor);
1474 return (HCURSOR) xcursor;
1475 }
1476
1477 void
1478 ui_set_cursor(HCURSOR cursor)
1479 {
1480 g_current_cursor = (Cursor) cursor;
1481 XDefineCursor(g_display, g_wnd, g_current_cursor);
1482 }
1483
1484 void
1485 ui_destroy_cursor(HCURSOR cursor)
1486 {
1487 XFreeCursor(g_display, (Cursor) cursor);
1488 }
1489
1490 void
1491 ui_set_null_cursor(void)
1492 {
1493 ui_set_cursor(g_null_cursor);
1494 }
1495
1496 #define MAKE_XCOLOR(xc,c) \
1497 (xc)->red = ((c)->red << 8) | (c)->red; \
1498 (xc)->green = ((c)->green << 8) | (c)->green; \
1499 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1500 (xc)->flags = DoRed | DoGreen | DoBlue;
1501
1502
1503 HCOLOURMAP
1504 ui_create_colourmap(COLOURMAP * colours)
1505 {
1506 COLOURENTRY *entry;
1507 int i, ncolours = colours->ncolours;
1508 if (!g_owncolmap)
1509 {
1510 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1511 XColor xentry;
1512 XColor xc_cache[256];
1513 uint32 colour;
1514 int colLookup = 256;
1515 for (i = 0; i < ncolours; i++)
1516 {
1517 entry = &colours->colours[i];
1518 MAKE_XCOLOR(&xentry, entry);
1519
1520 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1521 {
1522 /* Allocation failed, find closest match. */
1523 int j = 256;
1524 int nMinDist = 3 * 256 * 256;
1525 long nDist = nMinDist;
1526
1527 /* only get the colors once */
1528 while (colLookup--)
1529 {
1530 xc_cache[colLookup].pixel = colLookup;
1531 xc_cache[colLookup].red = xc_cache[colLookup].green =
1532 xc_cache[colLookup].blue = 0;
1533 xc_cache[colLookup].flags = 0;
1534 XQueryColor(g_display,
1535 DefaultColormap(g_display,
1536 DefaultScreen(g_display)),
1537 &xc_cache[colLookup]);
1538 }
1539 colLookup = 0;
1540
1541 /* approximate the pixel */
1542 while (j--)
1543 {
1544 if (xc_cache[j].flags)
1545 {
1546 nDist = ((long) (xc_cache[j].red >> 8) -
1547 (long) (xentry.red >> 8)) *
1548 ((long) (xc_cache[j].red >> 8) -
1549 (long) (xentry.red >> 8)) +
1550 ((long) (xc_cache[j].green >> 8) -
1551 (long) (xentry.green >> 8)) *
1552 ((long) (xc_cache[j].green >> 8) -
1553 (long) (xentry.green >> 8)) +
1554 ((long) (xc_cache[j].blue >> 8) -
1555 (long) (xentry.blue >> 8)) *
1556 ((long) (xc_cache[j].blue >> 8) -
1557 (long) (xentry.blue >> 8));
1558 }
1559 if (nDist < nMinDist)
1560 {
1561 nMinDist = nDist;
1562 xentry.pixel = j;
1563 }
1564 }
1565 }
1566 colour = xentry.pixel;
1567
1568 /* update our cache */
1569 if (xentry.pixel < 256)
1570 {
1571 xc_cache[xentry.pixel].red = xentry.red;
1572 xc_cache[xentry.pixel].green = xentry.green;
1573 xc_cache[xentry.pixel].blue = xentry.blue;
1574
1575 }
1576
1577 map[i] = colour;
1578 }
1579 return map;
1580 }
1581 else
1582 {
1583 XColor *xcolours, *xentry;
1584 Colormap map;
1585
1586 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1587 for (i = 0; i < ncolours; i++)
1588 {
1589 entry = &colours->colours[i];
1590 xentry = &xcolours[i];
1591 xentry->pixel = i;
1592 MAKE_XCOLOR(xentry, entry);
1593 }
1594
1595 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1596 XStoreColors(g_display, map, xcolours, ncolours);
1597
1598 xfree(xcolours);
1599 return (HCOLOURMAP) map;
1600 }
1601 }
1602
1603 void
1604 ui_destroy_colourmap(HCOLOURMAP map)
1605 {
1606 if (!g_owncolmap)
1607 xfree(map);
1608 else
1609 XFreeColormap(g_display, (Colormap) map);
1610 }
1611
1612 void
1613 ui_set_colourmap(HCOLOURMAP map)
1614 {
1615 if (!g_owncolmap)
1616 {
1617 if (g_colmap)
1618 xfree(g_colmap);
1619
1620 g_colmap = (uint32 *) map;
1621 }
1622 else
1623 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1624 }
1625
1626 void
1627 ui_set_clip(int x, int y, int cx, int cy)
1628 {
1629 XRectangle rect;
1630
1631 rect.x = x;
1632 rect.y = y;
1633 rect.width = cx;
1634 rect.height = cy;
1635 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1636 }
1637
1638 void
1639 ui_reset_clip(void)
1640 {
1641 XRectangle rect;
1642
1643 rect.x = 0;
1644 rect.y = 0;
1645 rect.width = g_width;
1646 rect.height = g_height;
1647 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1648 }
1649
1650 void
1651 ui_bell(void)
1652 {
1653 XBell(g_display, 0);
1654 }
1655
1656 void
1657 ui_destblt(uint8 opcode,
1658 /* dest */ int x, int y, int cx, int cy)
1659 {
1660 SET_FUNCTION(opcode);
1661 FILL_RECTANGLE(x, y, cx, cy);
1662 RESET_FUNCTION(opcode);
1663 }
1664
1665 static uint8 hatch_patterns[] = {
1666 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1667 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1668 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1669 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1670 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1671 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1672 };
1673
1674 void
1675 ui_patblt(uint8 opcode,
1676 /* dest */ int x, int y, int cx, int cy,
1677 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1678 {
1679 Pixmap fill;
1680 uint8 i, ipattern[8];
1681
1682 SET_FUNCTION(opcode);
1683
1684 switch (brush->style)
1685 {
1686 case 0: /* Solid */
1687 SET_FOREGROUND(fgcolour);
1688 FILL_RECTANGLE(x, y, cx, cy);
1689 break;
1690
1691 case 2: /* Hatch */
1692 fill = (Pixmap) ui_create_glyph(8, 8,
1693 hatch_patterns + brush->pattern[0] * 8);
1694 SET_FOREGROUND(fgcolour);
1695 SET_BACKGROUND(bgcolour);
1696 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1697 XSetStipple(g_display, g_gc, fill);
1698 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1699 FILL_RECTANGLE(x, y, cx, cy);
1700 XSetFillStyle(g_display, g_gc, FillSolid);
1701 XSetTSOrigin(g_display, g_gc, 0, 0);
1702 ui_destroy_glyph((HGLYPH) fill);
1703 break;
1704
1705 case 3: /* Pattern */
1706 for (i = 0; i != 8; i++)
1707 ipattern[7 - i] = brush->pattern[i];
1708 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1709
1710 SET_FOREGROUND(bgcolour);
1711 SET_BACKGROUND(fgcolour);
1712 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1713 XSetStipple(g_display, g_gc, fill);
1714 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1715
1716 FILL_RECTANGLE(x, y, cx, cy);
1717
1718 XSetFillStyle(g_display, g_gc, FillSolid);
1719 XSetTSOrigin(g_display, g_gc, 0, 0);
1720 ui_destroy_glyph((HGLYPH) fill);
1721 break;
1722
1723 default:
1724 unimpl("brush %d\n", brush->style);
1725 }
1726
1727 RESET_FUNCTION(opcode);
1728 }
1729
1730 void
1731 ui_screenblt(uint8 opcode,
1732 /* dest */ int x, int y, int cx, int cy,
1733 /* src */ int srcx, int srcy)
1734 {
1735 SET_FUNCTION(opcode);
1736 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1737 if (g_ownbackstore)
1738 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1739 RESET_FUNCTION(opcode);
1740 }
1741
1742 void
1743 ui_memblt(uint8 opcode,
1744 /* dest */ int x, int y, int cx, int cy,
1745 /* src */ HBITMAP src, int srcx, int srcy)
1746 {
1747 SET_FUNCTION(opcode);
1748 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1749 if (g_ownbackstore)
1750 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1751 RESET_FUNCTION(opcode);
1752 }
1753
1754 void
1755 ui_triblt(uint8 opcode,
1756 /* dest */ int x, int y, int cx, int cy,
1757 /* src */ HBITMAP src, int srcx, int srcy,
1758 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1759 {
1760 /* This is potentially difficult to do in general. Until someone
1761 comes up with a more efficient way of doing it I am using cases. */
1762
1763 switch (opcode)
1764 {
1765 case 0x69: /* PDSxxn */
1766 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1767 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1768 break;
1769
1770 case 0xb8: /* PSDPxax */
1771 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1772 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1773 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1774 break;
1775
1776 case 0xc0: /* PSa */
1777 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1778 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1779 break;
1780
1781 default:
1782 unimpl("triblt 0x%x\n", opcode);
1783 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1784 }
1785 }
1786
1787 void
1788 ui_line(uint8 opcode,
1789 /* dest */ int startx, int starty, int endx, int endy,
1790 /* pen */ PEN * pen)
1791 {
1792 SET_FUNCTION(opcode);
1793 SET_FOREGROUND(pen->colour);
1794 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1795 if (g_ownbackstore)
1796 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1797 RESET_FUNCTION(opcode);
1798 }
1799
1800 void
1801 ui_rect(
1802 /* dest */ int x, int y, int cx, int cy,
1803 /* brush */ int colour)
1804 {
1805 SET_FOREGROUND(colour);
1806 FILL_RECTANGLE(x, y, cx, cy);
1807 }
1808
1809 /* warning, this function only draws on wnd or backstore, not both */
1810 void
1811 ui_draw_glyph(int mixmode,
1812 /* dest */ int x, int y, int cx, int cy,
1813 /* src */ HGLYPH glyph, int srcx, int srcy,
1814 int bgcolour, int fgcolour)
1815 {
1816 SET_FOREGROUND(fgcolour);
1817 SET_BACKGROUND(bgcolour);
1818
1819 XSetFillStyle(g_display, g_gc,
1820 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1821 XSetStipple(g_display, g_gc, (Pixmap) glyph);
1822 XSetTSOrigin(g_display, g_gc, x, y);
1823
1824 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1825
1826 XSetFillStyle(g_display, g_gc, FillSolid);
1827 }
1828
1829 #define DO_GLYPH(ttext,idx) \
1830 {\
1831 glyph = cache_get_font (font, ttext[idx]);\
1832 if (!(flags & TEXT2_IMPLICIT_X))\
1833 {\
1834 xyoffset = ttext[++idx];\
1835 if ((xyoffset & 0x80))\
1836 {\
1837 if (flags & TEXT2_VERTICAL) \
1838 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1839 else\
1840 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1841 idx += 2;\
1842 }\
1843 else\
1844 {\
1845 if (flags & TEXT2_VERTICAL) \
1846 y += xyoffset;\
1847 else\
1848 x += xyoffset;\
1849 }\
1850 }\
1851 if (glyph != NULL)\
1852 {\
1853 ui_draw_glyph (mixmode, x + glyph->offset,\
1854 y + glyph->baseline,\
1855 glyph->width, glyph->height,\
1856 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1857 if (flags & TEXT2_IMPLICIT_X)\
1858 x += glyph->width;\
1859 }\
1860 }
1861
1862 void
1863 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1864 int clipx, int clipy, int clipcx, int clipcy,
1865 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1866 int fgcolour, uint8 * text, uint8 length)
1867 {
1868 FONTGLYPH *glyph;
1869 int i, j, xyoffset;
1870 DATABLOB *entry;
1871
1872 SET_FOREGROUND(bgcolour);
1873
1874 if (boxcx > 1)
1875 {
1876 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1877 }
1878 else if (mixmode == MIX_OPAQUE)
1879 {
1880 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1881 }
1882
1883 /* Paint text, character by character */
1884 for (i = 0; i < length;)
1885 {
1886 switch (text[i])
1887 {
1888 case 0xff:
1889 if (i + 2 < length)
1890 cache_put_text(text[i + 1], text, text[i + 2]);
1891 else
1892 {
1893 error("this shouldn't be happening\n");
1894 exit(1);
1895 }
1896 /* this will move pointer from start to first character after FF command */
1897 length -= i + 3;
1898 text = &(text[i + 3]);
1899 i = 0;
1900 break;
1901
1902 case 0xfe:
1903 entry = cache_get_text(text[i + 1]);
1904 if (entry != NULL)
1905 {
1906 if ((((uint8 *) (entry->data))[1] ==
1907 0) && (!(flags & TEXT2_IMPLICIT_X)))
1908 {
1909 if (flags & TEXT2_VERTICAL)
1910 y += text[i + 2];
1911 else
1912 x += text[i + 2];
1913 }
1914 for (j = 0; j < entry->size; j++)
1915 DO_GLYPH(((uint8 *) (entry->data)), j);
1916 }
1917 if (i + 2 < length)
1918 i += 3;
1919 else
1920 i += 2;
1921 length -= i;
1922 /* this will move pointer from start to first character after FE command */
1923 text = &(text[i]);
1924 i = 0;
1925 break;
1926
1927 default:
1928 DO_GLYPH(text, i);
1929 i++;
1930 break;
1931 }
1932 }
1933 if (g_ownbackstore)
1934 {
1935 if (boxcx > 1)
1936 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1937 boxy, boxcx, boxcy, boxx, boxy);
1938 else
1939 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1940 clipy, clipcx, clipcy, clipx, clipy);
1941 }
1942 }
1943
1944 void
1945 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1946 {
1947 Pixmap pix;
1948 XImage *image;
1949
1950 if (g_ownbackstore)
1951 {
1952 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1953 }
1954 else
1955 {
1956 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1957 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1958 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1959 XFreePixmap(g_display, pix);
1960 }
1961
1962 offset *= g_bpp / 8;
1963 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
1964
1965 XDestroyImage(image);
1966 }
1967
1968 void
1969 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1970 {
1971 XImage *image;
1972 uint8 *data;
1973
1974 offset *= g_bpp / 8;
1975 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
1976 if (data == NULL)
1977 return;
1978
1979 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1980 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
1981
1982 if (g_ownbackstore)
1983 {
1984 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1985 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1986 }
1987 else
1988 {
1989 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1990 }
1991
1992 XFree(image);
1993 }

  ViewVC Help
Powered by ViewVC 1.1.26