/[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 54 - (show annotations)
Fri Jun 7 07:49:59 2002 UTC (21 years, 10 months ago) by n-ki
File MIME type: text/plain
File size: 28541 byte(s)
using XEvent instead of XkbEvent. better tracking of modifiers. ( TODO: 1. sync at start up, 2. fallback for missing or improperly configured xkb module. )

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

  ViewVC Help
Powered by ViewVC 1.1.26