/[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 519 - (show annotations)
Tue Oct 28 03:40:26 2003 UTC (20 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 42468 byte(s)
Convert bpp printf into DEBUG_RDP5 (perhaps not the ideal category but
it will do for now).

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

  ViewVC Help
Powered by ViewVC 1.1.26