/[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 279 - (show annotations)
Tue Nov 26 10:09:14 2002 UTC (21 years, 5 months ago) by n-ki
File MIME type: text/plain
File size: 30459 byte(s)
owncolmap reintroduced, basically the same code, but with a switch -C. didn't use the -v switch as in the patches. I believe it is confusing and should be reserved for -version information. Other than that I can say that the code does not work as it does in the patches... haven't found what's wrong with it. bit shifting?

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

  ViewVC Help
Powered by ViewVC 1.1.26