/[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 679 - (show annotations)
Mon Apr 26 23:00:25 2004 UTC (20 years ago) by jsorg71
File MIME type: text/plain
File size: 46684 byte(s)
unroll the bits in translate8to16/32

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

  ViewVC Help
Powered by ViewVC 1.1.26