/[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 281 - (show annotations)
Mon Dec 2 22:57:47 2002 UTC (21 years, 5 months ago) by jsorg71
File MIME type: text/plain
File size: 30499 byte(s)
minor draw_text optimize

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

  ViewVC Help
Powered by ViewVC 1.1.26