/[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 273 - (show annotations)
Tue Nov 19 14:22:47 2002 UTC (21 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 28449 byte(s)
Made -g workarea a bit less fatal when the WM does not support _NET_WORKAREA:
defaulting to 800x600.

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

  ViewVC Help
Powered by ViewVC 1.1.26