/[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 52 - (show annotations)
Fri Apr 26 08:22:39 2002 UTC (22 years ago) by n-ki
File MIME type: text/plain
File size: 26873 byte(s)
adds support for accessx, makes it possible for people with disabilities to use rdesktop. Relies on XKB. Sync problem with changed modifiers on focus in not fixed yet...

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

  ViewVC Help
Powered by ViewVC 1.1.26