/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 508 - (show annotations)
Wed Oct 22 10:55:11 2003 UTC (20 years, 6 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 42411 byte(s)
Applied null cursor patch from jeroen@oldambt7.com

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

  ViewVC Help
Powered by ViewVC 1.1.26