/[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 521 - (show annotations)
Tue Oct 28 09:02:46 2003 UTC (20 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 43278 byte(s)
endianess fixes for 8 bit
fix for crash when g_bpp==24

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

  ViewVC Help
Powered by ViewVC 1.1.26