/[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 517 - (show annotations)
Tue Oct 28 03:30:51 2003 UTC (20 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 42513 byte(s)
private colour map code only works for 8 bpp, disable otherwise
(from neoware)

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

  ViewVC Help
Powered by ViewVC 1.1.26