/[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 461 - (show annotations)
Tue Sep 2 09:40:07 2003 UTC (20 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 39923 byte(s)
restore_remote_modifiers takes ev_time argument.

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

  ViewVC Help
Powered by ViewVC 1.1.26