/[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 278 - (show annotations)
Mon Nov 25 18:23:44 2002 UTC (21 years, 5 months ago) by jsorg71
File MIME type: text/plain
File size: 29473 byte(s)
ui_draw_text optimization from unified patches

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

  ViewVC Help
Powered by ViewVC 1.1.26