/[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

Annotation of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 274 - (hide annotations)
Tue Nov 19 14:45:13 2002 UTC (21 years, 6 months ago) by astrand
File MIME type: text/plain
File size: 28452 byte(s)
Small indent fix.

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

  ViewVC Help
Powered by ViewVC 1.1.26