/[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 274 - (show annotations)
Tue Nov 19 14:45:13 2002 UTC (21 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 28452 byte(s)
Small indent fix.

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

  ViewVC Help
Powered by ViewVC 1.1.26