/[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 498 - (show annotations)
Tue Oct 14 12:05:27 2003 UTC (20 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 41883 byte(s)
xkeymap_init must be before using g_enable_compose.

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

  ViewVC Help
Powered by ViewVC 1.1.26