/[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 500 - (show annotations)
Wed Oct 15 14:32:43 2003 UTC (20 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 42036 byte(s)
Support for specifying geometry in terms of percent of whole screen

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

  ViewVC Help
Powered by ViewVC 1.1.26