/[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 619 - (show annotations)
Wed Mar 3 10:41:53 2004 UTC (20 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 44920 byte(s)
Indent fixes

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

  ViewVC Help
Powered by ViewVC 1.1.26