/[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 606 - (show annotations)
Sat Feb 14 23:20:24 2004 UTC (20 years, 3 months ago) by stargo
File MIME type: text/plain
File size: 44861 byte(s)
fix select errors due to exploding fdnum n

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

  ViewVC Help
Powered by ViewVC 1.1.26