/[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 528 - (show annotations)
Wed Oct 29 08:37:20 2003 UTC (20 years, 6 months ago) by matthewc
File MIME type: text/plain
File size: 43055 byte(s)
Fix translate16to16 along the lines of all the other translate functions.

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

  ViewVC Help
Powered by ViewVC 1.1.26