/[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 262 - (show annotations)
Mon Nov 18 15:37:20 2002 UTC (21 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 28088 byte(s)
Support for hiding WM decorations

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 (fullscreen)
302 {
303 width = WidthOfScreen(screen);
304 height = HeightOfScreen(screen);
305 }
306
307 /* make sure width is a multiple of 4 */
308 width = (width + 3) & ~3;
309
310 if (ownbackstore)
311 {
312 backstore =
313 XCreatePixmap(display, RootWindowOfScreen(screen), width, height, depth);
314
315 /* clear to prevent rubbish being exposed at startup */
316 XSetForeground(display, gc, BlackPixelOfScreen(screen));
317 XFillRectangle(display, backstore, gc, 0, 0, width, height);
318 }
319
320 mod_map = XGetModifierMapping(display);
321
322 if (enable_compose)
323 IM = XOpenIM(display, NULL, NULL, NULL);
324
325 xkeymap_init();
326 return True;
327 }
328
329 void
330 ui_deinit(void)
331 {
332 if (IM != NULL)
333 XCloseIM(IM);
334
335 XFreeModifiermap(mod_map);
336
337 if (ownbackstore)
338 XFreePixmap(display, backstore);
339
340 XFreeGC(display, gc);
341 XCloseDisplay(display);
342 display = NULL;
343 }
344
345 BOOL
346 ui_create_window(void)
347 {
348 XSetWindowAttributes attribs;
349 XClassHint *classhints;
350 XSizeHints *sizehints;
351 int wndwidth, wndheight;
352 long input_mask, ic_input_mask;
353 XEvent xevent;
354
355 wndwidth = fullscreen ? WidthOfScreen(screen) : width;
356 wndheight = fullscreen ? HeightOfScreen(screen) : height;
357
358 attribs.background_pixel = BlackPixelOfScreen(screen);
359 attribs.backing_store = ownbackstore ? NotUseful : Always;
360 attribs.override_redirect = fullscreen;
361
362 wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, wndwidth, wndheight,
363 0, CopyFromParent, InputOutput, CopyFromParent,
364 CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);
365
366 XStoreName(display, wnd, title);
367
368 if (hide_decorations)
369 mwm_hide_decorations();
370
371 classhints = XAllocClassHint();
372 if (classhints != NULL)
373 {
374 classhints->res_name = classhints->res_class = "rdesktop";
375 XSetClassHint(display, wnd, classhints);
376 XFree(classhints);
377 }
378
379 sizehints = XAllocSizeHints();
380 if (sizehints)
381 {
382 sizehints->flags = PMinSize | PMaxSize;
383 sizehints->min_width = sizehints->max_width = width;
384 sizehints->min_height = sizehints->max_height = height;
385 XSetWMNormalHints(display, wnd, sizehints);
386 XFree(sizehints);
387 }
388
389 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
390 VisibilityChangeMask | FocusChangeMask;
391
392 if (sendmotion)
393 input_mask |= PointerMotionMask;
394 if (ownbackstore)
395 input_mask |= ExposureMask;
396 if (fullscreen || grab_keyboard)
397 input_mask |= EnterWindowMask;
398 if (grab_keyboard)
399 input_mask |= LeaveWindowMask;
400
401 if (IM != NULL)
402 {
403 IC = XCreateIC(IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
404 XNClientWindow, wnd, XNFocusWindow, wnd, NULL);
405
406 if ((IC != NULL)
407 && (XGetICValues(IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
408 input_mask |= ic_input_mask;
409 }
410
411 XSelectInput(display, wnd, input_mask);
412 XMapWindow(display, wnd);
413
414 /* wait for VisibilityNotify */
415 do
416 {
417 XMaskEvent(display, VisibilityChangeMask, &xevent);
418 }
419 while (xevent.type != VisibilityNotify);
420
421 focused = False;
422 mouse_in_wnd = False;
423
424 return True;
425 }
426
427 void
428 ui_destroy_window(void)
429 {
430 if (IC != NULL)
431 XDestroyIC(IC);
432
433 XDestroyWindow(display, wnd);
434 }
435
436 void
437 xwin_toggle_fullscreen(void)
438 {
439 Pixmap contents = 0;
440
441 if (!ownbackstore)
442 {
443 /* need to save contents of window */
444 contents = XCreatePixmap(display, wnd, width, height, depth);
445 XCopyArea(display, wnd, contents, gc, 0, 0, width, height, 0, 0);
446 }
447
448 ui_destroy_window();
449 fullscreen = !fullscreen;
450 ui_create_window();
451
452 XDefineCursor(display, wnd, current_cursor);
453
454 if (!ownbackstore)
455 {
456 XCopyArea(display, contents, wnd, gc, 0, 0, width, height, 0, 0);
457 XFreePixmap(display, contents);
458 }
459 }
460
461 /* Process all events in Xlib queue */
462 static void
463 xwin_process_events(void)
464 {
465 XEvent xevent;
466 KeySym keysym;
467 uint16 button, flags;
468 uint32 ev_time;
469 key_translation tr;
470 char str[256];
471 Status status;
472 unsigned int state;
473 Window wdummy;
474 int dummy;
475
476 while (XPending(display) > 0)
477 {
478 XNextEvent(display, &xevent);
479
480 if ((IC != NULL) && (XFilterEvent(&xevent, None) == True))
481 {
482 DEBUG_KBD(("Filtering event\n"));
483 continue;
484 }
485
486 flags = 0;
487
488 switch (xevent.type)
489 {
490 case KeyPress:
491 if (IC != NULL)
492 /* Multi_key compatible version */
493 {
494 XmbLookupString(IC,
495 (XKeyPressedEvent *) &
496 xevent, str, sizeof(str), &keysym, &status);
497 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
498 {
499 error("XmbLookupString failed with status 0x%x\n",
500 status);
501 break;
502 }
503 }
504 else
505 {
506 /* Plain old XLookupString */
507 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
508 XLookupString((XKeyEvent *) & xevent,
509 str, sizeof(str), &keysym, NULL);
510 }
511
512 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
513 get_ksname(keysym)));
514
515 ev_time = time(NULL);
516 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
517 break;
518
519 tr = xkeymap_translate_key(keysym,
520 xevent.xkey.keycode, xevent.xkey.state);
521
522 if (tr.scancode == 0)
523 break;
524
525 ensure_remote_modifiers(ev_time, tr);
526
527 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
528 break;
529
530 case KeyRelease:
531 XLookupString((XKeyEvent *) & xevent, str,
532 sizeof(str), &keysym, NULL);
533
534 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
535 get_ksname(keysym)));
536
537 ev_time = time(NULL);
538 if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
539 break;
540
541 tr = xkeymap_translate_key(keysym,
542 xevent.xkey.keycode, xevent.xkey.state);
543
544 if (tr.scancode == 0)
545 break;
546
547 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
548 break;
549
550 case ButtonPress:
551 flags = MOUSE_FLAG_DOWN;
552 /* fall through */
553
554 case ButtonRelease:
555 button = xkeymap_translate_button(xevent.xbutton.button);
556 if (button == 0)
557 break;
558
559 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
560 flags | button, xevent.xbutton.x, xevent.xbutton.y);
561 break;
562
563 case MotionNotify:
564 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
565 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
566 break;
567
568 case FocusIn:
569 if (xevent.xfocus.mode == NotifyGrab)
570 break;
571 focused = True;
572 XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy,
573 &dummy, &dummy, &state);
574 reset_modifier_keys(state);
575 if (grab_keyboard && mouse_in_wnd)
576 XGrabKeyboard(display, wnd, True,
577 GrabModeAsync, GrabModeAsync, CurrentTime);
578 break;
579
580 case FocusOut:
581 if (xevent.xfocus.mode == NotifyUngrab)
582 break;
583 focused = False;
584 if (xevent.xfocus.mode == NotifyWhileGrabbed)
585 XUngrabKeyboard(display, CurrentTime);
586 break;
587
588 case EnterNotify:
589 /* we only register for this event when in fullscreen mode */
590 /* or grab_keyboard */
591 mouse_in_wnd = True;
592 if (fullscreen)
593 {
594 XSetInputFocus(display, wnd, RevertToPointerRoot,
595 CurrentTime);
596 break;
597 }
598 if (focused)
599 XGrabKeyboard(display, wnd, True,
600 GrabModeAsync, GrabModeAsync, CurrentTime);
601 break;
602
603 case LeaveNotify:
604 /* we only register for this event when grab_keyboard */
605 mouse_in_wnd = False;
606 XUngrabKeyboard(display, CurrentTime);
607 break;
608
609 case Expose:
610 XCopyArea(display, backstore, wnd, gc,
611 xevent.xexpose.x, xevent.xexpose.y,
612 xevent.xexpose.width,
613 xevent.xexpose.height,
614 xevent.xexpose.x, xevent.xexpose.y);
615 break;
616
617 case MappingNotify:
618 /* Refresh keyboard mapping if it has changed. This is important for
619 Xvnc, since it allocates keycodes dynamically */
620 if (xevent.xmapping.request == MappingKeyboard
621 || xevent.xmapping.request == MappingModifier)
622 XRefreshKeyboardMapping(&xevent.xmapping);
623
624 if (xevent.xmapping.request == MappingModifier)
625 {
626 XFreeModifiermap(mod_map);
627 mod_map = XGetModifierMapping(display);
628 }
629 break;
630
631 }
632 }
633 }
634
635 void
636 ui_select(int rdp_socket)
637 {
638 int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;
639 fd_set rfds;
640
641 FD_ZERO(&rfds);
642
643 while (True)
644 {
645 /* Process any events already waiting */
646 xwin_process_events();
647
648 FD_ZERO(&rfds);
649 FD_SET(rdp_socket, &rfds);
650 FD_SET(x_socket, &rfds);
651
652 switch (select(n, &rfds, NULL, NULL, NULL))
653 {
654 case -1:
655 error("select: %s\n", strerror(errno));
656
657 case 0:
658 continue;
659 }
660
661 if (FD_ISSET(rdp_socket, &rfds))
662 return;
663 }
664 }
665
666 void
667 ui_move_pointer(int x, int y)
668 {
669 XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);
670 }
671
672 HBITMAP
673 ui_create_bitmap(int width, int height, uint8 * data)
674 {
675 XImage *image;
676 Pixmap bitmap;
677 uint8 *tdata;
678
679 tdata = translate_image(width, height, data);
680 bitmap = XCreatePixmap(display, wnd, width, height, depth);
681 image = XCreateImage(display, visual, depth, ZPixmap, 0,
682 (char *) tdata, width, height, 8, 0);
683
684 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
685
686 XFree(image);
687 xfree(tdata);
688 return (HBITMAP) bitmap;
689 }
690
691 void
692 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
693 {
694 XImage *image;
695 uint8 *tdata;
696
697 tdata = translate_image(width, height, data);
698 image = XCreateImage(display, visual, depth, ZPixmap, 0,
699 (char *) tdata, width, height, 8, 0);
700
701 if (ownbackstore)
702 {
703 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
704 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
705 }
706 else
707 {
708 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
709 }
710
711 XFree(image);
712 xfree(tdata);
713 }
714
715 void
716 ui_destroy_bitmap(HBITMAP bmp)
717 {
718 XFreePixmap(display, (Pixmap) bmp);
719 }
720
721 HGLYPH
722 ui_create_glyph(int width, int height, uint8 * data)
723 {
724 XImage *image;
725 Pixmap bitmap;
726 int scanline;
727 GC gc;
728
729 scanline = (width + 7) / 8;
730
731 bitmap = XCreatePixmap(display, wnd, width, height, 1);
732 gc = XCreateGC(display, bitmap, 0, NULL);
733
734 image = XCreateImage(display, visual, 1, ZPixmap, 0, (char *) data,
735 width, height, 8, scanline);
736 image->byte_order = MSBFirst;
737 image->bitmap_bit_order = MSBFirst;
738 XInitImage(image);
739
740 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
741
742 XFree(image);
743 XFreeGC(display, gc);
744 return (HGLYPH) bitmap;
745 }
746
747 void
748 ui_destroy_glyph(HGLYPH glyph)
749 {
750 XFreePixmap(display, (Pixmap) glyph);
751 }
752
753 HCURSOR
754 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
755 uint8 * andmask, uint8 * xormask)
756 {
757 HGLYPH maskglyph, cursorglyph;
758 XColor bg, fg;
759 Cursor xcursor;
760 uint8 *cursor, *pcursor;
761 uint8 *mask, *pmask;
762 uint8 nextbit;
763 int scanline, offset;
764 int i, j;
765
766 scanline = (width + 7) / 8;
767 offset = scanline * height;
768
769 cursor = xmalloc(offset);
770 memset(cursor, 0, offset);
771
772 mask = xmalloc(offset);
773 memset(mask, 0, offset);
774
775 /* approximate AND and XOR masks with a monochrome X pointer */
776 for (i = 0; i < height; i++)
777 {
778 offset -= scanline;
779 pcursor = &cursor[offset];
780 pmask = &mask[offset];
781
782 for (j = 0; j < scanline; j++)
783 {
784 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
785 {
786 if (xormask[0] || xormask[1] || xormask[2])
787 {
788 *pcursor |= (~(*andmask) & nextbit);
789 *pmask |= nextbit;
790 }
791 else
792 {
793 *pcursor |= ((*andmask) & nextbit);
794 *pmask |= (~(*andmask) & nextbit);
795 }
796
797 xormask += 3;
798 }
799
800 andmask++;
801 pcursor++;
802 pmask++;
803 }
804 }
805
806 fg.red = fg.blue = fg.green = 0xffff;
807 bg.red = bg.blue = bg.green = 0x0000;
808 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
809
810 cursorglyph = ui_create_glyph(width, height, cursor);
811 maskglyph = ui_create_glyph(width, height, mask);
812
813 xcursor =
814 XCreatePixmapCursor(display, (Pixmap) cursorglyph,
815 (Pixmap) maskglyph, &fg, &bg, x, y);
816
817 ui_destroy_glyph(maskglyph);
818 ui_destroy_glyph(cursorglyph);
819 xfree(mask);
820 xfree(cursor);
821 return (HCURSOR) xcursor;
822 }
823
824 void
825 ui_set_cursor(HCURSOR cursor)
826 {
827 current_cursor = (Cursor) cursor;
828 XDefineCursor(display, wnd, current_cursor);
829 }
830
831 void
832 ui_destroy_cursor(HCURSOR cursor)
833 {
834 XFreeCursor(display, (Cursor) cursor);
835 }
836
837 #define MAKE_XCOLOR(xc,c) \
838 (xc)->red = ((c)->red << 8) | (c)->red; \
839 (xc)->green = ((c)->green << 8) | (c)->green; \
840 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
841 (xc)->flags = DoRed | DoGreen | DoBlue;
842
843 HCOLOURMAP
844 ui_create_colourmap(COLOURMAP * colours)
845 {
846 COLOURENTRY *entry;
847 int i, ncolours = colours->ncolours;
848 uint32 *map = xmalloc(sizeof(*colmap) * ncolours);
849 XColor xentry;
850 XColor xc_cache[256];
851 uint32 colour;
852 int colLookup = 256;
853 for (i = 0; i < ncolours; i++)
854 {
855 entry = &colours->colours[i];
856 MAKE_XCOLOR(&xentry, entry);
857
858 if (XAllocColor(display, xcolmap, &xentry) == 0)
859 {
860 /* Allocation failed, find closest match. */
861 int j = 256;
862 int nMinDist = 3 * 256 * 256;
863 long nDist = nMinDist;
864
865 /* only get the colors once */
866 while (colLookup--)
867 {
868 xc_cache[colLookup].pixel = colLookup;
869 xc_cache[colLookup].red = xc_cache[colLookup].green =
870 xc_cache[colLookup].blue = 0;
871 xc_cache[colLookup].flags = 0;
872 XQueryColor(display,
873 DefaultColormap(display, DefaultScreen(display)),
874 &xc_cache[colLookup]);
875 }
876 colLookup = 0;
877
878 /* approximate the pixel */
879 while (j--)
880 {
881 if (xc_cache[j].flags)
882 {
883 nDist = ((long) (xc_cache[j].red >> 8) -
884 (long) (xentry.red >> 8)) *
885 ((long) (xc_cache[j].red >> 8) -
886 (long) (xentry.red >> 8)) +
887 ((long) (xc_cache[j].green >> 8) -
888 (long) (xentry.green >> 8)) *
889 ((long) (xc_cache[j].green >> 8) -
890 (long) (xentry.green >> 8)) +
891 ((long) (xc_cache[j].blue >> 8) -
892 (long) (xentry.blue >> 8)) *
893 ((long) (xc_cache[j].blue >> 8) -
894 (long) (xentry.blue >> 8));
895 }
896 if (nDist < nMinDist)
897 {
898 nMinDist = nDist;
899 xentry.pixel = j;
900 }
901 }
902 }
903 colour = xentry.pixel;
904
905 /* update our cache */
906 if (xentry.pixel < 256)
907 {
908 xc_cache[xentry.pixel].red = xentry.red;
909 xc_cache[xentry.pixel].green = xentry.green;
910 xc_cache[xentry.pixel].blue = xentry.blue;
911
912 }
913
914
915 /* byte swap here to make translate_image faster */
916 map[i] = translate_colour(colour);
917 }
918
919 return map;
920 }
921
922 void
923 ui_destroy_colourmap(HCOLOURMAP map)
924 {
925 xfree(map);
926 }
927
928 void
929 ui_set_colourmap(HCOLOURMAP map)
930 {
931 colmap = map;
932 }
933
934 void
935 ui_set_clip(int x, int y, int cx, int cy)
936 {
937 XRectangle rect;
938
939 rect.x = x;
940 rect.y = y;
941 rect.width = cx;
942 rect.height = cy;
943 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
944 }
945
946 void
947 ui_reset_clip(void)
948 {
949 XRectangle rect;
950
951 rect.x = 0;
952 rect.y = 0;
953 rect.width = width;
954 rect.height = height;
955 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
956 }
957
958 void
959 ui_bell(void)
960 {
961 XBell(display, 0);
962 }
963
964 void
965 ui_destblt(uint8 opcode,
966 /* dest */ int x, int y, int cx, int cy)
967 {
968 SET_FUNCTION(opcode);
969 FILL_RECTANGLE(x, y, cx, cy);
970 RESET_FUNCTION(opcode);
971 }
972
973 void
974 ui_patblt(uint8 opcode,
975 /* dest */ int x, int y, int cx, int cy,
976 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
977 {
978 Pixmap fill;
979 uint8 i, ipattern[8];
980
981 SET_FUNCTION(opcode);
982
983 switch (brush->style)
984 {
985 case 0: /* Solid */
986 SET_FOREGROUND(fgcolour);
987 FILL_RECTANGLE(x, y, cx, cy);
988 break;
989
990 case 3: /* Pattern */
991 for (i = 0; i != 8; i++)
992 ipattern[7 - i] = brush->pattern[i];
993 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
994
995 SET_FOREGROUND(bgcolour);
996 SET_BACKGROUND(fgcolour);
997 XSetFillStyle(display, gc, FillOpaqueStippled);
998 XSetStipple(display, gc, fill);
999 XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);
1000
1001 FILL_RECTANGLE(x, y, cx, cy);
1002
1003 XSetFillStyle(display, gc, FillSolid);
1004 XSetTSOrigin(display, gc, 0, 0);
1005 ui_destroy_glyph((HGLYPH) fill);
1006 break;
1007
1008 default:
1009 unimpl("brush %d\n", brush->style);
1010 }
1011
1012 RESET_FUNCTION(opcode);
1013 }
1014
1015 void
1016 ui_screenblt(uint8 opcode,
1017 /* dest */ int x, int y, int cx, int cy,
1018 /* src */ int srcx, int srcy)
1019 {
1020 SET_FUNCTION(opcode);
1021 XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);
1022 if (ownbackstore)
1023 XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx, cy, x, y);
1024 RESET_FUNCTION(opcode);
1025 }
1026
1027 void
1028 ui_memblt(uint8 opcode,
1029 /* dest */ int x, int y, int cx, int cy,
1030 /* src */ HBITMAP src, int srcx, int srcy)
1031 {
1032 SET_FUNCTION(opcode);
1033 XCopyArea(display, (Pixmap) src, wnd, gc, srcx, srcy, cx, cy, x, y);
1034 if (ownbackstore)
1035 XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy, cx, cy, x, y);
1036 RESET_FUNCTION(opcode);
1037 }
1038
1039 void
1040 ui_triblt(uint8 opcode,
1041 /* dest */ int x, int y, int cx, int cy,
1042 /* src */ HBITMAP src, int srcx, int srcy,
1043 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1044 {
1045 /* This is potentially difficult to do in general. Until someone
1046 comes up with a more efficient way of doing it I am using cases. */
1047
1048 switch (opcode)
1049 {
1050 case 0x69: /* PDSxxn */
1051 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1052 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1053 break;
1054
1055 case 0xb8: /* PSDPxax */
1056 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1057 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1058 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1059 break;
1060
1061 case 0xc0: /* PSa */
1062 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1063 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1064 break;
1065
1066 default:
1067 unimpl("triblt 0x%x\n", opcode);
1068 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1069 }
1070 }
1071
1072 void
1073 ui_line(uint8 opcode,
1074 /* dest */ int startx, int starty, int endx, int endy,
1075 /* pen */ PEN * pen)
1076 {
1077 SET_FUNCTION(opcode);
1078 SET_FOREGROUND(pen->colour);
1079 XDrawLine(display, wnd, gc, startx, starty, endx, endy);
1080 if (ownbackstore)
1081 XDrawLine(display, backstore, gc, startx, starty, endx, endy);
1082 RESET_FUNCTION(opcode);
1083 }
1084
1085 void
1086 ui_rect(
1087 /* dest */ int x, int y, int cx, int cy,
1088 /* brush */ int colour)
1089 {
1090 SET_FOREGROUND(colour);
1091 FILL_RECTANGLE(x, y, cx, cy);
1092 }
1093
1094 void
1095 ui_draw_glyph(int mixmode,
1096 /* dest */ int x, int y, int cx, int cy,
1097 /* src */ HGLYPH glyph, int srcx, int srcy,
1098 int bgcolour, int fgcolour)
1099 {
1100 SET_FOREGROUND(fgcolour);
1101 SET_BACKGROUND(bgcolour);
1102
1103 XSetFillStyle(display, gc,
1104 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1105 XSetStipple(display, gc, (Pixmap) glyph);
1106 XSetTSOrigin(display, gc, x, y);
1107
1108 FILL_RECTANGLE(x, y, cx, cy);
1109
1110 XSetFillStyle(display, gc, FillSolid);
1111 }
1112
1113 #define DO_GLYPH(ttext,idx) \
1114 {\
1115 glyph = cache_get_font (font, ttext[idx]);\
1116 if (!(flags & TEXT2_IMPLICIT_X))\
1117 {\
1118 xyoffset = ttext[++idx];\
1119 if ((xyoffset & 0x80))\
1120 {\
1121 if (flags & TEXT2_VERTICAL) \
1122 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1123 else\
1124 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1125 idx += 2;\
1126 }\
1127 else\
1128 {\
1129 if (flags & TEXT2_VERTICAL) \
1130 y += xyoffset;\
1131 else\
1132 x += xyoffset;\
1133 }\
1134 }\
1135 if (glyph != NULL)\
1136 {\
1137 ui_draw_glyph (mixmode, x + (short) glyph->offset,\
1138 y + (short) glyph->baseline,\
1139 glyph->width, glyph->height,\
1140 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1141 if (flags & TEXT2_IMPLICIT_X)\
1142 x += glyph->width;\
1143 }\
1144 }
1145
1146 void
1147 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1148 int clipx, int clipy, int clipcx, int clipcy,
1149 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1150 int fgcolour, uint8 * text, uint8 length)
1151 {
1152 FONTGLYPH *glyph;
1153 int i, j, xyoffset;
1154 DATABLOB *entry;
1155
1156 SET_FOREGROUND(bgcolour);
1157
1158 if (boxcx > 1)
1159 {
1160 FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);
1161 }
1162 else if (mixmode == MIX_OPAQUE)
1163 {
1164 FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);
1165 }
1166
1167 /* Paint text, character by character */
1168 for (i = 0; i < length;)
1169 {
1170 switch (text[i])
1171 {
1172 case 0xff:
1173 if (i + 2 < length)
1174 cache_put_text(text[i + 1], text, text[i + 2]);
1175 else
1176 {
1177 error("this shouldn't be happening\n");
1178 break;
1179 }
1180 /* this will move pointer from start to first character after FF command */
1181 length -= i + 3;
1182 text = &(text[i + 3]);
1183 i = 0;
1184 break;
1185
1186 case 0xfe:
1187 entry = cache_get_text(text[i + 1]);
1188 if (entry != NULL)
1189 {
1190 if ((((uint8 *) (entry->data))[1] ==
1191 0) && (!(flags & TEXT2_IMPLICIT_X)))
1192 {
1193 if (flags & TEXT2_VERTICAL)
1194 y += text[i + 2];
1195 else
1196 x += text[i + 2];
1197 }
1198 if (i + 2 < length)
1199 i += 3;
1200 else
1201 i += 2;
1202 length -= i;
1203 /* this will move pointer from start to first character after FE command */
1204 text = &(text[i]);
1205 i = 0;
1206 for (j = 0; j < entry->size; j++)
1207 DO_GLYPH(((uint8 *) (entry->data)), j);
1208 }
1209 break;
1210
1211 default:
1212 DO_GLYPH(text, i);
1213 i++;
1214 break;
1215 }
1216 }
1217
1218
1219 }
1220
1221 void
1222 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1223 {
1224 Pixmap pix;
1225 XImage *image;
1226
1227 if (ownbackstore)
1228 {
1229 image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1230 }
1231 else
1232 {
1233 pix = XCreatePixmap(display, wnd, cx, cy, depth);
1234 XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);
1235 image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1236 XFreePixmap(display, pix);
1237 }
1238
1239 offset *= bpp / 8;
1240 cache_put_desktop(offset, cx, cy, image->bytes_per_line, bpp / 8, (uint8 *) image->data);
1241
1242 XDestroyImage(image);
1243 }
1244
1245 void
1246 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1247 {
1248 XImage *image;
1249 uint8 *data;
1250
1251 offset *= bpp / 8;
1252 data = cache_get_desktop(offset, cx, cy, bpp / 8);
1253 if (data == NULL)
1254 return;
1255
1256 image = XCreateImage(display, visual, depth, ZPixmap, 0,
1257 (char *) data, cx, cy, BitmapPad(display), cx * bpp / 8);
1258
1259 if (ownbackstore)
1260 {
1261 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
1262 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
1263 }
1264 else
1265 {
1266 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
1267 }
1268
1269 XFree(image);
1270 }

  ViewVC Help
Powered by ViewVC 1.1.26