/[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 566 - (show annotations)
Mon Jan 19 23:45:26 2004 UTC (20 years, 4 months ago) by stargo
File MIME type: text/plain
File size: 44502 byte(s)
fix g_gc memleak

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

  ViewVC Help
Powered by ViewVC 1.1.26