/[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 415 - (show annotations)
Fri Jun 6 11:10:48 2003 UTC (20 years, 11 months ago) by forsberg
File MIME type: text/plain
File size: 41335 byte(s)
Listen for clipboard-related events and handle them.
Listen for IPC-related events and handle them.
Changes after running indent-all.sh

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

  ViewVC Help
Powered by ViewVC 1.1.26