/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26