/[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 499 - (show annotations)
Wed Oct 15 14:01:32 2003 UTC (20 years, 7 months ago) by astrand
File MIME type: text/plain
File size: 41848 byte(s)
Fixed indentation

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

  ViewVC Help
Powered by ViewVC 1.1.26