/[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 119 - (show annotations)
Thu Sep 12 09:38:31 2002 UTC (21 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 28095 byte(s)
Fixes Excel scroll-of-death problem: earlier select-loop failed to call xwin_process_events
when the queue was non-zero but the X11 socket was empty.

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 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 /* Process all events in Xlib queue */
521 static void
522 xwin_process_events()
523 {
524 XEvent xevent;
525
526 KeySym keysym;
527 uint16 button, flags;
528 uint32 ev_time;
529 key_translation tr;
530 char *ksname = NULL;
531 char str[256];
532 Status status;
533
534 while (XCheckMaskEvent(display, ~0, &xevent))
535 {
536 if (enable_compose && (XFilterEvent(&xevent, None) == True))
537 {
538 DEBUG_KBD(("Filtering event\n"));
539 continue;
540 }
541
542 ev_time = time(NULL);
543 flags = 0;
544
545 switch (xevent.type)
546 {
547 case KeyPress:
548 if (IC != NULL)
549 /* Multi_key compatible version */
550 {
551 XmbLookupString(IC,
552 (XKeyPressedEvent *) &
553 xevent, str, sizeof(str), &keysym, &status);
554 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
555 {
556 error("XmbLookupString failed with status 0x%x\n",
557 status);
558 break;
559 }
560 }
561 else
562 {
563 /* Plain old XLookupString */
564 DEBUG_KBD(("No input context, using XLookupString\n"));
565 XLookupString((XKeyEvent *) & xevent,
566 str, sizeof(str), &keysym, NULL);
567 }
568
569 ksname = get_ksname(keysym);
570 DEBUG_KBD(("\nKeyPress for (keysym 0x%lx, %s)\n", keysym, ksname));
571
572 if (handle_special_keys(keysym, ev_time, True))
573 break;
574
575 tr = xkeymap_translate_key(keysym,
576 xevent.xkey.keycode, xevent.xkey.state);
577
578 if (tr.scancode == 0)
579 break;
580
581 ensure_remote_modifiers(ev_time, tr);
582
583 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
584 break;
585 case KeyRelease:
586 XLookupString((XKeyEvent *) & xevent, str,
587 sizeof(str), &keysym, NULL);
588
589 ksname = get_ksname(keysym);
590 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
591 ksname));
592
593 if (handle_special_keys(keysym, ev_time, False))
594 break;
595
596 tr = xkeymap_translate_key(keysym,
597 xevent.xkey.keycode, xevent.xkey.state);
598
599 if (tr.scancode == 0)
600 break;
601
602 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
603 break;
604
605 case ButtonPress:
606 flags = MOUSE_FLAG_DOWN;
607 /* fall through */
608
609 case ButtonRelease:
610 button = xkeymap_translate_button(xevent.xbutton.button);
611 if (button == 0)
612 break;
613
614 rdp_send_input(ev_time, RDP_INPUT_MOUSE,
615 flags | button, xevent.xbutton.x, xevent.xbutton.y);
616 break;
617
618 case MotionNotify:
619 rdp_send_input(ev_time, RDP_INPUT_MOUSE,
620 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
621 break;
622
623 case FocusIn:
624 /* fall through */
625 case EnterNotify:
626 if (grab_keyboard)
627 XGrabKeyboard(display, wnd, True,
628 GrabModeAsync, GrabModeAsync, CurrentTime);
629 break;
630
631 case FocusOut:
632 reset_keys();
633 /* fall through */
634 case LeaveNotify:
635 if (grab_keyboard)
636 XUngrabKeyboard(display, CurrentTime);
637 break;
638
639 case Expose:
640 XCopyArea(display, backstore, wnd, gc,
641 xevent.xexpose.x, xevent.xexpose.y,
642 xevent.xexpose.width,
643 xevent.xexpose.height,
644 xevent.xexpose.x, xevent.xexpose.y);
645 break;
646
647 case MappingNotify:
648 /* Refresh keyboard mapping if it has changed. This is important for
649 Xvnc, since it allocates keycodes dynamically */
650 if (xevent.xmapping.request == MappingKeyboard
651 || xevent.xmapping.request == MappingModifier)
652 XRefreshKeyboardMapping(&xevent.xmapping);
653 break;
654
655 }
656 }
657 }
658
659 void
660 ui_select(int rdp_socket)
661 {
662 int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;
663 fd_set rfds;
664 XEvent xevent;
665
666 FD_ZERO(&rfds);
667
668 while (True)
669 {
670 /* Process any events already in queue */
671 xwin_process_events();
672
673 FD_ZERO(&rfds);
674 FD_SET(rdp_socket, &rfds);
675 if (display != NULL)
676 {
677 FD_SET(x_socket, &rfds);
678 XFlush(display);
679 }
680
681 switch (select(n, &rfds, NULL, NULL, NULL))
682 {
683 case -1:
684 error("select: %s\n", strerror(errno));
685
686 case 0:
687 continue;
688 }
689
690 if (FD_ISSET(x_socket, &rfds))
691 {
692 /* Move new events from socket to queue */
693 XPeekEvent(display, &xevent);
694 continue;
695 }
696
697 if (FD_ISSET(rdp_socket, &rfds))
698 return;
699 }
700 }
701
702 void
703 ui_move_pointer(int x, int y)
704 {
705 XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);
706 }
707
708 HBITMAP
709 ui_create_bitmap(int width, int height, uint8 * data)
710 {
711 XImage *image;
712 Pixmap bitmap;
713 uint8 *tdata;
714
715 tdata = (owncolmap ? data : translate_image(width, height, data));
716 bitmap = XCreatePixmap(display, wnd, width, height, depth);
717 image = XCreateImage(display, visual, depth, ZPixmap, 0,
718 (char *) tdata, width, height, 8, 0);
719
720 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
721
722 XFree(image);
723 if (!owncolmap)
724 xfree(tdata);
725 return (HBITMAP) bitmap;
726 }
727
728 void
729 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
730 {
731 XImage *image;
732 uint8 *tdata;
733
734 tdata = (owncolmap ? data : translate_image(width, height, data));
735 image = XCreateImage(display, visual, depth, ZPixmap, 0,
736 (char *) tdata, width, height, 8, 0);
737
738 if (ownbackstore)
739 {
740 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
741 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
742 }
743 else
744 {
745 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
746 }
747
748 XFree(image);
749 if (!owncolmap)
750 xfree(tdata);
751 }
752
753 void
754 ui_destroy_bitmap(HBITMAP bmp)
755 {
756 XFreePixmap(display, (Pixmap) bmp);
757 }
758
759 HGLYPH
760 ui_create_glyph(int width, int height, uint8 * data)
761 {
762 XImage *image;
763 Pixmap bitmap;
764 int scanline;
765 GC gc;
766
767 scanline = (width + 7) / 8;
768
769 bitmap = XCreatePixmap(display, wnd, width, height, 1);
770 gc = XCreateGC(display, bitmap, 0, NULL);
771
772 image = XCreateImage(display, visual, 1, ZPixmap, 0, (char *) data,
773 width, height, 8, scanline);
774 image->byte_order = MSBFirst;
775 image->bitmap_bit_order = MSBFirst;
776 XInitImage(image);
777
778 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
779
780 XFree(image);
781 XFreeGC(display, gc);
782 return (HGLYPH) bitmap;
783 }
784
785 void
786 ui_destroy_glyph(HGLYPH glyph)
787 {
788 XFreePixmap(display, (Pixmap) glyph);
789 }
790
791 HCURSOR
792 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
793 uint8 * andmask, uint8 * xormask)
794 {
795 HGLYPH maskglyph, cursorglyph;
796 XColor bg, fg;
797 Cursor xcursor;
798 uint8 *cursor, *pcursor;
799 uint8 *mask, *pmask;
800 uint8 nextbit;
801 int scanline, offset;
802 int i, j;
803
804 scanline = (width + 7) / 8;
805 offset = scanline * height;
806
807 cursor = xmalloc(offset);
808 memset(cursor, 0, offset);
809
810 mask = xmalloc(offset);
811 memset(mask, 0, offset);
812
813 /* approximate AND and XOR masks with a monochrome X pointer */
814 for (i = 0; i < height; i++)
815 {
816 offset -= scanline;
817 pcursor = &cursor[offset];
818 pmask = &mask[offset];
819
820 for (j = 0; j < scanline; j++)
821 {
822 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
823 {
824 if (xormask[0] || xormask[1] || xormask[2])
825 {
826 *pcursor |= (~(*andmask) & nextbit);
827 *pmask |= nextbit;
828 }
829 else
830 {
831 *pcursor |= ((*andmask) & nextbit);
832 *pmask |= (~(*andmask) & nextbit);
833 }
834
835 xormask += 3;
836 }
837
838 andmask++;
839 pcursor++;
840 pmask++;
841 }
842 }
843
844 fg.red = fg.blue = fg.green = 0xffff;
845 bg.red = bg.blue = bg.green = 0x0000;
846 fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
847
848 cursorglyph = ui_create_glyph(width, height, cursor);
849 maskglyph = ui_create_glyph(width, height, mask);
850
851 xcursor =
852 XCreatePixmapCursor(display, (Pixmap) cursorglyph,
853 (Pixmap) maskglyph, &fg, &bg, x, y);
854
855 ui_destroy_glyph(maskglyph);
856 ui_destroy_glyph(cursorglyph);
857 xfree(mask);
858 xfree(cursor);
859 return (HCURSOR) xcursor;
860 }
861
862 void
863 ui_set_cursor(HCURSOR cursor)
864 {
865 XDefineCursor(display, wnd, (Cursor) cursor);
866 }
867
868 void
869 ui_destroy_cursor(HCURSOR cursor)
870 {
871 XFreeCursor(display, (Cursor) cursor);
872 }
873
874 #define MAKE_XCOLOR(xc,c) \
875 (xc)->red = ((c)->red << 8) | (c)->red; \
876 (xc)->green = ((c)->green << 8) | (c)->green; \
877 (xc)->blue = ((c)->blue << 8) | (c)->blue; \
878 (xc)->flags = DoRed | DoGreen | DoBlue;
879
880 HCOLOURMAP
881 ui_create_colourmap(COLOURMAP * colours)
882 {
883 COLOURENTRY *entry;
884 int i, ncolours = colours->ncolours;
885
886 if (owncolmap)
887 {
888 XColor *xcolours, *xentry;
889 Colormap map;
890
891 xcolours = xmalloc(sizeof(XColor) * ncolours);
892 for (i = 0; i < ncolours; i++)
893 {
894 entry = &colours->colours[i];
895 xentry = &xcolours[i];
896 xentry->pixel = i;
897 MAKE_XCOLOR(xentry, entry);
898 }
899
900 map = XCreateColormap(display, wnd, visual, AllocAll);
901 XStoreColors(display, map, xcolours, ncolours);
902
903 xfree(xcolours);
904 return (HCOLOURMAP) map;
905 }
906 else
907 {
908 uint32 *map = xmalloc(sizeof(*colmap) * ncolours);
909 XColor xentry;
910 uint32 colour;
911
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 colour = xentry.pixel;
919 else
920 colour = white;
921
922 /* byte swap here to make translate_image faster */
923 map[i] = translate_colour(colour);
924 }
925
926 return map;
927 }
928 }
929
930 void
931 ui_destroy_colourmap(HCOLOURMAP map)
932 {
933 if (owncolmap)
934 XFreeColormap(display, (Colormap) map);
935 else
936 xfree(map);
937 }
938
939 void
940 ui_set_colourmap(HCOLOURMAP map)
941 {
942 if (owncolmap)
943 XSetWindowColormap(display, wnd, (Colormap) map);
944 else
945 colmap = map;
946 }
947
948 void
949 ui_set_clip(int x, int y, int cx, int cy)
950 {
951 XRectangle rect;
952
953 rect.x = x;
954 rect.y = y;
955 rect.width = cx;
956 rect.height = cy;
957 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
958 }
959
960 void
961 ui_reset_clip()
962 {
963 XRectangle rect;
964
965 rect.x = 0;
966 rect.y = 0;
967 rect.width = width;
968 rect.height = height;
969 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
970 }
971
972 void
973 ui_bell()
974 {
975 XBell(display, 0);
976 }
977
978 void
979 ui_destblt(uint8 opcode,
980 /* dest */ int x, int y, int cx, int cy)
981 {
982 SET_FUNCTION(opcode);
983 FILL_RECTANGLE(x, y, cx, cy);
984 RESET_FUNCTION(opcode);
985 }
986
987 void
988 ui_patblt(uint8 opcode,
989 /* dest */ int x, int y, int cx, int cy,
990 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
991 {
992 Pixmap fill;
993 uint8 i, ipattern[8];
994
995 SET_FUNCTION(opcode);
996
997 switch (brush->style)
998 {
999 case 0: /* Solid */
1000 SET_FOREGROUND(fgcolour);
1001 FILL_RECTANGLE(x, y, cx, cy);
1002 break;
1003
1004 case 3: /* Pattern */
1005 for (i = 0; i != 8; i++)
1006 ipattern[7 - i] = brush->pattern[i];
1007 fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1008
1009 SET_FOREGROUND(bgcolour);
1010 SET_BACKGROUND(fgcolour);
1011 XSetFillStyle(display, gc, FillOpaqueStippled);
1012 XSetStipple(display, gc, fill);
1013 XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);
1014
1015 FILL_RECTANGLE(x, y, cx, cy);
1016
1017 XSetFillStyle(display, gc, FillSolid);
1018 XSetTSOrigin(display, gc, 0, 0);
1019 ui_destroy_glyph((HGLYPH) fill);
1020 break;
1021
1022 default:
1023 unimpl("brush %d\n", brush->style);
1024 }
1025
1026 RESET_FUNCTION(opcode);
1027 }
1028
1029 void
1030 ui_screenblt(uint8 opcode,
1031 /* dest */ int x, int y, int cx, int cy,
1032 /* src */ int srcx, int srcy)
1033 {
1034 SET_FUNCTION(opcode);
1035 XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);
1036 if (ownbackstore)
1037 XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx, cy, x, y);
1038 RESET_FUNCTION(opcode);
1039 }
1040
1041 void
1042 ui_memblt(uint8 opcode,
1043 /* dest */ int x, int y, int cx, int cy,
1044 /* src */ HBITMAP src, int srcx, int srcy)
1045 {
1046 SET_FUNCTION(opcode);
1047 XCopyArea(display, (Pixmap) src, wnd, gc, srcx, srcy, cx, cy, x, y);
1048 if (ownbackstore)
1049 XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy, cx, cy, x, y);
1050 RESET_FUNCTION(opcode);
1051 }
1052
1053 void
1054 ui_triblt(uint8 opcode,
1055 /* dest */ int x, int y, int cx, int cy,
1056 /* src */ HBITMAP src, int srcx, int srcy,
1057 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1058 {
1059 /* This is potentially difficult to do in general. Until someone
1060 comes up with a more efficient way of doing it I am using cases. */
1061
1062 switch (opcode)
1063 {
1064 case 0x69: /* PDSxxn */
1065 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1066 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1067 break;
1068
1069 case 0xb8: /* PSDPxax */
1070 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1071 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1072 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1073 break;
1074
1075 case 0xc0: /* PSa */
1076 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1077 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1078 break;
1079
1080 default:
1081 unimpl("triblt 0x%x\n", opcode);
1082 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1083 }
1084 }
1085
1086 void
1087 ui_line(uint8 opcode,
1088 /* dest */ int startx, int starty, int endx, int endy,
1089 /* pen */ PEN * pen)
1090 {
1091 SET_FUNCTION(opcode);
1092 SET_FOREGROUND(pen->colour);
1093 XDrawLine(display, wnd, gc, startx, starty, endx, endy);
1094 if (ownbackstore)
1095 XDrawLine(display, backstore, gc, startx, starty, endx, endy);
1096 RESET_FUNCTION(opcode);
1097 }
1098
1099 void
1100 ui_rect(
1101 /* dest */ int x, int y, int cx, int cy,
1102 /* brush */ int colour)
1103 {
1104 SET_FOREGROUND(colour);
1105 FILL_RECTANGLE(x, y, cx, cy);
1106 }
1107
1108 void
1109 ui_draw_glyph(int mixmode,
1110 /* dest */ int x, int y, int cx, int cy,
1111 /* src */ HGLYPH glyph, int srcx, int srcy,
1112 int bgcolour, int fgcolour)
1113 {
1114 SET_FOREGROUND(fgcolour);
1115 SET_BACKGROUND(bgcolour);
1116
1117 XSetFillStyle(display, gc,
1118 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1119 XSetStipple(display, gc, (Pixmap) glyph);
1120 XSetTSOrigin(display, gc, x, y);
1121
1122 FILL_RECTANGLE(x, y, cx, cy);
1123
1124 XSetFillStyle(display, gc, FillSolid);
1125 }
1126
1127 #define DO_GLYPH(ttext,idx) \
1128 {\
1129 glyph = cache_get_font (font, ttext[idx]);\
1130 if (!(flags & TEXT2_IMPLICIT_X))\
1131 {\
1132 xyoffset = ttext[++idx];\
1133 if ((xyoffset & 0x80))\
1134 {\
1135 if (flags & TEXT2_VERTICAL) \
1136 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1137 else\
1138 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1139 idx += 2;\
1140 }\
1141 else\
1142 {\
1143 if (flags & TEXT2_VERTICAL) \
1144 y += xyoffset;\
1145 else\
1146 x += xyoffset;\
1147 }\
1148 }\
1149 if (glyph != NULL)\
1150 {\
1151 ui_draw_glyph (mixmode, x + (short) glyph->offset,\
1152 y + (short) glyph->baseline,\
1153 glyph->width, glyph->height,\
1154 glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1155 if (flags & TEXT2_IMPLICIT_X)\
1156 x += glyph->width;\
1157 }\
1158 }
1159
1160 void
1161 ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1162 int clipx, int clipy, int clipcx, int clipcy,
1163 int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1164 int fgcolour, uint8 * text, uint8 length)
1165 {
1166 FONTGLYPH *glyph;
1167 int i, j, xyoffset;
1168 DATABLOB *entry;
1169
1170 SET_FOREGROUND(bgcolour);
1171
1172 if (boxcx > 1)
1173 {
1174 FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);
1175 }
1176 else if (mixmode == MIX_OPAQUE)
1177 {
1178 FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);
1179 }
1180
1181 /* Paint text, character by character */
1182 for (i = 0; i < length;)
1183 {
1184 switch (text[i])
1185 {
1186 case 0xff:
1187 if (i + 2 < length)
1188 cache_put_text(text[i + 1], text, text[i + 2]);
1189 else
1190 {
1191 error("this shouldn't be happening\n");
1192 break;
1193 }
1194 /* this will move pointer from start to first character after FF command */
1195 length -= i + 3;
1196 text = &(text[i + 3]);
1197 i = 0;
1198 break;
1199
1200 case 0xfe:
1201 entry = cache_get_text(text[i + 1]);
1202 if (entry != NULL)
1203 {
1204 if ((((uint8 *) (entry->data))[1] ==
1205 0) && (!(flags & TEXT2_IMPLICIT_X)))
1206 {
1207 if (flags & TEXT2_VERTICAL)
1208 y += text[i + 2];
1209 else
1210 x += text[i + 2];
1211 }
1212 if (i + 2 < length)
1213 i += 3;
1214 else
1215 i += 2;
1216 length -= i;
1217 /* this will move pointer from start to first character after FE command */
1218 text = &(text[i]);
1219 i = 0;
1220 for (j = 0; j < entry->size; j++)
1221 DO_GLYPH(((uint8 *) (entry->data)), j);
1222 }
1223 break;
1224
1225 default:
1226 DO_GLYPH(text, i);
1227 i++;
1228 break;
1229 }
1230 }
1231
1232
1233 }
1234
1235 void
1236 ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1237 {
1238 Pixmap pix;
1239 XImage *image;
1240
1241 if (ownbackstore)
1242 {
1243 image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1244 }
1245 else
1246 {
1247 pix = XCreatePixmap(display, wnd, cx, cy, depth);
1248 XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);
1249 image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1250 XFreePixmap(display, pix);
1251 }
1252
1253 offset *= bpp / 8;
1254 cache_put_desktop(offset, cx, cy, image->bytes_per_line, bpp / 8, (uint8 *) image->data);
1255
1256 XDestroyImage(image);
1257 }
1258
1259 void
1260 ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1261 {
1262 XImage *image;
1263 uint8 *data;
1264
1265 offset *= bpp / 8;
1266 data = cache_get_desktop(offset, cx, cy, bpp / 8);
1267 if (data == NULL)
1268 return;
1269
1270 image = XCreateImage(display, visual, depth, ZPixmap, 0,
1271 (char *) data, cx, cy, BitmapPad(display), cx * bpp / 8);
1272
1273 if (ownbackstore)
1274 {
1275 XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
1276 XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
1277 }
1278 else
1279 {
1280 XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
1281 }
1282
1283 XFree(image);
1284 }

  ViewVC Help
Powered by ViewVC 1.1.26