/[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 800 - (show annotations)
Thu Nov 18 11:18:49 2004 UTC (19 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 48545 byte(s)
add support for specifying the window-position with the -g parameter

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

  ViewVC Help
Powered by ViewVC 1.1.26