/[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 545 - (show annotations)
Mon Nov 3 20:19:01 2003 UTC (20 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 43297 byte(s)
compile when not all baudrates are defined on a system

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

  ViewVC Help
Powered by ViewVC 1.1.26