/[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 309 - (show annotations)
Tue Feb 4 05:32:13 2003 UTC (21 years, 3 months ago) by jsorg71
File MIME type: text/plain
File size: 31034 byte(s)
16bit

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

  ViewVC Help
Powered by ViewVC 1.1.26