/[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 300 - (show annotations)
Thu Jan 30 11:20:30 2003 UTC (21 years, 3 months ago) by matthewc
File MIME type: text/plain
File size: 30620 byte(s)
Fix a few compile warnings.

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 x, y, cx, cy;
319
320 if (get_current_workarea(&x, &y, &cx, &cy) == 0)
321 {
322 width = cx;
323 height = cy;
324 }
325 else
326 {
327 warning("Failed to get workarea: probably your window manager does not support extended hints\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 if (fullscreen && !focused)
611 XSetInputFocus(display, wnd, RevertToPointerRoot,
612 CurrentTime);
613 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
614 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
615 break;
616
617 case FocusIn:
618 if (xevent.xfocus.mode == NotifyGrab)
619 break;
620 focused = True;
621 XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy,
622 &dummy, &dummy, &state);
623 reset_modifier_keys(state);
624 if (grab_keyboard && mouse_in_wnd)
625 XGrabKeyboard(display, wnd, True,
626 GrabModeAsync, GrabModeAsync, CurrentTime);
627 break;
628
629 case FocusOut:
630 if (xevent.xfocus.mode == NotifyUngrab)
631 break;
632 focused = False;
633 if (xevent.xfocus.mode == NotifyWhileGrabbed)
634 XUngrabKeyboard(display, CurrentTime);
635 break;
636
637 case EnterNotify:
638 /* we only register for this event when in fullscreen mode */
639 /* or grab_keyboard */
640 mouse_in_wnd = True;
641 if (fullscreen)
642 {
643 XSetInputFocus(display, wnd, RevertToPointerRoot,
644 CurrentTime);
645 break;
646 }
647 if (focused)
648 XGrabKeyboard(display, wnd, True,
649 GrabModeAsync, GrabModeAsync, CurrentTime);
650 break;
651
652 case LeaveNotify:
653 /* we only register for this event when grab_keyboard */
654 mouse_in_wnd = False;
655 XUngrabKeyboard(display, CurrentTime);
656 break;
657
658 case Expose:
659 XCopyArea(display, backstore, wnd, gc,
660 xevent.xexpose.x, xevent.xexpose.y,
661 xevent.xexpose.width,
662 xevent.xexpose.height,
663 xevent.xexpose.x, xevent.xexpose.y);
664 break;
665
666 case MappingNotify:
667 /* Refresh keyboard mapping if it has changed. This is important for
668 Xvnc, since it allocates keycodes dynamically */
669 if (xevent.xmapping.request == MappingKeyboard
670 || xevent.xmapping.request == MappingModifier)
671 XRefreshKeyboardMapping(&xevent.xmapping);
672
673 if (xevent.xmapping.request == MappingModifier)
674 {
675 XFreeModifiermap(mod_map);
676 mod_map = XGetModifierMapping(display);
677 }
678 break;
679
680 }
681 }
682 /* Keep going */
683 return 1;
684 }
685
686 /* Returns 0 after user quit, 1 otherwise */
687 int
688 ui_select(int rdp_socket)
689 {
690 int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;
691 fd_set rfds;
692
693 FD_ZERO(&rfds);
694
695 while (True)
696 {
697 /* Process any events already waiting */
698 if (!xwin_process_events())
699 /* User quit */
700 return 0;
701
702 FD_ZERO(&rfds);
703 FD_SET(rdp_socket, &rfds);
704 FD_SET(x_socket, &rfds);
705
706 switch (select(n, &rfds, NULL, NULL, NULL))
707 {
708 case -1:
709 error("select: %s\n", strerror(errno));
710
711 case 0:
712 continue;
713 }
714
715 if (FD_ISSET(rdp_socket, &rfds))
716 return 1;
717 }
718 }
719
720 void
721 ui_move_pointer(int x, int y)
722 {
723 XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);
724 }
725
726 HBITMAP
727 ui_create_bitmap(int width, int height, uint8 * data)
728 {
729 XImage *image;
730 Pixmap bitmap;
731 uint8 *tdata;
732
733 tdata = (owncolmap ? data : translate_image(width, height, data));
734 bitmap = XCreatePixmap(display, wnd, width, height, depth);
735 image = XCreateImage(display, visual, depth, ZPixmap, 0,
736 (char *) tdata, width, height, 8, 0);
737
738 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
739
740 XFree(image);
741 if (!owncolmap)
742 xfree(tdata);
743 return (HBITMAP) bitmap;
744 }
745
746 void
747 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
748 {
749 XImage *image;
750 uint8 *tdata;
751
752 tdata = (owncolmap ? data : translate_image(width, height, data));
753 image = XCreateImage(display, visual, depth, ZPixmap, 0,
754 (char *) tdata, width, height, 8, 0);
755
756 if (ownbackstore)
757 {
758 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
759 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
760 }
761 else
762 {
763 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
764 }
765
766 XFree(image);
767 if (!owncolmap)
768 xfree(tdata);
769 }
770
771 void
772 ui_destroy_bitmap(HBITMAP bmp)
773 {
774 XFreePixmap(display, (Pixmap) bmp);
775 }
776
777 HGLYPH
778 ui_create_glyph(int width, int height, uint8 * data)
779 {
780 XImage *image;
781 Pixmap bitmap;
782 int scanline;
783 GC gc;
784
785 scanline = (width + 7) / 8;
786
787 bitmap = XCreatePixmap(display, wnd, width, height, 1);
788 gc = XCreateGC(display, bitmap, 0, NULL);
789
790 image = XCreateImage(display, visual, 1, ZPixmap, 0, (char *) data,
791 width, height, 8, scanline);
792 image->byte_order = MSBFirst;
793 image->bitmap_bit_order = MSBFirst;
794 XInitImage(image);
795
796 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
797
798 XFree(image);
799 XFreeGC(display, gc);
800 return (HGLYPH) bitmap;
801 }
802
803 void
804 ui_destroy_glyph(HGLYPH glyph)
805 {
806 XFreePixmap(display, (Pixmap) glyph);
807 }
808
809 HCURSOR
810 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
811 uint8 * andmask, uint8 * xormask)
812 {
813 HGLYPH maskglyph, cursorglyph;
814 XColor bg, fg;
815 Cursor xcursor;
816 uint8 *cursor, *pcursor;
817 uint8 *mask, *pmask;
818 uint8 nextbit;
819 int scanline, offset;
820 int i, j;
821
822 scanline = (width + 7) / 8;
823 offset = scanline * height;
824
825 cursor = xmalloc(offset);
826 memset(cursor, 0, offset);
827
828 mask = xmalloc(offset);
829 memset(mask, 0, offset);
830
831 /* approximate AND and XOR masks with a monochrome X pointer */
832 for (i = 0; i < height; i++)
833 {
834 offset -= scanline;
835 pcursor = &cursor[offset];
836 pmask = &mask[offset];
837
838 for (j = 0; j < scanline; j++)
839 {
840 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
841 {
842 if (xormask[0] || xormask[1] || xormask[2])
843 {
844 *pcursor |= (~(*andmask) & nextbit);
845 *pmask |= nextbit;
846 }
847 else
848 {
849 *pcursor |= ((*andmask) & nextbit);
850 *pmask |= (~(*andmask) & nextbit);
851 }
852
853 xormask += 3;
854 }
855
856 andmask++;
857 pcursor++;
858 pmask++;
859 }
860 }
861
862 fg.red = fg.blue = fg.green = 0xffff;
863 bg.red = bg.blue = bg.green = 0x0000;
864 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
865
866 cursorglyph = ui_create_glyph(width, height, cursor);
867 maskglyph = ui_create_glyph(width, height, mask);
868
869 xcursor =
870 XCreatePixmapCursor(display, (Pixmap) cursorglyph,
871 (Pixmap) maskglyph, &fg, &bg, x, y);
872
873 ui_destroy_glyph(maskglyph);
874 ui_destroy_glyph(cursorglyph);
875 xfree(mask);
876 xfree(cursor);
877 return (HCURSOR) xcursor;
878 }
879
880 void
881 ui_set_cursor(HCURSOR cursor)
882 {
883 current_cursor = (Cursor) cursor;
884 XDefineCursor(display, wnd, current_cursor);
885 }
886
887 void
888 ui_destroy_cursor(HCURSOR cursor)
889 {
890 XFreeCursor(display, (Cursor) cursor);
891 }
892
893 #define MAKE_XCOLOR(xc,c) \
894 (xc)->red = ((c)->red << 8) | (c)->red; \
895 (xc)->green = ((c)->green << 8) | (c)->green; \
896 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
897 (xc)->flags = DoRed | DoGreen | DoBlue;
898
899
900 HCOLOURMAP
901 ui_create_colourmap(COLOURMAP * colours)
902 {
903 COLOURENTRY *entry;
904 int i, ncolours = colours->ncolours;
905 if (!owncolmap)
906 {
907 uint32 *map = xmalloc(sizeof(*colmap) * ncolours);
908 XColor xentry;
909 XColor xc_cache[256];
910 uint32 colour;
911 int colLookup = 256;
912 for (i = 0; i < ncolours; i++)
913 {
914 entry = &colours->colours[i];
915 MAKE_XCOLOR(&xentry, entry);
916
917 if (XAllocColor(display, xcolmap, &xentry) == 0)
918 {
919 /* Allocation failed, find closest match. */
920 int j = 256;
921 int nMinDist = 3 * 256 * 256;
922 long nDist = nMinDist;
923
924 /* only get the colors once */
925 while (colLookup--)
926 {
927 xc_cache[colLookup].pixel = colLookup;
928 xc_cache[colLookup].red = xc_cache[colLookup].green =
929 xc_cache[colLookup].blue = 0;
930 xc_cache[colLookup].flags = 0;
931 XQueryColor(display,
932 DefaultColormap(display,
933 DefaultScreen(display)),
934 &xc_cache[colLookup]);
935 }
936 colLookup = 0;
937
938 /* approximate the pixel */
939 while (j--)
940 {
941 if (xc_cache[j].flags)
942 {
943 nDist = ((long) (xc_cache[j].red >> 8) -
944 (long) (xentry.red >> 8)) *
945 ((long) (xc_cache[j].red >> 8) -
946 (long) (xentry.red >> 8)) +
947 ((long) (xc_cache[j].green >> 8) -
948 (long) (xentry.green >> 8)) *
949 ((long) (xc_cache[j].green >> 8) -
950 (long) (xentry.green >> 8)) +
951 ((long) (xc_cache[j].blue >> 8) -
952 (long) (xentry.blue >> 8)) *
953 ((long) (xc_cache[j].blue >> 8) -
954 (long) (xentry.blue >> 8));
955 }
956 if (nDist < nMinDist)
957 {
958 nMinDist = nDist;
959 xentry.pixel = j;
960 }
961 }
962 }
963 colour = xentry.pixel;
964
965 /* update our cache */
966 if (xentry.pixel < 256)
967 {
968 xc_cache[xentry.pixel].red = xentry.red;
969 xc_cache[xentry.pixel].green = xentry.green;
970 xc_cache[xentry.pixel].blue = xentry.blue;
971
972 }
973
974
975 /* byte swap here to make translate_image faster */
976 map[i] = translate_colour(colour);
977 }
978 return map;
979 }
980 else
981 {
982 XColor *xcolours, *xentry;
983 Colormap map;
984
985 xcolours = xmalloc(sizeof(XColor) * ncolours);
986 for (i = 0; i < ncolours; i++)
987 {
988 entry = &colours->colours[i];
989 xentry = &xcolours[i];
990 xentry->pixel = i;
991 MAKE_XCOLOR(xentry, entry);
992 }
993
994 map = XCreateColormap(display, wnd, visual, AllocAll);
995 XStoreColors(display, map, xcolours, ncolours);
996
997 xfree(xcolours);
998 return (HCOLOURMAP) map;
999 }
1000 }
1001
1002 void
1003 ui_destroy_colourmap(HCOLOURMAP map)
1004 {
1005 if (!owncolmap)
1006 xfree(map);
1007 else
1008 XFreeColormap(display, (Colormap) map);
1009 }
1010
1011 void
1012 ui_set_colourmap(HCOLOURMAP map)
1013 {
1014 if (!owncolmap)
1015 colmap = map;
1016 else
1017 XSetWindowColormap(display, wnd, (Colormap) map);
1018 }
1019
1020 void
1021 ui_set_clip(int x, int y, int cx, int cy)
1022 {
1023 XRectangle rect;
1024
1025 rect.x = x;
1026 rect.y = y;
1027 rect.width = cx;
1028 rect.height = cy;
1029 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
1030 }
1031
1032 void
1033 ui_reset_clip(void)
1034 {
1035 XRectangle rect;
1036
1037 rect.x = 0;
1038 rect.y = 0;
1039 rect.width = width;
1040 rect.height = height;
1041 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
1042 }
1043
1044 void
1045 ui_bell(void)
1046 {
1047 XBell(display, 0);
1048 }
1049
1050 void
1051 ui_destblt(uint8 opcode,
1052 /* dest */ int x, int y, int cx, int cy)
1053 {
1054 SET_FUNCTION(opcode);
1055 FILL_RECTANGLE(x, y, cx, cy);
1056 RESET_FUNCTION(opcode);
1057 }
1058
1059 void
1060 ui_patblt(uint8 opcode,
1061 /* dest */ int x, int y, int cx, int cy,
1062 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1063 {
1064 Pixmap fill;
1065 uint8 i, ipattern[8];
1066
1067 SET_FUNCTION(opcode);
1068
1069 switch (brush->style)
1070 {
1071 case 0: /* Solid */
1072 SET_FOREGROUND(fgcolour);
1073 FILL_RECTANGLE(x, y, cx, cy);
1074 break;
1075
1076 case 3: /* Pattern */
1077 for (i = 0; i != 8; i++)
1078 ipattern[7 - i] = brush->pattern[i];
1079 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1080
1081 SET_FOREGROUND(bgcolour);
1082 SET_BACKGROUND(fgcolour);
1083 XSetFillStyle(display, gc, FillOpaqueStippled);
1084 XSetStipple(display, gc, fill);
1085 XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);
1086
1087 FILL_RECTANGLE(x, y, cx, cy);
1088
1089 XSetFillStyle(display, gc, FillSolid);
1090 XSetTSOrigin(display, gc, 0, 0);
1091 ui_destroy_glyph((HGLYPH) fill);
1092 break;
1093
1094 default:
1095 unimpl("brush %d\n", brush->style);
1096 }
1097
1098 RESET_FUNCTION(opcode);
1099 }
1100
1101 void
1102 ui_screenblt(uint8 opcode,
1103 /* dest */ int x, int y, int cx, int cy,
1104 /* src */ int srcx, int srcy)
1105 {
1106 SET_FUNCTION(opcode);
1107 XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);
1108 if (ownbackstore)
1109 XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx, cy, x, y);
1110 RESET_FUNCTION(opcode);
1111 }
1112
1113 void
1114 ui_memblt(uint8 opcode,
1115 /* dest */ int x, int y, int cx, int cy,
1116 /* src */ HBITMAP src, int srcx, int srcy)
1117 {
1118 SET_FUNCTION(opcode);
1119 XCopyArea(display, (Pixmap) src, wnd, gc, srcx, srcy, cx, cy, x, y);
1120 if (ownbackstore)
1121 XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy, cx, cy, x, y);
1122 RESET_FUNCTION(opcode);
1123 }
1124
1125 void
1126 ui_triblt(uint8 opcode,
1127 /* dest */ int x, int y, int cx, int cy,
1128 /* src */ HBITMAP src, int srcx, int srcy,
1129 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1130 {
1131 /* This is potentially difficult to do in general. Until someone
1132 comes up with a more efficient way of doing it I am using cases. */
1133
1134 switch (opcode)
1135 {
1136 case 0x69: /* PDSxxn */
1137 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1138 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1139 break;
1140
1141 case 0xb8: /* PSDPxax */
1142 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1143 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1144 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1145 break;
1146
1147 case 0xc0: /* PSa */
1148 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1149 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1150 break;
1151
1152 default:
1153 unimpl("triblt 0x%x\n", opcode);
1154 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1155 }
1156 }
1157
1158 void
1159 ui_line(uint8 opcode,
1160 /* dest */ int startx, int starty, int endx, int endy,
1161 /* pen */ PEN * pen)
1162 {
1163 SET_FUNCTION(opcode);
1164 SET_FOREGROUND(pen->colour);
1165 XDrawLine(display, wnd, gc, startx, starty, endx, endy);
1166 if (ownbackstore)
1167 XDrawLine(display, backstore, gc, startx, starty, endx, endy);
1168 RESET_FUNCTION(opcode);
1169 }
1170
1171 void
1172 ui_rect(
1173 /* dest */ int x, int y, int cx, int cy,
1174 /* brush */ int colour)
1175 {
1176 SET_FOREGROUND(colour);
1177 FILL_RECTANGLE(x, y, cx, cy);
1178 }
1179
1180 /* warning, this function only draws on wnd or backstore, not both */
1181 void
1182 ui_draw_glyph(int mixmode,
1183 /* dest */ int x, int y, int cx, int cy,
1184 /* src */ HGLYPH glyph, int srcx, int srcy,
1185 int bgcolour, int fgcolour)
1186 {
1187 SET_FOREGROUND(fgcolour);
1188 SET_BACKGROUND(bgcolour);
1189
1190 XSetFillStyle(display, gc,
1191 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1192 XSetStipple(display, gc, (Pixmap) glyph);
1193 XSetTSOrigin(display, gc, x, y);
1194
1195 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1196
1197 XSetFillStyle(display, gc, FillSolid);
1198 }
1199
1200 #define DO_GLYPH(ttext,idx) \
1201 {\
1202 glyph = cache_get_font (font, ttext[idx]);\
1203 if (!(flags & TEXT2_IMPLICIT_X))\
1204 {\
1205 xyoffset = ttext[++idx];\
1206 if ((xyoffset & 0x80))\
1207 {\
1208 if (flags & TEXT2_VERTICAL) \
1209 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1210 else\
1211 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1212 idx += 2;\
1213 }\
1214 else\
1215 {\
1216 if (flags & TEXT2_VERTICAL) \
1217 y += xyoffset;\
1218 else\
1219 x += xyoffset;\
1220 }\
1221 }\
1222 if (glyph != NULL)\
1223 {\
1224 ui_draw_glyph (mixmode, x + glyph->offset,\
1225 y + glyph->baseline,\
1226 glyph->width, glyph->height,\
1227 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1228 if (flags & TEXT2_IMPLICIT_X)\
1229 x += glyph->width;\
1230 }\
1231 }
1232
1233 void
1234 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1235 int clipx, int clipy, int clipcx, int clipcy,
1236 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1237 int fgcolour, uint8 * text, uint8 length)
1238 {
1239 FONTGLYPH *glyph;
1240 int i, j, xyoffset;
1241 DATABLOB *entry;
1242
1243 SET_FOREGROUND(bgcolour);
1244
1245 if (boxcx > 1)
1246 {
1247 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1248 }
1249 else if (mixmode == MIX_OPAQUE)
1250 {
1251 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1252 }
1253
1254 /* Paint text, character by character */
1255 for (i = 0; i < length;)
1256 {
1257 switch (text[i])
1258 {
1259 case 0xff:
1260 if (i + 2 < length)
1261 cache_put_text(text[i + 1], text, text[i + 2]);
1262 else
1263 {
1264 error("this shouldn't be happening\n");
1265 exit(1);
1266 }
1267 /* this will move pointer from start to first character after FF command */
1268 length -= i + 3;
1269 text = &(text[i + 3]);
1270 i = 0;
1271 break;
1272
1273 case 0xfe:
1274 entry = cache_get_text(text[i + 1]);
1275 if (entry != NULL)
1276 {
1277 if ((((uint8 *) (entry->data))[1] ==
1278 0) && (!(flags & TEXT2_IMPLICIT_X)))
1279 {
1280 if (flags & TEXT2_VERTICAL)
1281 y += text[i + 2];
1282 else
1283 x += text[i + 2];
1284 }
1285 for (j = 0; j < entry->size; j++)
1286 DO_GLYPH(((uint8 *) (entry->data)), j);
1287 }
1288 if (i + 2 < length)
1289 i += 3;
1290 else
1291 i += 2;
1292 length -= i;
1293 /* this will move pointer from start to first character after FE command */
1294 text = &(text[i]);
1295 i = 0;
1296 break;
1297
1298 default:
1299 DO_GLYPH(text, i);
1300 i++;
1301 break;
1302 }
1303 }
1304 if (ownbackstore)
1305 {
1306 if (boxcx > 1)
1307 XCopyArea(display, backstore, wnd, gc, boxx,
1308 boxy, boxcx, boxcy, boxx, boxy);
1309 else
1310 XCopyArea(display, backstore, wnd, gc, clipx,
1311 clipy, clipcx, clipcy, clipx, clipy);
1312 }
1313 }
1314
1315 void
1316 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1317 {
1318 Pixmap pix;
1319 XImage *image;
1320
1321 if (ownbackstore)
1322 {
1323 image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1324 }
1325 else
1326 {
1327 pix = XCreatePixmap(display, wnd, cx, cy, depth);
1328 XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);
1329 image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1330 XFreePixmap(display, pix);
1331 }
1332
1333 offset *= bpp / 8;
1334 cache_put_desktop(offset, cx, cy, image->bytes_per_line, bpp / 8, (uint8 *) image->data);
1335
1336 XDestroyImage(image);
1337 }
1338
1339 void
1340 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1341 {
1342 XImage *image;
1343 uint8 *data;
1344
1345 offset *= bpp / 8;
1346 data = cache_get_desktop(offset, cx, cy, bpp / 8);
1347 if (data == NULL)
1348 return;
1349
1350 image = XCreateImage(display, visual, depth, ZPixmap, 0,
1351 (char *) data, cx, cy, BitmapPad(display), cx * bpp / 8);
1352
1353 if (ownbackstore)
1354 {
1355 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
1356 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
1357 }
1358 else
1359 {
1360 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
1361 }
1362
1363 XFree(image);
1364 }

  ViewVC Help
Powered by ViewVC 1.1.26