/[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 603 - (show annotations)
Sat Feb 7 18:47:06 2004 UTC (20 years, 3 months ago) by stargo
File MIME type: text/plain
File size: 44856 byte(s)
fixes for HP-UX

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

  ViewVC Help
Powered by ViewVC 1.1.26