/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 592 - (show annotations)
Fri Jan 30 14:10:32 2004 UTC (20 years, 3 months ago) by n-ki
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 44749 byte(s)
reworked the asyncio some and completed it. parallel and serial uses it now. disk.c is a likely candidate for the future, but there are some problems with disk.c that we will have to look into first. parallel and serial works better, they do not hang the session, but are still yerky at large chunks... possibly we could split the chunks, but the terminal server does not seem to like partial transfers, i've tried some variations.. :) fns->write() could be split in smaller pieces, but what should the thresholds be.

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

  ViewVC Help
Powered by ViewVC 1.1.26