/[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 297 - (show annotations)
Tue Jan 28 12:27:28 2003 UTC (21 years, 3 months ago) by matthewc
File MIME type: text/plain
File size: 30600 byte(s)
Add a warning function, change some errors to warnings, improve a
couple of error messages (not sure whether scewed was meant to be skewed
or screwed :))

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

  ViewVC Help
Powered by ViewVC 1.1.26