/[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 688 - (show annotations)
Fri Apr 30 19:14:15 2004 UTC (20 years ago) by jsorg71
File MIME type: text/plain
File size: 47218 byte(s)
speed up screenblt if screen is unobscured

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

  ViewVC Help
Powered by ViewVC 1.1.26