/[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 534 - (show annotations)
Thu Oct 30 00:10:32 2003 UTC (20 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 43530 byte(s)
translate24to{24,32} were not using make/split-colour which makes
them unuseable on BE RGB-Displays of this depth...
This should fix it.

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

  ViewVC Help
Powered by ViewVC 1.1.26