/[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 102 - (show annotations)
Mon Aug 26 17:14:04 2002 UTC (21 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 28170 byte(s)
Alt modifier for fullscreen toggle

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

  ViewVC Help
Powered by ViewVC 1.1.26