/[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 695 - (show annotations)
Tue May 11 07:34:03 2004 UTC (19 years, 11 months ago) by stargo
File MIME type: text/plain
File size: 47250 byte(s)
fix compiler warning/error "a cast does not yield a lvalue"

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

  ViewVC Help
Powered by ViewVC 1.1.26