/[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 708 - (show annotations)
Fri Jun 4 15:01:36 2004 UTC (19 years, 11 months ago) by jsorg71
File MIME type: text/plain
File size: 47784 byte(s)
warnings when screen size of depth change and backstore resizeing when screen size changes

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 Pixmap bs;
1035
1036 sizehints = XAllocSizeHints();
1037 if (sizehints)
1038 {
1039 sizehints->flags = PMinSize | PMaxSize;
1040 sizehints->min_width = sizehints->max_width = g_width;
1041 sizehints->min_height = sizehints->max_height = g_height;
1042 XSetWMNormalHints(g_display, g_wnd, sizehints);
1043 XFree(sizehints);
1044 }
1045
1046 if (!(g_fullscreen || g_embed_wnd))
1047 {
1048 XResizeWindow(g_display, g_wnd, g_width, g_height);
1049 }
1050
1051 /* create new backstore pixmap */
1052 if (g_backstore != 0)
1053 {
1054 bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1055 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1056 XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1057 XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1058 XFreePixmap(g_display, g_backstore);
1059 g_backstore = bs;
1060 }
1061 }
1062
1063 void
1064 ui_destroy_window(void)
1065 {
1066 if (g_IC != NULL)
1067 XDestroyIC(g_IC);
1068
1069 XDestroyWindow(g_display, g_wnd);
1070 }
1071
1072 void
1073 xwin_toggle_fullscreen(void)
1074 {
1075 Pixmap contents = 0;
1076
1077 if (!g_ownbackstore)
1078 {
1079 /* need to save contents of window */
1080 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1081 XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1082 }
1083
1084 ui_destroy_window();
1085 g_fullscreen = !g_fullscreen;
1086 ui_create_window();
1087
1088 XDefineCursor(g_display, g_wnd, g_current_cursor);
1089
1090 if (!g_ownbackstore)
1091 {
1092 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1093 XFreePixmap(g_display, contents);
1094 }
1095 }
1096
1097 /* Process all events in Xlib queue
1098 Returns 0 after user quit, 1 otherwise */
1099 static int
1100 xwin_process_events(void)
1101 {
1102 XEvent xevent;
1103 KeySym keysym;
1104 uint16 button, flags;
1105 uint32 ev_time;
1106 key_translation tr;
1107 char str[256];
1108 Status status;
1109
1110 while (XPending(g_display) > 0)
1111 {
1112 XNextEvent(g_display, &xevent);
1113
1114 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1115 {
1116 DEBUG_KBD(("Filtering event\n"));
1117 continue;
1118 }
1119
1120 flags = 0;
1121
1122 switch (xevent.type)
1123 {
1124 case VisibilityNotify:
1125 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1126 break;
1127 case ClientMessage:
1128 /* the window manager told us to quit */
1129 if ((xevent.xclient.message_type == g_protocol_atom)
1130 && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1131 /* Quit */
1132 return 0;
1133 break;
1134
1135 case KeyPress:
1136 g_last_gesturetime = xevent.xkey.time;
1137 if (g_IC != NULL)
1138 /* Multi_key compatible version */
1139 {
1140 XmbLookupString(g_IC,
1141 &xevent.xkey, str, sizeof(str), &keysym,
1142 &status);
1143 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1144 {
1145 error("XmbLookupString failed with status 0x%x\n",
1146 status);
1147 break;
1148 }
1149 }
1150 else
1151 {
1152 /* Plain old XLookupString */
1153 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1154 XLookupString((XKeyEvent *) & xevent,
1155 str, sizeof(str), &keysym, NULL);
1156 }
1157
1158 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
1159 get_ksname(keysym)));
1160
1161 ev_time = time(NULL);
1162 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1163 break;
1164
1165 tr = xkeymap_translate_key(keysym,
1166 xevent.xkey.keycode, xevent.xkey.state);
1167
1168 if (tr.scancode == 0)
1169 break;
1170
1171 save_remote_modifiers(tr.scancode);
1172 ensure_remote_modifiers(ev_time, tr);
1173 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
1174 restore_remote_modifiers(ev_time, tr.scancode);
1175
1176 break;
1177
1178 case KeyRelease:
1179 g_last_gesturetime = xevent.xkey.time;
1180 XLookupString((XKeyEvent *) & xevent, str,
1181 sizeof(str), &keysym, NULL);
1182
1183 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
1184 get_ksname(keysym)));
1185
1186 ev_time = time(NULL);
1187 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1188 break;
1189
1190 tr = xkeymap_translate_key(keysym,
1191 xevent.xkey.keycode, xevent.xkey.state);
1192
1193 if (tr.scancode == 0)
1194 break;
1195
1196 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
1197 break;
1198
1199 case ButtonPress:
1200 flags = MOUSE_FLAG_DOWN;
1201 /* fall through */
1202
1203 case ButtonRelease:
1204 g_last_gesturetime = xevent.xbutton.time;
1205 button = xkeymap_translate_button(xevent.xbutton.button);
1206 if (button == 0)
1207 break;
1208
1209 /* If win_button_size is nonzero, enable single app mode */
1210 if (xevent.xbutton.y < g_win_button_size)
1211 {
1212 /* Stop moving window when button is released, regardless of cursor position */
1213 if (g_moving_wnd && (xevent.type == ButtonRelease))
1214 g_moving_wnd = False;
1215
1216 /* Check from right to left: */
1217
1218 if (xevent.xbutton.x >= g_width - g_win_button_size)
1219 {
1220 /* The close button, continue */
1221 ;
1222 }
1223 else if (xevent.xbutton.x >=
1224 g_width - g_win_button_size * 2)
1225 {
1226 /* The maximize/restore button. Do not send to
1227 server. It might be a good idea to change the
1228 cursor or give some other visible indication
1229 that rdesktop inhibited this click */
1230 break;
1231 }
1232 else if (xevent.xbutton.x >=
1233 g_width - g_win_button_size * 3)
1234 {
1235 /* The minimize button. Iconify window. */
1236 XIconifyWindow(g_display, g_wnd,
1237 DefaultScreen(g_display));
1238 break;
1239 }
1240 else if (xevent.xbutton.x <= g_win_button_size)
1241 {
1242 /* The system menu. Ignore. */
1243 break;
1244 }
1245 else
1246 {
1247 /* The title bar. */
1248 if ((xevent.type == ButtonPress) && !g_fullscreen
1249 && g_hide_decorations)
1250 {
1251 g_moving_wnd = True;
1252 g_move_x_offset = xevent.xbutton.x;
1253 g_move_y_offset = xevent.xbutton.y;
1254 }
1255 break;
1256
1257 }
1258 }
1259
1260 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1261 flags | button, xevent.xbutton.x, xevent.xbutton.y);
1262 break;
1263
1264 case MotionNotify:
1265 if (g_moving_wnd)
1266 {
1267 XMoveWindow(g_display, g_wnd,
1268 xevent.xmotion.x_root - g_move_x_offset,
1269 xevent.xmotion.y_root - g_move_y_offset);
1270 break;
1271 }
1272
1273 if (g_fullscreen && !g_focused)
1274 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1275 CurrentTime);
1276 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1277 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1278 break;
1279
1280 case FocusIn:
1281 if (xevent.xfocus.mode == NotifyGrab)
1282 break;
1283 g_focused = True;
1284 reset_modifier_keys();
1285 if (g_grab_keyboard && g_mouse_in_wnd)
1286 XGrabKeyboard(g_display, g_wnd, True,
1287 GrabModeAsync, GrabModeAsync, CurrentTime);
1288 break;
1289
1290 case FocusOut:
1291 if (xevent.xfocus.mode == NotifyUngrab)
1292 break;
1293 g_focused = False;
1294 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1295 XUngrabKeyboard(g_display, CurrentTime);
1296 break;
1297
1298 case EnterNotify:
1299 /* we only register for this event when in fullscreen mode */
1300 /* or grab_keyboard */
1301 g_mouse_in_wnd = True;
1302 if (g_fullscreen)
1303 {
1304 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1305 CurrentTime);
1306 break;
1307 }
1308 if (g_focused)
1309 XGrabKeyboard(g_display, g_wnd, True,
1310 GrabModeAsync, GrabModeAsync, CurrentTime);
1311 break;
1312
1313 case LeaveNotify:
1314 /* we only register for this event when grab_keyboard */
1315 g_mouse_in_wnd = False;
1316 XUngrabKeyboard(g_display, CurrentTime);
1317 break;
1318
1319 case Expose:
1320 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1321 xevent.xexpose.x, xevent.xexpose.y,
1322 xevent.xexpose.width,
1323 xevent.xexpose.height,
1324 xevent.xexpose.x, xevent.xexpose.y);
1325 break;
1326
1327 case MappingNotify:
1328 /* Refresh keyboard mapping if it has changed. This is important for
1329 Xvnc, since it allocates keycodes dynamically */
1330 if (xevent.xmapping.request == MappingKeyboard
1331 || xevent.xmapping.request == MappingModifier)
1332 XRefreshKeyboardMapping(&xevent.xmapping);
1333
1334 if (xevent.xmapping.request == MappingModifier)
1335 {
1336 XFreeModifiermap(g_mod_map);
1337 g_mod_map = XGetModifierMapping(g_display);
1338 }
1339 break;
1340
1341 /* clipboard stuff */
1342 case SelectionNotify:
1343 xclip_handle_SelectionNotify(&xevent.xselection);
1344 break;
1345 case SelectionRequest:
1346 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1347 break;
1348 case SelectionClear:
1349 xclip_handle_SelectionClear();
1350 break;
1351 case PropertyNotify:
1352 xclip_handle_PropertyNotify(&xevent.xproperty);
1353 break;
1354 }
1355 }
1356 /* Keep going */
1357 return 1;
1358 }
1359
1360 /* Returns 0 after user quit, 1 otherwise */
1361 int
1362 ui_select(int rdp_socket)
1363 {
1364 int n;
1365 fd_set rfds, wfds;
1366 struct timeval tv;
1367 BOOL s_timeout = False;
1368
1369 while (True)
1370 {
1371 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1372 /* Process any events already waiting */
1373 if (!xwin_process_events())
1374 /* User quit */
1375 return 0;
1376
1377 FD_ZERO(&rfds);
1378 FD_ZERO(&wfds);
1379 FD_SET(rdp_socket, &rfds);
1380 FD_SET(g_x_socket, &rfds);
1381
1382 #ifdef WITH_RDPSND
1383 /* FIXME: there should be an API for registering fds */
1384 if (g_dsp_busy)
1385 {
1386 FD_SET(g_dsp_fd, &wfds);
1387 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1388 }
1389 #endif
1390 /* default timeout */
1391 tv.tv_sec = 60;
1392 tv.tv_usec = 0;
1393
1394 /* add redirection handles */
1395 rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1396
1397 n++;
1398
1399 switch (select(n, &rfds, &wfds, NULL, &tv))
1400 {
1401 case -1:
1402 error("select: %s\n", strerror(errno));
1403
1404 case 0:
1405 /* TODO: if tv.tv_sec just times out
1406 * we will segfault.
1407 * FIXME:
1408 */
1409 //s_timeout = True;
1410 //rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1411 continue;
1412 }
1413
1414 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1415
1416 if (FD_ISSET(rdp_socket, &rfds))
1417 return 1;
1418
1419 #ifdef WITH_RDPSND
1420 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1421 wave_out_play();
1422 #endif
1423 }
1424 }
1425
1426 void
1427 ui_move_pointer(int x, int y)
1428 {
1429 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1430 }
1431
1432 HBITMAP
1433 ui_create_bitmap(int width, int height, uint8 * data)
1434 {
1435 XImage *image;
1436 Pixmap bitmap;
1437 uint8 *tdata;
1438 int bitmap_pad;
1439
1440 if (g_server_bpp == 8)
1441 {
1442 bitmap_pad = 8;
1443 }
1444 else
1445 {
1446 bitmap_pad = g_bpp;
1447
1448 if (g_bpp == 24)
1449 bitmap_pad = 32;
1450 }
1451
1452 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1453 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1454 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1455 (char *) tdata, width, height, bitmap_pad, 0);
1456
1457 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1458
1459 XFree(image);
1460 if (tdata != data)
1461 xfree(tdata);
1462 return (HBITMAP) bitmap;
1463 }
1464
1465 void
1466 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1467 {
1468 XImage *image;
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 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1486 (char *) tdata, width, height, bitmap_pad, 0);
1487
1488 if (g_ownbackstore)
1489 {
1490 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1491 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1492 }
1493 else
1494 {
1495 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1496 }
1497
1498 XFree(image);
1499 if (tdata != data)
1500 xfree(tdata);
1501 }
1502
1503 void
1504 ui_destroy_bitmap(HBITMAP bmp)
1505 {
1506 XFreePixmap(g_display, (Pixmap) bmp);
1507 }
1508
1509 HGLYPH
1510 ui_create_glyph(int width, int height, uint8 * data)
1511 {
1512 XImage *image;
1513 Pixmap bitmap;
1514 int scanline;
1515 GC gc;
1516
1517 scanline = (width + 7) / 8;
1518
1519 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1520 gc = XCreateGC(g_display, bitmap, 0, NULL);
1521
1522 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1523 width, height, 8, scanline);
1524 image->byte_order = MSBFirst;
1525 image->bitmap_bit_order = MSBFirst;
1526 XInitImage(image);
1527
1528 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1529
1530 XFree(image);
1531 XFreeGC(g_display, gc);
1532 return (HGLYPH) bitmap;
1533 }
1534
1535 void
1536 ui_destroy_glyph(HGLYPH glyph)
1537 {
1538 XFreePixmap(g_display, (Pixmap) glyph);
1539 }
1540
1541 HCURSOR
1542 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1543 uint8 * andmask, uint8 * xormask)
1544 {
1545 HGLYPH maskglyph, cursorglyph;
1546 XColor bg, fg;
1547 Cursor xcursor;
1548 uint8 *cursor, *pcursor;
1549 uint8 *mask, *pmask;
1550 uint8 nextbit;
1551 int scanline, offset;
1552 int i, j;
1553
1554 scanline = (width + 7) / 8;
1555 offset = scanline * height;
1556
1557 cursor = (uint8 *) xmalloc(offset);
1558 memset(cursor, 0, offset);
1559
1560 mask = (uint8 *) xmalloc(offset);
1561 memset(mask, 0, offset);
1562
1563 /* approximate AND and XOR masks with a monochrome X pointer */
1564 for (i = 0; i < height; i++)
1565 {
1566 offset -= scanline;
1567 pcursor = &cursor[offset];
1568 pmask = &mask[offset];
1569
1570 for (j = 0; j < scanline; j++)
1571 {
1572 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1573 {
1574 if (xormask[0] || xormask[1] || xormask[2])
1575 {
1576 *pcursor |= (~(*andmask) & nextbit);
1577 *pmask |= nextbit;
1578 }
1579 else
1580 {
1581 *pcursor |= ((*andmask) & nextbit);
1582 *pmask |= (~(*andmask) & nextbit);
1583 }
1584
1585 xormask += 3;
1586 }
1587
1588 andmask++;
1589 pcursor++;
1590 pmask++;
1591 }
1592 }
1593
1594 fg.red = fg.blue = fg.green = 0xffff;
1595 bg.red = bg.blue = bg.green = 0x0000;
1596 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1597
1598 cursorglyph = ui_create_glyph(width, height, cursor);
1599 maskglyph = ui_create_glyph(width, height, mask);
1600
1601 xcursor =
1602 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1603 (Pixmap) maskglyph, &fg, &bg, x, y);
1604
1605 ui_destroy_glyph(maskglyph);
1606 ui_destroy_glyph(cursorglyph);
1607 xfree(mask);
1608 xfree(cursor);
1609 return (HCURSOR) xcursor;
1610 }
1611
1612 void
1613 ui_set_cursor(HCURSOR cursor)
1614 {
1615 g_current_cursor = (Cursor) cursor;
1616 XDefineCursor(g_display, g_wnd, g_current_cursor);
1617 }
1618
1619 void
1620 ui_destroy_cursor(HCURSOR cursor)
1621 {
1622 XFreeCursor(g_display, (Cursor) cursor);
1623 }
1624
1625 void
1626 ui_set_null_cursor(void)
1627 {
1628 ui_set_cursor(g_null_cursor);
1629 }
1630
1631 #define MAKE_XCOLOR(xc,c) \
1632 (xc)->red = ((c)->red << 8) | (c)->red; \
1633 (xc)->green = ((c)->green << 8) | (c)->green; \
1634 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1635 (xc)->flags = DoRed | DoGreen | DoBlue;
1636
1637
1638 HCOLOURMAP
1639 ui_create_colourmap(COLOURMAP * colours)
1640 {
1641 COLOURENTRY *entry;
1642 int i, ncolours = colours->ncolours;
1643 if (!g_owncolmap)
1644 {
1645 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1646 XColor xentry;
1647 XColor xc_cache[256];
1648 uint32 colour;
1649 int colLookup = 256;
1650 for (i = 0; i < ncolours; i++)
1651 {
1652 entry = &colours->colours[i];
1653 MAKE_XCOLOR(&xentry, entry);
1654
1655 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1656 {
1657 /* Allocation failed, find closest match. */
1658 int j = 256;
1659 int nMinDist = 3 * 256 * 256;
1660 long nDist = nMinDist;
1661
1662 /* only get the colors once */
1663 while (colLookup--)
1664 {
1665 xc_cache[colLookup].pixel = colLookup;
1666 xc_cache[colLookup].red = xc_cache[colLookup].green =
1667 xc_cache[colLookup].blue = 0;
1668 xc_cache[colLookup].flags = 0;
1669 XQueryColor(g_display,
1670 DefaultColormap(g_display,
1671 DefaultScreen(g_display)),
1672 &xc_cache[colLookup]);
1673 }
1674 colLookup = 0;
1675
1676 /* approximate the pixel */
1677 while (j--)
1678 {
1679 if (xc_cache[j].flags)
1680 {
1681 nDist = ((long) (xc_cache[j].red >> 8) -
1682 (long) (xentry.red >> 8)) *
1683 ((long) (xc_cache[j].red >> 8) -
1684 (long) (xentry.red >> 8)) +
1685 ((long) (xc_cache[j].green >> 8) -
1686 (long) (xentry.green >> 8)) *
1687 ((long) (xc_cache[j].green >> 8) -
1688 (long) (xentry.green >> 8)) +
1689 ((long) (xc_cache[j].blue >> 8) -
1690 (long) (xentry.blue >> 8)) *
1691 ((long) (xc_cache[j].blue >> 8) -
1692 (long) (xentry.blue >> 8));
1693 }
1694 if (nDist < nMinDist)
1695 {
1696 nMinDist = nDist;
1697 xentry.pixel = j;
1698 }
1699 }
1700 }
1701 colour = xentry.pixel;
1702
1703 /* update our cache */
1704 if (xentry.pixel < 256)
1705 {
1706 xc_cache[xentry.pixel].red = xentry.red;
1707 xc_cache[xentry.pixel].green = xentry.green;
1708 xc_cache[xentry.pixel].blue = xentry.blue;
1709
1710 }
1711
1712 map[i] = colour;
1713 }
1714 return map;
1715 }
1716 else
1717 {
1718 XColor *xcolours, *xentry;
1719 Colormap map;
1720
1721 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1722 for (i = 0; i < ncolours; i++)
1723 {
1724 entry = &colours->colours[i];
1725 xentry = &xcolours[i];
1726 xentry->pixel = i;
1727 MAKE_XCOLOR(xentry, entry);
1728 }
1729
1730 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1731 XStoreColors(g_display, map, xcolours, ncolours);
1732
1733 xfree(xcolours);
1734 return (HCOLOURMAP) map;
1735 }
1736 }
1737
1738 void
1739 ui_destroy_colourmap(HCOLOURMAP map)
1740 {
1741 if (!g_owncolmap)
1742 xfree(map);
1743 else
1744 XFreeColormap(g_display, (Colormap) map);
1745 }
1746
1747 void
1748 ui_set_colourmap(HCOLOURMAP map)
1749 {
1750 if (!g_owncolmap)
1751 {
1752 if (g_colmap)
1753 xfree(g_colmap);
1754
1755 g_colmap = (uint32 *) map;
1756 }
1757 else
1758 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1759 }
1760
1761 void
1762 ui_set_clip(int x, int y, int cx, int cy)
1763 {
1764 XRectangle rect;
1765
1766 rect.x = x;
1767 rect.y = y;
1768 rect.width = cx;
1769 rect.height = cy;
1770 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1771 }
1772
1773 void
1774 ui_reset_clip(void)
1775 {
1776 XRectangle rect;
1777
1778 rect.x = 0;
1779 rect.y = 0;
1780 rect.width = g_width;
1781 rect.height = g_height;
1782 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1783 }
1784
1785 void
1786 ui_bell(void)
1787 {
1788 XBell(g_display, 0);
1789 }
1790
1791 void
1792 ui_destblt(uint8 opcode,
1793 /* dest */ int x, int y, int cx, int cy)
1794 {
1795 SET_FUNCTION(opcode);
1796 FILL_RECTANGLE(x, y, cx, cy);
1797 RESET_FUNCTION(opcode);
1798 }
1799
1800 static uint8 hatch_patterns[] = {
1801 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1802 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1803 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1804 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1805 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1806 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1807 };
1808
1809 void
1810 ui_patblt(uint8 opcode,
1811 /* dest */ int x, int y, int cx, int cy,
1812 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1813 {
1814 Pixmap fill;
1815 uint8 i, ipattern[8];
1816
1817 SET_FUNCTION(opcode);
1818
1819 switch (brush->style)
1820 {
1821 case 0: /* Solid */
1822 SET_FOREGROUND(fgcolour);
1823 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1824 break;
1825
1826 case 2: /* Hatch */
1827 fill = (Pixmap) ui_create_glyph(8, 8,
1828 hatch_patterns + brush->pattern[0] * 8);
1829 SET_FOREGROUND(fgcolour);
1830 SET_BACKGROUND(bgcolour);
1831 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1832 XSetStipple(g_display, g_gc, fill);
1833 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1834 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1835 XSetFillStyle(g_display, g_gc, FillSolid);
1836 XSetTSOrigin(g_display, g_gc, 0, 0);
1837 ui_destroy_glyph((HGLYPH) fill);
1838 break;
1839
1840 case 3: /* Pattern */
1841 for (i = 0; i != 8; i++)
1842 ipattern[7 - i] = brush->pattern[i];
1843 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1844 SET_FOREGROUND(bgcolour);
1845 SET_BACKGROUND(fgcolour);
1846 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1847 XSetStipple(g_display, g_gc, fill);
1848 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1849 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1850 XSetFillStyle(g_display, g_gc, FillSolid);
1851 XSetTSOrigin(g_display, g_gc, 0, 0);
1852 ui_destroy_glyph((HGLYPH) fill);
1853 break;
1854
1855 default:
1856 unimpl("brush %d\n", brush->style);
1857 }
1858
1859 RESET_FUNCTION(opcode);
1860
1861 if (g_ownbackstore)
1862 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1863 }
1864
1865 void
1866 ui_screenblt(uint8 opcode,
1867 /* dest */ int x, int y, int cx, int cy,
1868 /* src */ int srcx, int srcy)
1869 {
1870 SET_FUNCTION(opcode);
1871 if (g_ownbackstore)
1872 {
1873 if (g_Unobscured)
1874 {
1875 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1876 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1877 y);
1878 }
1879 else
1880 {
1881 XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1882 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
1883 y);
1884 }
1885 }
1886 else
1887 {
1888 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1889 }
1890 RESET_FUNCTION(opcode);
1891 }
1892
1893 void
1894 ui_memblt(uint8 opcode,
1895 /* dest */ int x, int y, int cx, int cy,
1896 /* src */ HBITMAP src, int srcx, int srcy)
1897 {
1898 SET_FUNCTION(opcode);
1899 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1900 if (g_ownbackstore)
1901 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1902 RESET_FUNCTION(opcode);
1903 }
1904
1905 void
1906 ui_triblt(uint8 opcode,
1907 /* dest */ int x, int y, int cx, int cy,
1908 /* src */ HBITMAP src, int srcx, int srcy,
1909 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1910 {
1911 /* This is potentially difficult to do in general. Until someone
1912 comes up with a more efficient way of doing it I am using cases. */
1913
1914 switch (opcode)
1915 {
1916 case 0x69: /* PDSxxn */
1917 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1918 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1919 break;
1920
1921 case 0xb8: /* PSDPxax */
1922 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1923 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1924 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1925 break;
1926
1927 case 0xc0: /* PSa */
1928 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1929 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1930 break;
1931
1932 default:
1933 unimpl("triblt 0x%x\n", opcode);
1934 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1935 }
1936 }
1937
1938 void
1939 ui_line(uint8 opcode,
1940 /* dest */ int startx, int starty, int endx, int endy,
1941 /* pen */ PEN * pen)
1942 {
1943 SET_FUNCTION(opcode);
1944 SET_FOREGROUND(pen->colour);
1945 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1946 if (g_ownbackstore)
1947 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1948 RESET_FUNCTION(opcode);
1949 }
1950
1951 void
1952 ui_rect(
1953 /* dest */ int x, int y, int cx, int cy,
1954 /* brush */ int colour)
1955 {
1956 SET_FOREGROUND(colour);
1957 FILL_RECTANGLE(x, y, cx, cy);
1958 }
1959
1960 /* warning, this function only draws on wnd or backstore, not both */
1961 void
1962 ui_draw_glyph(int mixmode,
1963 /* dest */ int x, int y, int cx, int cy,
1964 /* src */ HGLYPH glyph, int srcx, int srcy,
1965 int bgcolour, int fgcolour)
1966 {
1967 SET_FOREGROUND(fgcolour);
1968 SET_BACKGROUND(bgcolour);
1969
1970 XSetFillStyle(g_display, g_gc,
1971 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1972 XSetStipple(g_display, g_gc, (Pixmap) glyph);
1973 XSetTSOrigin(g_display, g_gc, x, y);
1974
1975 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1976
1977 XSetFillStyle(g_display, g_gc, FillSolid);
1978 }
1979
1980 #define DO_GLYPH(ttext,idx) \
1981 {\
1982 glyph = cache_get_font (font, ttext[idx]);\
1983 if (!(flags & TEXT2_IMPLICIT_X))\
1984 {\
1985 xyoffset = ttext[++idx];\
1986 if ((xyoffset & 0x80))\
1987 {\
1988 if (flags & TEXT2_VERTICAL)\
1989 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1990 else\
1991 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1992 idx += 2;\
1993 }\
1994 else\
1995 {\
1996 if (flags & TEXT2_VERTICAL)\
1997 y += xyoffset;\
1998 else\
1999 x += xyoffset;\
2000 }\
2001 }\
2002 if (glyph != NULL)\
2003 {\
2004 x1 = x + glyph->offset;\
2005 y1 = y + glyph->baseline;\
2006 XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2007 XSetTSOrigin(g_display, g_gc, x1, y1);\
2008 FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2009 if (flags & TEXT2_IMPLICIT_X)\
2010 x += glyph->width;\
2011 }\
2012 }
2013
2014 void
2015 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
2016 int clipx, int clipy, int clipcx, int clipcy,
2017 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
2018 int fgcolour, uint8 * text, uint8 length)
2019 {
2020 FONTGLYPH *glyph;
2021 int i, j, xyoffset, x1, y1;
2022 DATABLOB *entry;
2023
2024 SET_FOREGROUND(bgcolour);
2025
2026 /* Sometimes, the boxcx value is something really large, like
2027 32691. This makes XCopyArea fail with Xvnc. The code below
2028 is a quick fix. */
2029 if (boxx + boxcx > g_width)
2030 boxcx = g_width - boxx;
2031
2032 if (boxcx > 1)
2033 {
2034 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2035 }
2036 else if (mixmode == MIX_OPAQUE)
2037 {
2038 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2039 }
2040
2041 SET_FOREGROUND(fgcolour);
2042 SET_BACKGROUND(bgcolour);
2043 XSetFillStyle(g_display, g_gc, FillStippled);
2044
2045 /* Paint text, character by character */
2046 for (i = 0; i < length;)
2047 {
2048 switch (text[i])
2049 {
2050 case 0xff:
2051 if (i + 2 < length)
2052 cache_put_text(text[i + 1], text, text[i + 2]);
2053 else
2054 {
2055 error("this shouldn't be happening\n");
2056 exit(1);
2057 }
2058 /* this will move pointer from start to first character after FF command */
2059 length -= i + 3;
2060 text = &(text[i + 3]);
2061 i = 0;
2062 break;
2063
2064 case 0xfe:
2065 entry = cache_get_text(text[i + 1]);
2066 if (entry != NULL)
2067 {
2068 if ((((uint8 *) (entry->data))[1] ==
2069 0) && (!(flags & TEXT2_IMPLICIT_X)))
2070 {
2071 if (flags & TEXT2_VERTICAL)
2072 y += text[i + 2];
2073 else
2074 x += text[i + 2];
2075 }
2076 for (j = 0; j < entry->size; j++)
2077 DO_GLYPH(((uint8 *) (entry->data)), j);
2078 }
2079 if (i + 2 < length)
2080 i += 3;
2081 else
2082 i += 2;
2083 length -= i;
2084 /* this will move pointer from start to first character after FE command */
2085 text = &(text[i]);
2086 i = 0;
2087 break;
2088
2089 default:
2090 DO_GLYPH(text, i);
2091 i++;
2092 break;
2093 }
2094 }
2095
2096 XSetFillStyle(g_display, g_gc, FillSolid);
2097
2098 if (g_ownbackstore)
2099 {
2100 if (boxcx > 1)
2101 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2102 boxy, boxcx, boxcy, boxx, boxy);
2103 else
2104 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2105 clipy, clipcx, clipcy, clipx, clipy);
2106 }
2107 }
2108
2109 void
2110 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2111 {
2112 Pixmap pix;
2113 XImage *image;
2114
2115 if (g_ownbackstore)
2116 {
2117 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2118 }
2119 else
2120 {
2121 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2122 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2123 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2124 XFreePixmap(g_display, pix);
2125 }
2126
2127 offset *= g_bpp / 8;
2128 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2129
2130 XDestroyImage(image);
2131 }
2132
2133 void
2134 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2135 {
2136 XImage *image;
2137 uint8 *data;
2138
2139 offset *= g_bpp / 8;
2140 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2141 if (data == NULL)
2142 return;
2143
2144 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2145 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2146
2147 if (g_ownbackstore)
2148 {
2149 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2150 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2151 }
2152 else
2153 {
2154 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2155 }
2156
2157 XFree(image);
2158 }

  ViewVC Help
Powered by ViewVC 1.1.26