/[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 536 - (show annotations)
Fri Oct 31 04:29:57 2003 UTC (20 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 43556 byte(s)
Fix compile warnings on HP-UX.

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

  ViewVC Help
Powered by ViewVC 1.1.26