/[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 709 - (show annotations)
Fri Jun 11 22:37:05 2004 UTC (19 years, 11 months ago) by jsorg71
File MIME type: text/plain
File size: 48250 byte(s)
clean up and comment the repeat macros

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

  ViewVC Help
Powered by ViewVC 1.1.26