/[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 487 - (show annotations)
Mon Oct 13 12:34:15 2003 UTC (20 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 41882 byte(s)
Corrected SET_FOREGROUND/SET_BACKGROUND in Hatch handling routine.
This should be done according to patch 688390, and feels right,
although I basically have no idea of what I'm doing :-)

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 if (g_enable_compose)
767 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
768
769 xkeymap_init();
770 xclip_init();
771
772 /* todo take this out when high colour is done */
773 printf("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth);
774
775 return True;
776 }
777
778 void
779 ui_deinit(void)
780 {
781 if (g_IM != NULL)
782 XCloseIM(g_IM);
783
784 XFreeModifiermap(g_mod_map);
785
786 if (g_ownbackstore)
787 XFreePixmap(g_display, g_backstore);
788
789 XFreeGC(g_display, g_gc);
790 XCloseDisplay(g_display);
791 g_display = NULL;
792 }
793
794 BOOL
795 ui_create_window(void)
796 {
797 XSetWindowAttributes attribs;
798 XClassHint *classhints;
799 XSizeHints *sizehints;
800 int wndwidth, wndheight;
801 long input_mask, ic_input_mask;
802 XEvent xevent;
803
804 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
805 wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
806
807 attribs.background_pixel = BlackPixelOfScreen(g_screen);
808 attribs.backing_store = g_ownbackstore ? NotUseful : Always;
809 attribs.override_redirect = g_fullscreen;
810
811 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,
812 0, CopyFromParent, InputOutput, CopyFromParent,
813 CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);
814
815 XStoreName(g_display, g_wnd, g_title);
816
817 if (g_hide_decorations)
818 mwm_hide_decorations();
819
820 classhints = XAllocClassHint();
821 if (classhints != NULL)
822 {
823 classhints->res_name = classhints->res_class = "rdesktop";
824 XSetClassHint(g_display, g_wnd, classhints);
825 XFree(classhints);
826 }
827
828 sizehints = XAllocSizeHints();
829 if (sizehints)
830 {
831 sizehints->flags = PMinSize | PMaxSize;
832 sizehints->min_width = sizehints->max_width = g_width;
833 sizehints->min_height = sizehints->max_height = g_height;
834 XSetWMNormalHints(g_display, g_wnd, sizehints);
835 XFree(sizehints);
836 }
837
838 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
839 VisibilityChangeMask | FocusChangeMask;
840
841 if (g_sendmotion)
842 input_mask |= PointerMotionMask;
843 if (g_ownbackstore)
844 input_mask |= ExposureMask;
845 if (g_fullscreen || g_grab_keyboard)
846 input_mask |= EnterWindowMask;
847 if (g_grab_keyboard)
848 input_mask |= LeaveWindowMask;
849
850 if (g_IM != NULL)
851 {
852 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
853 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
854
855 if ((g_IC != NULL)
856 && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
857 input_mask |= ic_input_mask;
858 }
859
860 XSelectInput(g_display, g_wnd, input_mask);
861 XMapWindow(g_display, g_wnd);
862
863 /* wait for VisibilityNotify */
864 do
865 {
866 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
867 }
868 while (xevent.type != VisibilityNotify);
869
870 g_focused = False;
871 g_mouse_in_wnd = False;
872
873 /* handle the WM_DELETE_WINDOW protocol */
874 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
875 g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
876 XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
877
878 return True;
879 }
880
881 void
882 ui_destroy_window(void)
883 {
884 if (g_IC != NULL)
885 XDestroyIC(g_IC);
886
887 XDestroyWindow(g_display, g_wnd);
888 }
889
890 void
891 xwin_toggle_fullscreen(void)
892 {
893 Pixmap contents = 0;
894
895 if (!g_ownbackstore)
896 {
897 /* need to save contents of window */
898 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
899 XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
900 }
901
902 ui_destroy_window();
903 g_fullscreen = !g_fullscreen;
904 ui_create_window();
905
906 XDefineCursor(g_display, g_wnd, g_current_cursor);
907
908 if (!g_ownbackstore)
909 {
910 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
911 XFreePixmap(g_display, contents);
912 }
913 }
914
915 /* Process all events in Xlib queue
916 Returns 0 after user quit, 1 otherwise */
917 static int
918 xwin_process_events(void)
919 {
920 XEvent xevent;
921 KeySym keysym;
922 uint16 button, flags;
923 uint32 ev_time;
924 key_translation tr;
925 char str[256];
926 Status status;
927 unsigned int state;
928 Window wdummy;
929 int dummy;
930
931 while (XPending(g_display) > 0)
932 {
933 XNextEvent(g_display, &xevent);
934
935 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
936 {
937 DEBUG_KBD(("Filtering event\n"));
938 continue;
939 }
940
941 flags = 0;
942
943 switch (xevent.type)
944 {
945 case ClientMessage:
946 /* the window manager told us to quit */
947 if ((xevent.xclient.message_type == g_protocol_atom)
948 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
949 /* Quit */
950 return 0;
951 break;
952
953 case KeyPress:
954 g_last_gesturetime = xevent.xkey.time;
955 if (g_IC != NULL)
956 /* Multi_key compatible version */
957 {
958 XmbLookupString(g_IC,
959 &xevent.xkey, str, sizeof(str), &keysym,
960 &status);
961 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
962 {
963 error("XmbLookupString failed with status 0x%x\n",
964 status);
965 break;
966 }
967 }
968 else
969 {
970 /* Plain old XLookupString */
971 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
972 XLookupString((XKeyEvent *) & xevent,
973 str, sizeof(str), &keysym, NULL);
974 }
975
976 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
977 get_ksname(keysym)));
978
979 ev_time = time(NULL);
980 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
981 break;
982
983 tr = xkeymap_translate_key(keysym,
984 xevent.xkey.keycode, xevent.xkey.state);
985
986 if (tr.scancode == 0)
987 break;
988
989 save_remote_modifiers(tr.scancode);
990 ensure_remote_modifiers(ev_time, tr);
991 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
992 restore_remote_modifiers(ev_time, tr.scancode);
993
994 break;
995
996 case KeyRelease:
997 g_last_gesturetime = xevent.xkey.time;
998 XLookupString((XKeyEvent *) & xevent, str,
999 sizeof(str), &keysym, NULL);
1000
1001 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1002 get_ksname(keysym)));
1003
1004 ev_time = time(NULL);
1005 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1006 break;
1007
1008 tr = xkeymap_translate_key(keysym,
1009 xevent.xkey.keycode, xevent.xkey.state);
1010
1011 if (tr.scancode == 0)
1012 break;
1013
1014 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1015 break;
1016
1017 case ButtonPress:
1018 flags = MOUSE_FLAG_DOWN;
1019 /* fall through */
1020
1021 case ButtonRelease:
1022 g_last_gesturetime = xevent.xbutton.time;
1023 button = xkeymap_translate_button(xevent.xbutton.button);
1024 if (button == 0)
1025 break;
1026
1027 /* If win_button_size is nonzero, enable single app mode */
1028 if (xevent.xbutton.y < g_win_button_size)
1029 {
1030 /* Stop moving window when button is released, regardless of cursor position */
1031 if (g_moving_wnd && (xevent.type == ButtonRelease))
1032 g_moving_wnd = False;
1033
1034 /* Check from right to left: */
1035
1036 if (xevent.xbutton.x >= g_width - g_win_button_size)
1037 {
1038 /* The close button, continue */
1039 ;
1040 }
1041 else if (xevent.xbutton.x >=
1042 g_width - g_win_button_size * 2)
1043 {
1044 /* The maximize/restore button. Do not send to
1045 server. It might be a good idea to change the
1046 cursor or give some other visible indication
1047 that rdesktop inhibited this click */
1048 break;
1049 }
1050 else if (xevent.xbutton.x >=
1051 g_width - g_win_button_size * 3)
1052 {
1053 /* The minimize button. Iconify window. */
1054 XIconifyWindow(g_display, g_wnd,
1055 DefaultScreen(g_display));
1056 break;
1057 }
1058 else if (xevent.xbutton.x <= g_win_button_size)
1059 {
1060 /* The system menu. Ignore. */
1061 break;
1062 }
1063 else
1064 {
1065 /* The title bar. */
1066 if ((xevent.type == ButtonPress) && !g_fullscreen
1067 && g_hide_decorations)
1068 {
1069 g_moving_wnd = True;
1070 g_move_x_offset = xevent.xbutton.x;
1071 g_move_y_offset = xevent.xbutton.y;
1072 }
1073 break;
1074
1075 }
1076 }
1077
1078 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1079 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1080 break;
1081
1082 case MotionNotify:
1083 if (g_moving_wnd)
1084 {
1085 XMoveWindow(g_display, g_wnd,
1086 xevent.xmotion.x_root - g_move_x_offset,
1087 xevent.xmotion.y_root - g_move_y_offset);
1088 break;
1089 }
1090
1091 if (g_fullscreen && !g_focused)
1092 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1093 CurrentTime);
1094 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1095 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1096 break;
1097
1098 case FocusIn:
1099 if (xevent.xfocus.mode == NotifyGrab)
1100 break;
1101 g_focused = True;
1102 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
1103 &dummy, &dummy, &state);
1104 reset_modifier_keys(state);
1105 if (g_grab_keyboard && g_mouse_in_wnd)
1106 XGrabKeyboard(g_display, g_wnd, True,
1107 GrabModeAsync, GrabModeAsync, CurrentTime);
1108 break;
1109
1110 case FocusOut:
1111 if (xevent.xfocus.mode == NotifyUngrab)
1112 break;
1113 g_focused = False;
1114 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1115 XUngrabKeyboard(g_display, CurrentTime);
1116 break;
1117
1118 case EnterNotify:
1119 /* we only register for this event when in fullscreen mode */
1120 /* or grab_keyboard */
1121 g_mouse_in_wnd = True;
1122 if (g_fullscreen)
1123 {
1124 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1125 CurrentTime);
1126 break;
1127 }
1128 if (g_focused)
1129 XGrabKeyboard(g_display, g_wnd, True,
1130 GrabModeAsync, GrabModeAsync, CurrentTime);
1131 break;
1132
1133 case LeaveNotify:
1134 /* we only register for this event when grab_keyboard */
1135 g_mouse_in_wnd = False;
1136 XUngrabKeyboard(g_display, CurrentTime);
1137 break;
1138
1139 case Expose:
1140 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1141 xevent.xexpose.x, xevent.xexpose.y,
1142 xevent.xexpose.width,
1143 xevent.xexpose.height,
1144 xevent.xexpose.x, xevent.xexpose.y);
1145 break;
1146
1147 case MappingNotify:
1148 /* Refresh keyboard mapping if it has changed. This is important for
1149 Xvnc, since it allocates keycodes dynamically */
1150 if (xevent.xmapping.request == MappingKeyboard
1151 || xevent.xmapping.request == MappingModifier)
1152 XRefreshKeyboardMapping(&xevent.xmapping);
1153
1154 if (xevent.xmapping.request == MappingModifier)
1155 {
1156 XFreeModifiermap(g_mod_map);
1157 g_mod_map = XGetModifierMapping(g_display);
1158 }
1159 break;
1160
1161 /* clipboard stuff */
1162 case SelectionNotify:
1163 xclip_handle_SelectionNotify(&xevent.xselection);
1164 break;
1165 case SelectionRequest:
1166 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1167 break;
1168 case SelectionClear:
1169 xclip_handle_SelectionClear();
1170 break;
1171 case PropertyNotify:
1172 xclip_handle_PropertyNotify(&xevent.xproperty);
1173 break;
1174 }
1175 }
1176 /* Keep going */
1177 return 1;
1178 }
1179
1180 /* Returns 0 after user quit, 1 otherwise */
1181 int
1182 ui_select(int rdp_socket)
1183 {
1184 int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1185 fd_set rfds, wfds;
1186
1187 while (True)
1188 {
1189 /* Process any events already waiting */
1190 if (!xwin_process_events())
1191 /* User quit */
1192 return 0;
1193
1194 FD_ZERO(&rfds);
1195 FD_ZERO(&wfds);
1196 FD_SET(rdp_socket, &rfds);
1197 FD_SET(g_x_socket, &rfds);
1198
1199 #ifdef WITH_RDPSND
1200 /* FIXME: there should be an API for registering fds */
1201 if (g_dsp_busy)
1202 {
1203 FD_SET(g_dsp_fd, &wfds);
1204 n = (g_dsp_fd + 1 > n) ? g_dsp_fd + 1 : n;
1205 }
1206 #endif
1207
1208 switch (select(n, &rfds, &wfds, NULL, NULL))
1209 {
1210 case -1:
1211 error("select: %s\n", strerror(errno));
1212
1213 case 0:
1214 continue;
1215 }
1216
1217 if (FD_ISSET(rdp_socket, &rfds))
1218 return 1;
1219
1220 #ifdef WITH_RDPSND
1221 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1222 wave_out_play();
1223 #endif
1224 }
1225 }
1226
1227 void
1228 ui_move_pointer(int x, int y)
1229 {
1230 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1231 }
1232
1233 HBITMAP
1234 ui_create_bitmap(int width, int height, uint8 * data)
1235 {
1236 XImage *image;
1237 Pixmap bitmap;
1238 uint8 *tdata;
1239
1240 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1241 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1242 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1243 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1244
1245 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1246
1247 XFree(image);
1248 if (!g_owncolmap)
1249 xfree(tdata);
1250 return (HBITMAP) bitmap;
1251 }
1252
1253 void
1254 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1255 {
1256 XImage *image;
1257 uint8 *tdata;
1258 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1259 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1260 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1261
1262 if (g_ownbackstore)
1263 {
1264 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1265 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1266 }
1267 else
1268 {
1269 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1270 }
1271
1272 XFree(image);
1273 if (!g_owncolmap)
1274 xfree(tdata);
1275 }
1276
1277 void
1278 ui_destroy_bitmap(HBITMAP bmp)
1279 {
1280 XFreePixmap(g_display, (Pixmap) bmp);
1281 }
1282
1283 HGLYPH
1284 ui_create_glyph(int width, int height, uint8 * data)
1285 {
1286 XImage *image;
1287 Pixmap bitmap;
1288 int scanline;
1289 GC gc;
1290
1291 scanline = (width + 7) / 8;
1292
1293 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1294 gc = XCreateGC(g_display, bitmap, 0, NULL);
1295
1296 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1297 width, height, 8, scanline);
1298 image->byte_order = MSBFirst;
1299 image->bitmap_bit_order = MSBFirst;
1300 XInitImage(image);
1301
1302 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1303
1304 XFree(image);
1305 XFreeGC(g_display, gc);
1306 return (HGLYPH) bitmap;
1307 }
1308
1309 void
1310 ui_destroy_glyph(HGLYPH glyph)
1311 {
1312 XFreePixmap(g_display, (Pixmap) glyph);
1313 }
1314
1315 HCURSOR
1316 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1317 uint8 * andmask, uint8 * xormask)
1318 {
1319 HGLYPH maskglyph, cursorglyph;
1320 XColor bg, fg;
1321 Cursor xcursor;
1322 uint8 *cursor, *pcursor;
1323 uint8 *mask, *pmask;
1324 uint8 nextbit;
1325 int scanline, offset;
1326 int i, j;
1327
1328 scanline = (width + 7) / 8;
1329 offset = scanline * height;
1330
1331 cursor = (uint8 *) xmalloc(offset);
1332 memset(cursor, 0, offset);
1333
1334 mask = (uint8 *) xmalloc(offset);
1335 memset(mask, 0, offset);
1336
1337 /* approximate AND and XOR masks with a monochrome X pointer */
1338 for (i = 0; i < height; i++)
1339 {
1340 offset -= scanline;
1341 pcursor = &cursor[offset];
1342 pmask = &mask[offset];
1343
1344 for (j = 0; j < scanline; j++)
1345 {
1346 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1347 {
1348 if (xormask[0] || xormask[1] || xormask[2])
1349 {
1350 *pcursor |= (~(*andmask) & nextbit);
1351 *pmask |= nextbit;
1352 }
1353 else
1354 {
1355 *pcursor |= ((*andmask) & nextbit);
1356 *pmask |= (~(*andmask) & nextbit);
1357 }
1358
1359 xormask += 3;
1360 }
1361
1362 andmask++;
1363 pcursor++;
1364 pmask++;
1365 }
1366 }
1367
1368 fg.red = fg.blue = fg.green = 0xffff;
1369 bg.red = bg.blue = bg.green = 0x0000;
1370 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1371
1372 cursorglyph = ui_create_glyph(width, height, cursor);
1373 maskglyph = ui_create_glyph(width, height, mask);
1374
1375 xcursor =
1376 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1377 (Pixmap) maskglyph, &fg, &bg, x, y);
1378
1379 ui_destroy_glyph(maskglyph);
1380 ui_destroy_glyph(cursorglyph);
1381 xfree(mask);
1382 xfree(cursor);
1383 return (HCURSOR) xcursor;
1384 }
1385
1386 void
1387 ui_set_cursor(HCURSOR cursor)
1388 {
1389 g_current_cursor = (Cursor) cursor;
1390 XDefineCursor(g_display, g_wnd, g_current_cursor);
1391 }
1392
1393 void
1394 ui_destroy_cursor(HCURSOR cursor)
1395 {
1396 XFreeCursor(g_display, (Cursor) cursor);
1397 }
1398
1399 #define MAKE_XCOLOR(xc,c) \
1400 (xc)->red = ((c)->red << 8) | (c)->red; \
1401 (xc)->green = ((c)->green << 8) | (c)->green; \
1402 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1403 (xc)->flags = DoRed | DoGreen | DoBlue;
1404
1405
1406 HCOLOURMAP
1407 ui_create_colourmap(COLOURMAP * colours)
1408 {
1409 COLOURENTRY *entry;
1410 int i, ncolours = colours->ncolours;
1411 if (!g_owncolmap)
1412 {
1413 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1414 XColor xentry;
1415 XColor xc_cache[256];
1416 uint32 colour;
1417 int colLookup = 256;
1418 for (i = 0; i < ncolours; i++)
1419 {
1420 entry = &colours->colours[i];
1421 MAKE_XCOLOR(&xentry, entry);
1422
1423 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1424 {
1425 /* Allocation failed, find closest match. */
1426 int j = 256;
1427 int nMinDist = 3 * 256 * 256;
1428 long nDist = nMinDist;
1429
1430 /* only get the colors once */
1431 while (colLookup--)
1432 {
1433 xc_cache[colLookup].pixel = colLookup;
1434 xc_cache[colLookup].red = xc_cache[colLookup].green =
1435 xc_cache[colLookup].blue = 0;
1436 xc_cache[colLookup].flags = 0;
1437 XQueryColor(g_display,
1438 DefaultColormap(g_display,
1439 DefaultScreen(g_display)),
1440 &xc_cache[colLookup]);
1441 }
1442 colLookup = 0;
1443
1444 /* approximate the pixel */
1445 while (j--)
1446 {
1447 if (xc_cache[j].flags)
1448 {
1449 nDist = ((long) (xc_cache[j].red >> 8) -
1450 (long) (xentry.red >> 8)) *
1451 ((long) (xc_cache[j].red >> 8) -
1452 (long) (xentry.red >> 8)) +
1453 ((long) (xc_cache[j].green >> 8) -
1454 (long) (xentry.green >> 8)) *
1455 ((long) (xc_cache[j].green >> 8) -
1456 (long) (xentry.green >> 8)) +
1457 ((long) (xc_cache[j].blue >> 8) -
1458 (long) (xentry.blue >> 8)) *
1459 ((long) (xc_cache[j].blue >> 8) -
1460 (long) (xentry.blue >> 8));
1461 }
1462 if (nDist < nMinDist)
1463 {
1464 nMinDist = nDist;
1465 xentry.pixel = j;
1466 }
1467 }
1468 }
1469 colour = xentry.pixel;
1470
1471 /* update our cache */
1472 if (xentry.pixel < 256)
1473 {
1474 xc_cache[xentry.pixel].red = xentry.red;
1475 xc_cache[xentry.pixel].green = xentry.green;
1476 xc_cache[xentry.pixel].blue = xentry.blue;
1477
1478 }
1479
1480
1481 /* byte swap here to make translate_image faster */
1482 map[i] = translate_colour(colour);
1483 }
1484 return map;
1485 }
1486 else
1487 {
1488 XColor *xcolours, *xentry;
1489 Colormap map;
1490
1491 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1492 for (i = 0; i < ncolours; i++)
1493 {
1494 entry = &colours->colours[i];
1495 xentry = &xcolours[i];
1496 xentry->pixel = i;
1497 MAKE_XCOLOR(xentry, entry);
1498 }
1499
1500 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1501 XStoreColors(g_display, map, xcolours, ncolours);
1502
1503 xfree(xcolours);
1504 return (HCOLOURMAP) map;
1505 }
1506 }
1507
1508 void
1509 ui_destroy_colourmap(HCOLOURMAP map)
1510 {
1511 if (!g_owncolmap)
1512 xfree(map);
1513 else
1514 XFreeColormap(g_display, (Colormap) map);
1515 }
1516
1517 void
1518 ui_set_colourmap(HCOLOURMAP map)
1519 {
1520 if (!g_owncolmap)
1521 {
1522 if (g_colmap)
1523 xfree(g_colmap);
1524
1525 g_colmap = (uint32 *) map;
1526 }
1527 else
1528 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1529 }
1530
1531 void
1532 ui_set_clip(int x, int y, int cx, int cy)
1533 {
1534 XRectangle rect;
1535
1536 rect.x = x;
1537 rect.y = y;
1538 rect.width = cx;
1539 rect.height = cy;
1540 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1541 }
1542
1543 void
1544 ui_reset_clip(void)
1545 {
1546 XRectangle rect;
1547
1548 rect.x = 0;
1549 rect.y = 0;
1550 rect.width = g_width;
1551 rect.height = g_height;
1552 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1553 }
1554
1555 void
1556 ui_bell(void)
1557 {
1558 XBell(g_display, 0);
1559 }
1560
1561 void
1562 ui_destblt(uint8 opcode,
1563 /* dest */ int x, int y, int cx, int cy)
1564 {
1565 SET_FUNCTION(opcode);
1566 FILL_RECTANGLE(x, y, cx, cy);
1567 RESET_FUNCTION(opcode);
1568 }
1569
1570 static uint8 hatch_patterns[] = {
1571 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1572 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1573 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1574 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1575 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1576 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1577 };
1578
1579 void
1580 ui_patblt(uint8 opcode,
1581 /* dest */ int x, int y, int cx, int cy,
1582 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1583 {
1584 Pixmap fill;
1585 uint8 i, ipattern[8];
1586
1587 SET_FUNCTION(opcode);
1588
1589 switch (brush->style)
1590 {
1591 case 0: /* Solid */
1592 SET_FOREGROUND(fgcolour);
1593 FILL_RECTANGLE(x, y, cx, cy);
1594 break;
1595
1596 case 2: /* Hatch */
1597 fill = (Pixmap) ui_create_glyph(8, 8,
1598 hatch_patterns + brush->pattern[0] * 8);
1599 SET_FOREGROUND(fgcolour);
1600 SET_BACKGROUND(bgcolour);
1601 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1602 XSetStipple(g_display, g_gc, fill);
1603 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1604 FILL_RECTANGLE(x, y, cx, cy);
1605 XSetFillStyle(g_display, g_gc, FillSolid);
1606 XSetTSOrigin(g_display, g_gc, 0, 0);
1607 ui_destroy_glyph((HGLYPH) fill);
1608 break;
1609
1610 case 3: /* Pattern */
1611 for (i = 0; i != 8; i++)
1612 ipattern[7 - i] = brush->pattern[i];
1613 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1614
1615 SET_FOREGROUND(bgcolour);
1616 SET_BACKGROUND(fgcolour);
1617 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1618 XSetStipple(g_display, g_gc, fill);
1619 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1620
1621 FILL_RECTANGLE(x, y, cx, cy);
1622
1623 XSetFillStyle(g_display, g_gc, FillSolid);
1624 XSetTSOrigin(g_display, g_gc, 0, 0);
1625 ui_destroy_glyph((HGLYPH) fill);
1626 break;
1627
1628 default:
1629 unimpl("brush %d\n", brush->style);
1630 }
1631
1632 RESET_FUNCTION(opcode);
1633 }
1634
1635 void
1636 ui_screenblt(uint8 opcode,
1637 /* dest */ int x, int y, int cx, int cy,
1638 /* src */ int srcx, int srcy)
1639 {
1640 SET_FUNCTION(opcode);
1641 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1642 if (g_ownbackstore)
1643 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1644 RESET_FUNCTION(opcode);
1645 }
1646
1647 void
1648 ui_memblt(uint8 opcode,
1649 /* dest */ int x, int y, int cx, int cy,
1650 /* src */ HBITMAP src, int srcx, int srcy)
1651 {
1652 SET_FUNCTION(opcode);
1653 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1654 if (g_ownbackstore)
1655 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1656 RESET_FUNCTION(opcode);
1657 }
1658
1659 void
1660 ui_triblt(uint8 opcode,
1661 /* dest */ int x, int y, int cx, int cy,
1662 /* src */ HBITMAP src, int srcx, int srcy,
1663 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1664 {
1665 /* This is potentially difficult to do in general. Until someone
1666 comes up with a more efficient way of doing it I am using cases. */
1667
1668 switch (opcode)
1669 {
1670 case 0x69: /* PDSxxn */
1671 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1672 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1673 break;
1674
1675 case 0xb8: /* PSDPxax */
1676 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1677 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1678 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1679 break;
1680
1681 case 0xc0: /* PSa */
1682 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1683 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1684 break;
1685
1686 default:
1687 unimpl("triblt 0x%x\n", opcode);
1688 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1689 }
1690 }
1691
1692 void
1693 ui_line(uint8 opcode,
1694 /* dest */ int startx, int starty, int endx, int endy,
1695 /* pen */ PEN * pen)
1696 {
1697 SET_FUNCTION(opcode);
1698 SET_FOREGROUND(pen->colour);
1699 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1700 if (g_ownbackstore)
1701 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1702 RESET_FUNCTION(opcode);
1703 }
1704
1705 void
1706 ui_rect(
1707 /* dest */ int x, int y, int cx, int cy,
1708 /* brush */ int colour)
1709 {
1710 SET_FOREGROUND(colour);
1711 FILL_RECTANGLE(x, y, cx, cy);
1712 }
1713
1714 /* warning, this function only draws on wnd or backstore, not both */
1715 void
1716 ui_draw_glyph(int mixmode,
1717 /* dest */ int x, int y, int cx, int cy,
1718 /* src */ HGLYPH glyph, int srcx, int srcy,
1719 int bgcolour, int fgcolour)
1720 {
1721 SET_FOREGROUND(fgcolour);
1722 SET_BACKGROUND(bgcolour);
1723
1724 XSetFillStyle(g_display, g_gc,
1725 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1726 XSetStipple(g_display, g_gc, (Pixmap) glyph);
1727 XSetTSOrigin(g_display, g_gc, x, y);
1728
1729 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1730
1731 XSetFillStyle(g_display, g_gc, FillSolid);
1732 }
1733
1734 #define DO_GLYPH(ttext,idx) \
1735 {\
1736 glyph = cache_get_font (font, ttext[idx]);\
1737 if (!(flags & TEXT2_IMPLICIT_X))\
1738 {\
1739 xyoffset = ttext[++idx];\
1740 if ((xyoffset & 0x80))\
1741 {\
1742 if (flags & TEXT2_VERTICAL) \
1743 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1744 else\
1745 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1746 idx += 2;\
1747 }\
1748 else\
1749 {\
1750 if (flags & TEXT2_VERTICAL) \
1751 y += xyoffset;\
1752 else\
1753 x += xyoffset;\
1754 }\
1755 }\
1756 if (glyph != NULL)\
1757 {\
1758 ui_draw_glyph (mixmode, x + glyph->offset,\
1759 y + glyph->baseline,\
1760 glyph->width, glyph->height,\
1761 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1762 if (flags & TEXT2_IMPLICIT_X)\
1763 x += glyph->width;\
1764 }\
1765 }
1766
1767 void
1768 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1769 int clipx, int clipy, int clipcx, int clipcy,
1770 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1771 int fgcolour, uint8 * text, uint8 length)
1772 {
1773 FONTGLYPH *glyph;
1774 int i, j, xyoffset;
1775 DATABLOB *entry;
1776
1777 SET_FOREGROUND(bgcolour);
1778
1779 if (boxcx > 1)
1780 {
1781 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1782 }
1783 else if (mixmode == MIX_OPAQUE)
1784 {
1785 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1786 }
1787
1788 /* Paint text, character by character */
1789 for (i = 0; i < length;)
1790 {
1791 switch (text[i])
1792 {
1793 case 0xff:
1794 if (i + 2 < length)
1795 cache_put_text(text[i + 1], text, text[i + 2]);
1796 else
1797 {
1798 error("this shouldn't be happening\n");
1799 exit(1);
1800 }
1801 /* this will move pointer from start to first character after FF command */
1802 length -= i + 3;
1803 text = &(text[i + 3]);
1804 i = 0;
1805 break;
1806
1807 case 0xfe:
1808 entry = cache_get_text(text[i + 1]);
1809 if (entry != NULL)
1810 {
1811 if ((((uint8 *) (entry->data))[1] ==
1812 0) && (!(flags & TEXT2_IMPLICIT_X)))
1813 {
1814 if (flags & TEXT2_VERTICAL)
1815 y += text[i + 2];
1816 else
1817 x += text[i + 2];
1818 }
1819 for (j = 0; j < entry->size; j++)
1820 DO_GLYPH(((uint8 *) (entry->data)), j);
1821 }
1822 if (i + 2 < length)
1823 i += 3;
1824 else
1825 i += 2;
1826 length -= i;
1827 /* this will move pointer from start to first character after FE command */
1828 text = &(text[i]);
1829 i = 0;
1830 break;
1831
1832 default:
1833 DO_GLYPH(text, i);
1834 i++;
1835 break;
1836 }
1837 }
1838 if (g_ownbackstore)
1839 {
1840 if (boxcx > 1)
1841 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1842 boxy, boxcx, boxcy, boxx, boxy);
1843 else
1844 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1845 clipy, clipcx, clipcy, clipx, clipy);
1846 }
1847 }
1848
1849 void
1850 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1851 {
1852 Pixmap pix;
1853 XImage *image;
1854
1855 if (g_ownbackstore)
1856 {
1857 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1858 }
1859 else
1860 {
1861 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1862 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1863 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1864 XFreePixmap(g_display, pix);
1865 }
1866
1867 offset *= g_bpp / 8;
1868 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
1869
1870 XDestroyImage(image);
1871 }
1872
1873 void
1874 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1875 {
1876 XImage *image;
1877 uint8 *data;
1878
1879 offset *= g_bpp / 8;
1880 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
1881 if (data == NULL)
1882 return;
1883
1884 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1885 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
1886
1887 if (g_ownbackstore)
1888 {
1889 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1890 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1891 }
1892 else
1893 {
1894 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1895 }
1896
1897 XFree(image);
1898 }

  ViewVC Help
Powered by ViewVC 1.1.26