/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 265 - (show annotations)
Tue Nov 19 10:37:39 2002 UTC (21 years, 6 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 28385 byte(s)
exit()ing after "this shouldn't be happening".

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

  ViewVC Help
Powered by ViewVC 1.1.26