/[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 501 - (show annotations)
Fri Oct 17 08:23:47 2003 UTC (20 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 42082 byte(s)
added switch (-A) to disable rdpsnd

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

  ViewVC Help
Powered by ViewVC 1.1.26