/[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 103 - (show annotations)
Thu Aug 29 14:18:24 2002 UTC (21 years, 8 months ago) by matthewc
File MIME type: text/plain
File size: 28102 byte(s)
Make sure width is a multiple of 4 (previous version in ui_create_window
was getting done too late, after connection).

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

  ViewVC Help
Powered by ViewVC 1.1.26