/[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 53 - (show annotations)
Tue May 28 11:48:55 2002 UTC (21 years, 11 months ago) by matthewc
File MIME type: text/plain
File size: 26873 byte(s)
Revert to old behaviour of connecting before creating the UI.
This is to stop the UI generating input before the connection is complete
(which causes connection failures).  The one difficulty is that ui_select
is now called before ui_create_window, which may cause problems for other
UIs - we may still need to change this in the future.

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

  ViewVC Help
Powered by ViewVC 1.1.26