/[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 677 - (show annotations)
Mon Apr 26 13:48:39 2004 UTC (20 years, 1 month ago) by n-ki
File MIME type: text/plain
File size: 46364 byte(s)
new: ui_resize_window() and related, which is used when resizing while shadowing. And fallback for color when connecting to a session with fewer colors than you have set in your session. Jeroen Meijer jeroen@oldambt7.com

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

  ViewVC Help
Powered by ViewVC 1.1.26