/[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 643 - (show annotations)
Wed Mar 24 18:16:58 2004 UTC (20 years, 1 month ago) by jsorg71
File MIME type: text/plain
File size: 45451 byte(s)
only check g_xserver_be once in translate8toXX

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

  ViewVC Help
Powered by ViewVC 1.1.26