/[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 594 - (show annotations)
Tue Feb 3 13:55:12 2004 UTC (20 years, 3 months ago) by n-ki
File MIME type: text/plain
File size: 44841 byte(s)
tmp disable select timeout - we segfault

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

  ViewVC Help
Powered by ViewVC 1.1.26