/[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 580 - (show annotations)
Fri Jan 23 08:35:52 2004 UTC (20 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 44450 byte(s)
Ran indent-all.sh

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

  ViewVC Help
Powered by ViewVC 1.1.26