/[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 311 - (show annotations)
Wed Feb 5 14:16:33 2003 UTC (21 years, 3 months ago) by jsorg71
File MIME type: text/plain
File size: 32322 byte(s)
support for > 16 bit clients with 16 bit server

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

  ViewVC Help
Powered by ViewVC 1.1.26