/[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 474 - (show annotations)
Tue Sep 30 09:11:08 2003 UTC (20 years, 7 months ago) by matthewc
File MIME type: text/plain
File size: 41013 byte(s)
Preliminary sound support (PCM only).
Based on code from GuoJunBo <guojunbo@ict.ac.cn>

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

  ViewVC Help
Powered by ViewVC 1.1.26