/[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 645 - (show annotations)
Mon Mar 29 13:59:03 2004 UTC (20 years, 1 month ago) by jsorg71
File MIME type: text/plain
File size: 46004 byte(s)
return data only if 15 or 16 bbp in translate_image

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

  ViewVC Help
Powered by ViewVC 1.1.26