/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 565 - (show annotations)
Mon Jan 19 21:58:58 2004 UTC (20 years, 4 months ago) by stargo
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 44403 byte(s)
Try to use a TrueColor visual, even if the default-visual is
PseudoColor. This enables high-colour modes on displays with
a PseudoColor default visual and eliminates colourmap-flashing
at 8 bpp there.

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

  ViewVC Help
Powered by ViewVC 1.1.26