/[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 450 - (show annotations)
Wed Aug 27 22:51:33 2003 UTC (20 years, 8 months ago) by jsorg71
File MIME type: text/plain
File size: 39903 byte(s)
more g_ prefix for global vars

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();
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 >= g_width - g_win_button_size * 2)
889 {
890 /* The maximize/restore button. Do not send to
891 server. It might be a good idea to change the
892 cursor or give some other visible indication
893 that rdesktop inhibited this click */
894 break;
895 }
896 else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
897 {
898 /* The minimize button. Iconify window. */
899 XIconifyWindow(g_display, g_wnd,
900 DefaultScreen(g_display));
901 break;
902 }
903 else if (xevent.xbutton.x <= g_win_button_size)
904 {
905 /* The system menu. Ignore. */
906 break;
907 }
908 else
909 {
910 /* The title bar. */
911 if ((xevent.type == ButtonPress) && !g_fullscreen
912 && g_hide_decorations)
913 {
914 g_moving_wnd = True;
915 g_move_x_offset = xevent.xbutton.x;
916 g_move_y_offset = xevent.xbutton.y;
917 }
918 break;
919
920 }
921 }
922
923 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
924 flags | button, xevent.xbutton.x, xevent.xbutton.y);
925 break;
926
927 case MotionNotify:
928 if (g_moving_wnd)
929 {
930 XMoveWindow(g_display, g_wnd,
931 xevent.xmotion.x_root - g_move_x_offset,
932 xevent.xmotion.y_root - g_move_y_offset);
933 break;
934 }
935
936 if (g_fullscreen && !g_focused)
937 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
938 CurrentTime);
939 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
940 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
941 break;
942
943 case FocusIn:
944 if (xevent.xfocus.mode == NotifyGrab)
945 break;
946 g_focused = True;
947 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
948 &dummy, &dummy, &state);
949 reset_modifier_keys(state);
950 if (g_grab_keyboard && g_mouse_in_wnd)
951 XGrabKeyboard(g_display, g_wnd, True,
952 GrabModeAsync, GrabModeAsync, CurrentTime);
953 break;
954
955 case FocusOut:
956 if (xevent.xfocus.mode == NotifyUngrab)
957 break;
958 g_focused = False;
959 if (xevent.xfocus.mode == NotifyWhileGrabbed)
960 XUngrabKeyboard(g_display, CurrentTime);
961 break;
962
963 case EnterNotify:
964 /* we only register for this event when in fullscreen mode */
965 /* or grab_keyboard */
966 g_mouse_in_wnd = True;
967 if (g_fullscreen)
968 {
969 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
970 CurrentTime);
971 break;
972 }
973 if (g_focused)
974 XGrabKeyboard(g_display, g_wnd, True,
975 GrabModeAsync, GrabModeAsync, CurrentTime);
976 break;
977
978 case LeaveNotify:
979 /* we only register for this event when grab_keyboard */
980 g_mouse_in_wnd = False;
981 XUngrabKeyboard(g_display, CurrentTime);
982 break;
983
984 case Expose:
985 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
986 xevent.xexpose.x, xevent.xexpose.y,
987 xevent.xexpose.width,
988 xevent.xexpose.height,
989 xevent.xexpose.x, xevent.xexpose.y);
990 break;
991
992 case MappingNotify:
993 /* Refresh keyboard mapping if it has changed. This is important for
994 Xvnc, since it allocates keycodes dynamically */
995 if (xevent.xmapping.request == MappingKeyboard
996 || xevent.xmapping.request == MappingModifier)
997 XRefreshKeyboardMapping(&xevent.xmapping);
998
999 if (xevent.xmapping.request == MappingModifier)
1000 {
1001 XFreeModifiermap(g_mod_map);
1002 g_mod_map = XGetModifierMapping(g_display);
1003 }
1004 break;
1005
1006 /* clipboard stuff */
1007 case SelectionNotify:
1008 xclip_handle_SelectionNotify(&xevent.xselection);
1009 break;
1010 case SelectionRequest:
1011 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1012 break;
1013 case SelectionClear:
1014 xclip_handle_SelectionClear();
1015 break;
1016 case PropertyNotify:
1017 xclip_handle_PropertyNotify(&xevent.xproperty);
1018 break;
1019 }
1020 }
1021 /* Keep going */
1022 return 1;
1023 }
1024
1025 /* Returns 0 after user quit, 1 otherwise */
1026 int
1027 ui_select(int rdp_socket)
1028 {
1029 int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1030 fd_set rfds;
1031
1032 FD_ZERO(&rfds);
1033
1034 while (True)
1035 {
1036 /* Process any events already waiting */
1037 if (!xwin_process_events())
1038 /* User quit */
1039 return 0;
1040
1041 FD_ZERO(&rfds);
1042 FD_SET(rdp_socket, &rfds);
1043 FD_SET(g_x_socket, &rfds);
1044
1045 switch (select(n, &rfds, NULL, NULL, NULL))
1046 {
1047 case -1:
1048 error("select: %s\n", strerror(errno));
1049
1050 case 0:
1051 continue;
1052 }
1053
1054 if (FD_ISSET(rdp_socket, &rfds))
1055 return 1;
1056 }
1057 }
1058
1059 void
1060 ui_move_pointer(int x, int y)
1061 {
1062 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1063 }
1064
1065 HBITMAP
1066 ui_create_bitmap(int width, int height, uint8 * data)
1067 {
1068 XImage *image;
1069 Pixmap bitmap;
1070 uint8 *tdata;
1071
1072 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1073 bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1074 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1075 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1076
1077 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1078
1079 XFree(image);
1080 if (!g_owncolmap)
1081 xfree(tdata);
1082 return (HBITMAP) bitmap;
1083 }
1084
1085 void
1086 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1087 {
1088 XImage *image;
1089 uint8 *tdata;
1090 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1091 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1092 (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1093
1094 if (g_ownbackstore)
1095 {
1096 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1097 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1098 }
1099 else
1100 {
1101 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1102 }
1103
1104 XFree(image);
1105 if (!g_owncolmap)
1106 xfree(tdata);
1107 }
1108
1109 void
1110 ui_destroy_bitmap(HBITMAP bmp)
1111 {
1112 XFreePixmap(g_display, (Pixmap) bmp);
1113 }
1114
1115 HGLYPH
1116 ui_create_glyph(int width, int height, uint8 * data)
1117 {
1118 XImage *image;
1119 Pixmap bitmap;
1120 int scanline;
1121 GC gc;
1122
1123 scanline = (width + 7) / 8;
1124
1125 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1126 gc = XCreateGC(g_display, bitmap, 0, NULL);
1127
1128 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1129 width, height, 8, scanline);
1130 image->byte_order = MSBFirst;
1131 image->bitmap_bit_order = MSBFirst;
1132 XInitImage(image);
1133
1134 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1135
1136 XFree(image);
1137 XFreeGC(g_display, gc);
1138 return (HGLYPH) bitmap;
1139 }
1140
1141 void
1142 ui_destroy_glyph(HGLYPH glyph)
1143 {
1144 XFreePixmap(g_display, (Pixmap) glyph);
1145 }
1146
1147 HCURSOR
1148 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1149 uint8 * andmask, uint8 * xormask)
1150 {
1151 HGLYPH maskglyph, cursorglyph;
1152 XColor bg, fg;
1153 Cursor xcursor;
1154 uint8 *cursor, *pcursor;
1155 uint8 *mask, *pmask;
1156 uint8 nextbit;
1157 int scanline, offset;
1158 int i, j;
1159
1160 scanline = (width + 7) / 8;
1161 offset = scanline * height;
1162
1163 cursor = (uint8 *) xmalloc(offset);
1164 memset(cursor, 0, offset);
1165
1166 mask = (uint8 *) xmalloc(offset);
1167 memset(mask, 0, offset);
1168
1169 /* approximate AND and XOR masks with a monochrome X pointer */
1170 for (i = 0; i < height; i++)
1171 {
1172 offset -= scanline;
1173 pcursor = &cursor[offset];
1174 pmask = &mask[offset];
1175
1176 for (j = 0; j < scanline; j++)
1177 {
1178 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1179 {
1180 if (xormask[0] || xormask[1] || xormask[2])
1181 {
1182 *pcursor |= (~(*andmask) & nextbit);
1183 *pmask |= nextbit;
1184 }
1185 else
1186 {
1187 *pcursor |= ((*andmask) & nextbit);
1188 *pmask |= (~(*andmask) & nextbit);
1189 }
1190
1191 xormask += 3;
1192 }
1193
1194 andmask++;
1195 pcursor++;
1196 pmask++;
1197 }
1198 }
1199
1200 fg.red = fg.blue = fg.green = 0xffff;
1201 bg.red = bg.blue = bg.green = 0x0000;
1202 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1203
1204 cursorglyph = ui_create_glyph(width, height, cursor);
1205 maskglyph = ui_create_glyph(width, height, mask);
1206
1207 xcursor =
1208 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1209 (Pixmap) maskglyph, &fg, &bg, x, y);
1210
1211 ui_destroy_glyph(maskglyph);
1212 ui_destroy_glyph(cursorglyph);
1213 xfree(mask);
1214 xfree(cursor);
1215 return (HCURSOR) xcursor;
1216 }
1217
1218 void
1219 ui_set_cursor(HCURSOR cursor)
1220 {
1221 g_current_cursor = (Cursor) cursor;
1222 XDefineCursor(g_display, g_wnd, g_current_cursor);
1223 }
1224
1225 void
1226 ui_destroy_cursor(HCURSOR cursor)
1227 {
1228 XFreeCursor(g_display, (Cursor) cursor);
1229 }
1230
1231 #define MAKE_XCOLOR(xc,c) \
1232 (xc)->red = ((c)->red << 8) | (c)->red; \
1233 (xc)->green = ((c)->green << 8) | (c)->green; \
1234 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1235 (xc)->flags = DoRed | DoGreen | DoBlue;
1236
1237
1238 HCOLOURMAP
1239 ui_create_colourmap(COLOURMAP * colours)
1240 {
1241 COLOURENTRY *entry;
1242 int i, ncolours = colours->ncolours;
1243 if (!g_owncolmap)
1244 {
1245 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1246 XColor xentry;
1247 XColor xc_cache[256];
1248 uint32 colour;
1249 int colLookup = 256;
1250 for (i = 0; i < ncolours; i++)
1251 {
1252 entry = &colours->colours[i];
1253 MAKE_XCOLOR(&xentry, entry);
1254
1255 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1256 {
1257 /* Allocation failed, find closest match. */
1258 int j = 256;
1259 int nMinDist = 3 * 256 * 256;
1260 long nDist = nMinDist;
1261
1262 /* only get the colors once */
1263 while (colLookup--)
1264 {
1265 xc_cache[colLookup].pixel = colLookup;
1266 xc_cache[colLookup].red = xc_cache[colLookup].green =
1267 xc_cache[colLookup].blue = 0;
1268 xc_cache[colLookup].flags = 0;
1269 XQueryColor(g_display,
1270 DefaultColormap(g_display,
1271 DefaultScreen(g_display)),
1272 &xc_cache[colLookup]);
1273 }
1274 colLookup = 0;
1275
1276 /* approximate the pixel */
1277 while (j--)
1278 {
1279 if (xc_cache[j].flags)
1280 {
1281 nDist = ((long) (xc_cache[j].red >> 8) -
1282 (long) (xentry.red >> 8)) *
1283 ((long) (xc_cache[j].red >> 8) -
1284 (long) (xentry.red >> 8)) +
1285 ((long) (xc_cache[j].green >> 8) -
1286 (long) (xentry.green >> 8)) *
1287 ((long) (xc_cache[j].green >> 8) -
1288 (long) (xentry.green >> 8)) +
1289 ((long) (xc_cache[j].blue >> 8) -
1290 (long) (xentry.blue >> 8)) *
1291 ((long) (xc_cache[j].blue >> 8) -
1292 (long) (xentry.blue >> 8));
1293 }
1294 if (nDist < nMinDist)
1295 {
1296 nMinDist = nDist;
1297 xentry.pixel = j;
1298 }
1299 }
1300 }
1301 colour = xentry.pixel;
1302
1303 /* update our cache */
1304 if (xentry.pixel < 256)
1305 {
1306 xc_cache[xentry.pixel].red = xentry.red;
1307 xc_cache[xentry.pixel].green = xentry.green;
1308 xc_cache[xentry.pixel].blue = xentry.blue;
1309
1310 }
1311
1312
1313 /* byte swap here to make translate_image faster */
1314 map[i] = translate_colour(colour);
1315 }
1316 return map;
1317 }
1318 else
1319 {
1320 XColor *xcolours, *xentry;
1321 Colormap map;
1322
1323 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1324 for (i = 0; i < ncolours; i++)
1325 {
1326 entry = &colours->colours[i];
1327 xentry = &xcolours[i];
1328 xentry->pixel = i;
1329 MAKE_XCOLOR(xentry, entry);
1330 }
1331
1332 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1333 XStoreColors(g_display, map, xcolours, ncolours);
1334
1335 xfree(xcolours);
1336 return (HCOLOURMAP) map;
1337 }
1338 }
1339
1340 void
1341 ui_destroy_colourmap(HCOLOURMAP map)
1342 {
1343 if (!g_owncolmap)
1344 xfree(map);
1345 else
1346 XFreeColormap(g_display, (Colormap) map);
1347 }
1348
1349 void
1350 ui_set_colourmap(HCOLOURMAP map)
1351 {
1352 if (!g_owncolmap)
1353 {
1354 if (g_colmap)
1355 xfree(g_colmap);
1356
1357 g_colmap = (uint32 *) map;
1358 }
1359 else
1360 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1361 }
1362
1363 void
1364 ui_set_clip(int x, int y, int cx, int cy)
1365 {
1366 XRectangle rect;
1367
1368 rect.x = x;
1369 rect.y = y;
1370 rect.width = cx;
1371 rect.height = cy;
1372 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1373 }
1374
1375 void
1376 ui_reset_clip(void)
1377 {
1378 XRectangle rect;
1379
1380 rect.x = 0;
1381 rect.y = 0;
1382 rect.width = g_width;
1383 rect.height = g_height;
1384 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1385 }
1386
1387 void
1388 ui_bell(void)
1389 {
1390 XBell(g_display, 0);
1391 }
1392
1393 void
1394 ui_destblt(uint8 opcode,
1395 /* dest */ int x, int y, int cx, int cy)
1396 {
1397 SET_FUNCTION(opcode);
1398 FILL_RECTANGLE(x, y, cx, cy);
1399 RESET_FUNCTION(opcode);
1400 }
1401
1402 static uint8 hatch_patterns[] = {
1403 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1404 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1405 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1406 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1407 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1408 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1409 };
1410
1411 void
1412 ui_patblt(uint8 opcode,
1413 /* dest */ int x, int y, int cx, int cy,
1414 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1415 {
1416 Pixmap fill;
1417 uint8 i, ipattern[8];
1418
1419 SET_FUNCTION(opcode);
1420
1421 switch (brush->style)
1422 {
1423 case 0: /* Solid */
1424 SET_FOREGROUND(fgcolour);
1425 FILL_RECTANGLE(x, y, cx, cy);
1426 break;
1427
1428 case 2: /* Hatch */
1429 fill = (Pixmap) ui_create_glyph(8, 8,
1430 hatch_patterns + brush->pattern[0] * 8);
1431 SET_FOREGROUND(bgcolour);
1432 SET_BACKGROUND(fgcolour);
1433 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1434 XSetStipple(g_display, g_gc, fill);
1435 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1436 FILL_RECTANGLE(x, y, cx, cy);
1437 XSetFillStyle(g_display, g_gc, FillSolid);
1438 XSetTSOrigin(g_display, g_gc, 0, 0);
1439 ui_destroy_glyph((HGLYPH) fill);
1440 break;
1441
1442 case 3: /* Pattern */
1443 for (i = 0; i != 8; i++)
1444 ipattern[7 - i] = brush->pattern[i];
1445 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1446
1447 SET_FOREGROUND(bgcolour);
1448 SET_BACKGROUND(fgcolour);
1449 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1450 XSetStipple(g_display, g_gc, fill);
1451 XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1452
1453 FILL_RECTANGLE(x, y, cx, cy);
1454
1455 XSetFillStyle(g_display, g_gc, FillSolid);
1456 XSetTSOrigin(g_display, g_gc, 0, 0);
1457 ui_destroy_glyph((HGLYPH) fill);
1458 break;
1459
1460 default:
1461 unimpl("brush %d\n", brush->style);
1462 }
1463
1464 RESET_FUNCTION(opcode);
1465 }
1466
1467 void
1468 ui_screenblt(uint8 opcode,
1469 /* dest */ int x, int y, int cx, int cy,
1470 /* src */ int srcx, int srcy)
1471 {
1472 SET_FUNCTION(opcode);
1473 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1474 if (g_ownbackstore)
1475 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1476 RESET_FUNCTION(opcode);
1477 }
1478
1479 void
1480 ui_memblt(uint8 opcode,
1481 /* dest */ int x, int y, int cx, int cy,
1482 /* src */ HBITMAP src, int srcx, int srcy)
1483 {
1484 SET_FUNCTION(opcode);
1485 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1486 if (g_ownbackstore)
1487 XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1488 RESET_FUNCTION(opcode);
1489 }
1490
1491 void
1492 ui_triblt(uint8 opcode,
1493 /* dest */ int x, int y, int cx, int cy,
1494 /* src */ HBITMAP src, int srcx, int srcy,
1495 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1496 {
1497 /* This is potentially difficult to do in general. Until someone
1498 comes up with a more efficient way of doing it I am using cases. */
1499
1500 switch (opcode)
1501 {
1502 case 0x69: /* PDSxxn */
1503 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1504 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1505 break;
1506
1507 case 0xb8: /* PSDPxax */
1508 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1509 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1510 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1511 break;
1512
1513 case 0xc0: /* PSa */
1514 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1515 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1516 break;
1517
1518 default:
1519 unimpl("triblt 0x%x\n", opcode);
1520 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1521 }
1522 }
1523
1524 void
1525 ui_line(uint8 opcode,
1526 /* dest */ int startx, int starty, int endx, int endy,
1527 /* pen */ PEN * pen)
1528 {
1529 SET_FUNCTION(opcode);
1530 SET_FOREGROUND(pen->colour);
1531 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1532 if (g_ownbackstore)
1533 XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1534 RESET_FUNCTION(opcode);
1535 }
1536
1537 void
1538 ui_rect(
1539 /* dest */ int x, int y, int cx, int cy,
1540 /* brush */ int colour)
1541 {
1542 SET_FOREGROUND(colour);
1543 FILL_RECTANGLE(x, y, cx, cy);
1544 }
1545
1546 /* warning, this function only draws on wnd or backstore, not both */
1547 void
1548 ui_draw_glyph(int mixmode,
1549 /* dest */ int x, int y, int cx, int cy,
1550 /* src */ HGLYPH glyph, int srcx, int srcy,
1551 int bgcolour, int fgcolour)
1552 {
1553 SET_FOREGROUND(fgcolour);
1554 SET_BACKGROUND(bgcolour);
1555
1556 XSetFillStyle(g_display, g_gc,
1557 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1558 XSetStipple(g_display, g_gc, (Pixmap) glyph);
1559 XSetTSOrigin(g_display, g_gc, x, y);
1560
1561 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1562
1563 XSetFillStyle(g_display, g_gc, FillSolid);
1564 }
1565
1566 #define DO_GLYPH(ttext,idx) \
1567 {\
1568 glyph = cache_get_font (font, ttext[idx]);\
1569 if (!(flags & TEXT2_IMPLICIT_X))\
1570 {\
1571 xyoffset = ttext[++idx];\
1572 if ((xyoffset & 0x80))\
1573 {\
1574 if (flags & TEXT2_VERTICAL) \
1575 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1576 else\
1577 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1578 idx += 2;\
1579 }\
1580 else\
1581 {\
1582 if (flags & TEXT2_VERTICAL) \
1583 y += xyoffset;\
1584 else\
1585 x += xyoffset;\
1586 }\
1587 }\
1588 if (glyph != NULL)\
1589 {\
1590 ui_draw_glyph (mixmode, x + glyph->offset,\
1591 y + glyph->baseline,\
1592 glyph->width, glyph->height,\
1593 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1594 if (flags & TEXT2_IMPLICIT_X)\
1595 x += glyph->width;\
1596 }\
1597 }
1598
1599 void
1600 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1601 int clipx, int clipy, int clipcx, int clipcy,
1602 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1603 int fgcolour, uint8 * text, uint8 length)
1604 {
1605 FONTGLYPH *glyph;
1606 int i, j, xyoffset;
1607 DATABLOB *entry;
1608
1609 SET_FOREGROUND(bgcolour);
1610
1611 if (boxcx > 1)
1612 {
1613 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1614 }
1615 else if (mixmode == MIX_OPAQUE)
1616 {
1617 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1618 }
1619
1620 /* Paint text, character by character */
1621 for (i = 0; i < length;)
1622 {
1623 switch (text[i])
1624 {
1625 case 0xff:
1626 if (i + 2 < length)
1627 cache_put_text(text[i + 1], text, text[i + 2]);
1628 else
1629 {
1630 error("this shouldn't be happening\n");
1631 exit(1);
1632 }
1633 /* this will move pointer from start to first character after FF command */
1634 length -= i + 3;
1635 text = &(text[i + 3]);
1636 i = 0;
1637 break;
1638
1639 case 0xfe:
1640 entry = cache_get_text(text[i + 1]);
1641 if (entry != NULL)
1642 {
1643 if ((((uint8 *) (entry->data))[1] ==
1644 0) && (!(flags & TEXT2_IMPLICIT_X)))
1645 {
1646 if (flags & TEXT2_VERTICAL)
1647 y += text[i + 2];
1648 else
1649 x += text[i + 2];
1650 }
1651 for (j = 0; j < entry->size; j++)
1652 DO_GLYPH(((uint8 *) (entry->data)), j);
1653 }
1654 if (i + 2 < length)
1655 i += 3;
1656 else
1657 i += 2;
1658 length -= i;
1659 /* this will move pointer from start to first character after FE command */
1660 text = &(text[i]);
1661 i = 0;
1662 break;
1663
1664 default:
1665 DO_GLYPH(text, i);
1666 i++;
1667 break;
1668 }
1669 }
1670 if (g_ownbackstore)
1671 {
1672 if (boxcx > 1)
1673 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1674 boxy, boxcx, boxcy, boxx, boxy);
1675 else
1676 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1677 clipy, clipcx, clipcy, clipx, clipy);
1678 }
1679 }
1680
1681 void
1682 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1683 {
1684 Pixmap pix;
1685 XImage *image;
1686
1687 if (g_ownbackstore)
1688 {
1689 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1690 }
1691 else
1692 {
1693 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1694 XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1695 image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1696 XFreePixmap(g_display, pix);
1697 }
1698
1699 offset *= g_bpp / 8;
1700 cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
1701
1702 XDestroyImage(image);
1703 }
1704
1705 void
1706 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1707 {
1708 XImage *image;
1709 uint8 *data;
1710
1711 offset *= g_bpp / 8;
1712 data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
1713 if (data == NULL)
1714 return;
1715
1716 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1717 (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
1718
1719 if (g_ownbackstore)
1720 {
1721 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1722 XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1723 }
1724 else
1725 {
1726 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1727 }
1728
1729 XFree(image);
1730 }

  ViewVC Help
Powered by ViewVC 1.1.26