/[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 706 - (show annotations)
Tue Jun 1 08:06:02 2004 UTC (19 years, 11 months ago) by astrand
File MIME type: text/plain
File size: 47373 byte(s)
Indent fixes

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

  ViewVC Help
Powered by ViewVC 1.1.26