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

  ViewVC Help
Powered by ViewVC 1.1.26