/[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 609 - (show annotations)
Mon Feb 16 20:28:09 2004 UTC (20 years, 3 months ago) by stargo
File MIME type: text/plain
File size: 45120 byte(s)
Make internal backing-store the default && small fix for it

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

  ViewVC Help
Powered by ViewVC 1.1.26