/[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 265 - (hide annotations)
Tue Nov 19 10:37:39 2002 UTC (21 years, 5 months ago) by astrand
File MIME type: text/plain
File size: 28385 byte(s)
exit()ing after "this shouldn't be happening".

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     exit(1);
311     }
312     }
313    
314 astrand 82 if (fullscreen)
315 jsorg71 81 {
316     width = WidthOfScreen(screen);
317     height = HeightOfScreen(screen);
318     }
319 matthewc 121
320 matthewc 160 /* make sure width is a multiple of 4 */
321     width = (width + 3) & ~3;
322    
323 matthewc 188 if (ownbackstore)
324     {
325 astrand 196 backstore =
326     XCreatePixmap(display, RootWindowOfScreen(screen), width, height, depth);
327 matthewc 188
328     /* clear to prevent rubbish being exposed at startup */
329     XSetForeground(display, gc, BlackPixelOfScreen(screen));
330     XFillRectangle(display, backstore, gc, 0, 0, width, height);
331     }
332    
333 matthewc 203 mod_map = XGetModifierMapping(display);
334    
335 matthewc 188 if (enable_compose)
336     IM = XOpenIM(display, NULL, NULL, NULL);
337    
338 matthewc 121 xkeymap_init();
339 jsorg71 81 return True;
340     }
341 astrand 66
342 matthewc 188 void
343 matthewc 192 ui_deinit(void)
344 matthewc 188 {
345     if (IM != NULL)
346     XCloseIM(IM);
347    
348 matthewc 204 XFreeModifiermap(mod_map);
349 matthewc 203
350 matthewc 188 if (ownbackstore)
351     XFreePixmap(display, backstore);
352    
353     XFreeGC(display, gc);
354     XCloseDisplay(display);
355     display = NULL;
356     }
357    
358 matthewc 121 BOOL
359 matthewc 192 ui_create_window(void)
360 matty 6 {
361 matthewc 121 XSetWindowAttributes attribs;
362 matty 28 XClassHint *classhints;
363     XSizeHints *sizehints;
364 matthewc 188 int wndwidth, wndheight;
365     long input_mask, ic_input_mask;
366 jsorg71 100 XEvent xevent;
367    
368 astrand 196 wndwidth = fullscreen ? WidthOfScreen(screen) : width;
369 matthewc 188 wndheight = fullscreen ? HeightOfScreen(screen) : height;
370    
371 matthewc 121 attribs.background_pixel = BlackPixelOfScreen(screen);
372     attribs.backing_store = ownbackstore ? NotUseful : Always;
373     attribs.override_redirect = fullscreen;
374 matthewc 188
375     wnd = XCreateWindow(display, RootWindowOfScreen(screen), 0, 0, wndwidth, wndheight,
376 matthewc 121 0, CopyFromParent, InputOutput, CopyFromParent,
377     CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);
378 jsorg71 100
379     XStoreName(display, wnd, title);
380    
381 astrand 262 if (hide_decorations)
382     mwm_hide_decorations();
383    
384 jsorg71 100 classhints = XAllocClassHint();
385     if (classhints != NULL)
386     {
387     classhints->res_name = classhints->res_class = "rdesktop";
388     XSetClassHint(display, wnd, classhints);
389     XFree(classhints);
390     }
391    
392     sizehints = XAllocSizeHints();
393     if (sizehints)
394     {
395     sizehints->flags = PMinSize | PMaxSize;
396     sizehints->min_width = sizehints->max_width = width;
397     sizehints->min_height = sizehints->max_height = height;
398     XSetWMNormalHints(display, wnd, sizehints);
399     XFree(sizehints);
400     }
401    
402 matthewc 121 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
403 jsorg71 257 VisibilityChangeMask | FocusChangeMask;
404 matthewc 121
405     if (sendmotion)
406     input_mask |= PointerMotionMask;
407     if (ownbackstore)
408     input_mask |= ExposureMask;
409 jsorg71 257 if (fullscreen || grab_keyboard)
410 matthewc 250 input_mask |= EnterWindowMask;
411 jsorg71 257 if (grab_keyboard)
412     input_mask |= LeaveWindowMask;
413 jsorg71 100
414 matthewc 188 if (IM != NULL)
415     {
416     IC = XCreateIC(IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
417     XNClientWindow, wnd, XNFocusWindow, wnd, NULL);
418    
419 astrand 196 if ((IC != NULL)
420     && (XGetICValues(IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
421 matthewc 188 input_mask |= ic_input_mask;
422     }
423    
424 jsorg71 100 XSelectInput(display, wnd, input_mask);
425 matthewc 188 XMapWindow(display, wnd);
426 jsorg71 100
427 matthewc 208 /* wait for VisibilityNotify */
428 astrand 196 do
429     {
430 matthewc 208 XMaskEvent(display, VisibilityChangeMask, &xevent);
431 astrand 196 }
432 matthewc 208 while (xevent.type != VisibilityNotify);
433 matthewc 123
434 jsorg71 257 focused = False;
435     mouse_in_wnd = False;
436    
437 matty 10 return True;
438 matty 6 }
439    
440 matty 25 void
441 matthewc 192 ui_destroy_window(void)
442 matty 6 {
443 matthewc 188 if (IC != NULL)
444     XDestroyIC(IC);
445 matty 31
446 matty 10 XDestroyWindow(display, wnd);
447 matty 6 }
448    
449 jsorg71 100 void
450 matthewc 192 xwin_toggle_fullscreen(void)
451 jsorg71 100 {
452 matthewc 188 Pixmap contents = 0;
453 matthewc 123
454 matthewc 188 if (!ownbackstore)
455     {
456     /* need to save contents of window */
457     contents = XCreatePixmap(display, wnd, width, height, depth);
458     XCopyArea(display, wnd, contents, gc, 0, 0, width, height, 0, 0);
459     }
460    
461     ui_destroy_window();
462 matthewc 123 fullscreen = !fullscreen;
463 matthewc 188 ui_create_window();
464 matthewc 123
465 matthewc 188 XDefineCursor(display, wnd, current_cursor);
466    
467     if (!ownbackstore)
468     {
469     XCopyArea(display, contents, wnd, gc, 0, 0, width, height, 0, 0);
470     XFreePixmap(display, contents);
471     }
472 jsorg71 100 }
473    
474 astrand 119 /* Process all events in Xlib queue */
475 matty 33 static void
476 matthewc 192 xwin_process_events(void)
477 matty 9 {
478 n-ki 54 XEvent xevent;
479 matthewc 38 KeySym keysym;
480 matthewc 50 uint16 button, flags;
481 matty 10 uint32 ev_time;
482 astrand 66 key_translation tr;
483     char str[256];
484     Status status;
485 matthewc 203 unsigned int state;
486     Window wdummy;
487     int dummy;
488 matty 9
489 matthewc 123 while (XPending(display) > 0)
490 matty 9 {
491 matthewc 123 XNextEvent(display, &xevent);
492    
493 matthewc 188 if ((IC != NULL) && (XFilterEvent(&xevent, None) == True))
494 astrand 66 {
495 astrand 84 DEBUG_KBD(("Filtering event\n"));
496 astrand 66 continue;
497     }
498    
499 matthewc 50 flags = 0;
500 matty 10
501 n-ki 54 switch (xevent.type)
502 matty 9 {
503     case KeyPress:
504 astrand 66 if (IC != NULL)
505     /* Multi_key compatible version */
506     {
507     XmbLookupString(IC,
508     (XKeyPressedEvent *) &
509 astrand 82 xevent, str, sizeof(str), &keysym, &status);
510     if (!((status == XLookupKeySym) || (status == XLookupBoth)))
511 astrand 66 {
512 astrand 82 error("XmbLookupString failed with status 0x%x\n",
513     status);
514 astrand 66 break;
515     }
516     }
517     else
518     {
519     /* Plain old XLookupString */
520 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
521 astrand 66 XLookupString((XKeyEvent *) & xevent,
522 astrand 82 str, sizeof(str), &keysym, NULL);
523 astrand 66 }
524    
525 astrand 261 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
526     get_ksname(keysym)));
527 astrand 66
528 matthewc 203 ev_time = time(NULL);
529     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
530 astrand 118 break;
531    
532 astrand 66 tr = xkeymap_translate_key(keysym,
533 astrand 82 xevent.xkey.keycode, xevent.xkey.state);
534 astrand 69
535 astrand 66 if (tr.scancode == 0)
536 n-ki 52 break;
537    
538 astrand 115 ensure_remote_modifiers(ev_time, tr);
539    
540 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
541 astrand 66 break;
542 matthewc 203
543 astrand 66 case KeyRelease:
544     XLookupString((XKeyEvent *) & xevent, str,
545     sizeof(str), &keysym, NULL);
546 n-ki 52
547 astrand 84 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
548 matthewc 203 get_ksname(keysym)));
549 n-ki 52
550 matthewc 203 ev_time = time(NULL);
551     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
552 astrand 118 break;
553    
554 astrand 66 tr = xkeymap_translate_key(keysym,
555 astrand 82 xevent.xkey.keycode, xevent.xkey.state);
556 astrand 66
557     if (tr.scancode == 0)
558     break;
559    
560 astrand 82 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
561 matty 9 break;
562    
563     case ButtonPress:
564 matthewc 50 flags = MOUSE_FLAG_DOWN;
565     /* fall through */
566 matty 9
567     case ButtonRelease:
568 astrand 82 button = xkeymap_translate_button(xevent.xbutton.button);
569 matty 9 if (button == 0)
570     break;
571    
572 matthewc 203 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
573 astrand 82 flags | button, xevent.xbutton.x, xevent.xbutton.y);
574 matty 10 break;
575    
576     case MotionNotify:
577 matthewc 203 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
578 astrand 82 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
579 matty 28 break;
580    
581 matthewc 194 case FocusIn:
582 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
583     break;
584     focused = True;
585 astrand 261 XQueryPointer(display, wnd, &wdummy, &wdummy, &dummy, &dummy,
586     &dummy, &dummy, &state);
587 matthewc 203 reset_modifier_keys(state);
588 jsorg71 257 if (grab_keyboard && mouse_in_wnd)
589 astrand 76 XGrabKeyboard(display, wnd, True,
590 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
591 matty 28 break;
592    
593 matthewc 194 case FocusOut:
594 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
595     break;
596     focused = False;
597 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
598 astrand 76 XUngrabKeyboard(display, CurrentTime);
599 matty 28 break;
600 matty 31
601 matthewc 250 case EnterNotify:
602     /* we only register for this event when in fullscreen mode */
603 jsorg71 257 /* or grab_keyboard */
604     mouse_in_wnd = True;
605     if (fullscreen)
606     {
607 astrand 261 XSetInputFocus(display, wnd, RevertToPointerRoot,
608     CurrentTime);
609 jsorg71 257 break;
610     }
611     if (focused)
612     XGrabKeyboard(display, wnd, True,
613     GrabModeAsync, GrabModeAsync, CurrentTime);
614 matthewc 250 break;
615    
616 matthewc 253 case LeaveNotify:
617 jsorg71 257 /* we only register for this event when grab_keyboard */
618     mouse_in_wnd = False;
619 matthewc 253 XUngrabKeyboard(display, CurrentTime);
620     break;
621    
622 matty 31 case Expose:
623     XCopyArea(display, backstore, wnd, gc,
624 n-ki 54 xevent.xexpose.x, xevent.xexpose.y,
625 astrand 64 xevent.xexpose.width,
626     xevent.xexpose.height,
627 n-ki 54 xevent.xexpose.x, xevent.xexpose.y);
628 matty 31 break;
629 astrand 119
630     case MappingNotify:
631     /* Refresh keyboard mapping if it has changed. This is important for
632     Xvnc, since it allocates keycodes dynamically */
633     if (xevent.xmapping.request == MappingKeyboard
634     || xevent.xmapping.request == MappingModifier)
635     XRefreshKeyboardMapping(&xevent.xmapping);
636 matthewc 203
637     if (xevent.xmapping.request == MappingModifier)
638     {
639 matthewc 204 XFreeModifiermap(mod_map);
640 matthewc 203 mod_map = XGetModifierMapping(display);
641     }
642 astrand 119 break;
643    
644 matty 9 }
645     }
646     }
647    
648 matty 25 void
649 matty 33 ui_select(int rdp_socket)
650     {
651 astrand 64 int n = (rdp_socket > x_socket) ? rdp_socket + 1 : x_socket + 1;
652 matty 33 fd_set rfds;
653    
654     FD_ZERO(&rfds);
655    
656     while (True)
657     {
658 matthewc 121 /* Process any events already waiting */
659 astrand 119 xwin_process_events();
660    
661 matty 33 FD_ZERO(&rfds);
662     FD_SET(rdp_socket, &rfds);
663 matthewc 121 FD_SET(x_socket, &rfds);
664 matty 33
665     switch (select(n, &rfds, NULL, NULL, NULL))
666     {
667     case -1:
668     error("select: %s\n", strerror(errno));
669    
670     case 0:
671     continue;
672     }
673    
674     if (FD_ISSET(rdp_socket, &rfds))
675     return;
676     }
677     }
678    
679     void
680 matty 25 ui_move_pointer(int x, int y)
681 matty 9 {
682 matty 10 XWarpPointer(display, wnd, wnd, 0, 0, 0, 0, x, y);
683 matty 9 }
684    
685 matty 25 HBITMAP
686 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
687 matty 6 {
688     XImage *image;
689 matty 9 Pixmap bitmap;
690 matty 28 uint8 *tdata;
691 matty 29
692 n-ki 185 tdata = translate_image(width, height, data);
693 matty 28 bitmap = XCreatePixmap(display, wnd, width, height, depth);
694 astrand 77 image = XCreateImage(display, visual, depth, ZPixmap, 0,
695     (char *) tdata, width, height, 8, 0);
696 matty 6
697 matty 28 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
698 matty 9
699     XFree(image);
700 n-ki 185 xfree(tdata);
701 matty 24 return (HBITMAP) bitmap;
702 matty 6 }
703    
704 matty 25 void
705 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
706 matty 6 {
707 matty 10 XImage *image;
708 matty 29 uint8 *tdata;
709 matty 10
710 n-ki 185 tdata = translate_image(width, height, data);
711 astrand 77 image = XCreateImage(display, visual, depth, ZPixmap, 0,
712     (char *) tdata, width, height, 8, 0);
713 matty 28
714 matty 31 if (ownbackstore)
715     {
716     XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
717     XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
718     }
719     else
720     {
721     XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
722     }
723 matty 29
724 matty 24 XFree(image);
725 n-ki 185 xfree(tdata);
726 matty 6 }
727    
728 matty 25 void
729     ui_destroy_bitmap(HBITMAP bmp)
730 matty 6 {
731 astrand 64 XFreePixmap(display, (Pixmap) bmp);
732 matty 10 }
733    
734 matty 25 HGLYPH
735 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
736 matty 10 {
737 matty 9 XImage *image;
738     Pixmap bitmap;
739     int scanline;
740     GC gc;
741 matty 6
742 matty 9 scanline = (width + 7) / 8;
743 matty 6
744 matty 10 bitmap = XCreatePixmap(display, wnd, width, height, 1);
745     gc = XCreateGC(display, bitmap, 0, NULL);
746 matty 9
747 astrand 77 image = XCreateImage(display, visual, 1, ZPixmap, 0, (char *) data,
748 astrand 73 width, height, 8, scanline);
749 matty 23 image->byte_order = MSBFirst;
750     image->bitmap_bit_order = MSBFirst;
751     XInitImage(image);
752    
753 matty 10 XPutImage(display, bitmap, gc, image, 0, 0, 0, 0, width, height);
754 matty 29
755 matty 9 XFree(image);
756 matty 10 XFreeGC(display, gc);
757 astrand 64 return (HGLYPH) bitmap;
758 matty 6 }
759 matty 7
760 matty 25 void
761     ui_destroy_glyph(HGLYPH glyph)
762 matty 7 {
763 astrand 64 XFreePixmap(display, (Pixmap) glyph);
764 matty 9 }
765    
766 matty 29 HCURSOR
767 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
768     uint8 * andmask, uint8 * xormask)
769 matty 9 {
770 matty 29 HGLYPH maskglyph, cursorglyph;
771     XColor bg, fg;
772     Cursor xcursor;
773     uint8 *cursor, *pcursor;
774     uint8 *mask, *pmask;
775     uint8 nextbit;
776     int scanline, offset;
777     int i, j;
778    
779     scanline = (width + 7) / 8;
780     offset = scanline * height;
781    
782     cursor = xmalloc(offset);
783     memset(cursor, 0, offset);
784    
785     mask = xmalloc(offset);
786     memset(mask, 0, offset);
787    
788     /* approximate AND and XOR masks with a monochrome X pointer */
789     for (i = 0; i < height; i++)
790 matty 7 {
791 matty 29 offset -= scanline;
792     pcursor = &cursor[offset];
793     pmask = &mask[offset];
794    
795     for (j = 0; j < scanline; j++)
796 matty 28 {
797 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
798     {
799     if (xormask[0] || xormask[1] || xormask[2])
800     {
801     *pcursor |= (~(*andmask) & nextbit);
802     *pmask |= nextbit;
803     }
804     else
805     {
806     *pcursor |= ((*andmask) & nextbit);
807     *pmask |= (~(*andmask) & nextbit);
808     }
809    
810     xormask += 3;
811     }
812    
813     andmask++;
814     pcursor++;
815     pmask++;
816 matty 28 }
817 matty 7 }
818 matty 29
819     fg.red = fg.blue = fg.green = 0xffff;
820     bg.red = bg.blue = bg.green = 0x0000;
821     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
822    
823     cursorglyph = ui_create_glyph(width, height, cursor);
824     maskglyph = ui_create_glyph(width, height, mask);
825    
826 astrand 66 xcursor =
827     XCreatePixmapCursor(display, (Pixmap) cursorglyph,
828     (Pixmap) maskglyph, &fg, &bg, x, y);
829 astrand 64
830 matty 29 ui_destroy_glyph(maskglyph);
831     ui_destroy_glyph(cursorglyph);
832     xfree(mask);
833     xfree(cursor);
834 astrand 64 return (HCURSOR) xcursor;
835 matty 29 }
836    
837     void
838     ui_set_cursor(HCURSOR cursor)
839     {
840 matthewc 188 current_cursor = (Cursor) cursor;
841     XDefineCursor(display, wnd, current_cursor);
842 matty 29 }
843    
844     void
845     ui_destroy_cursor(HCURSOR cursor)
846     {
847 astrand 64 XFreeCursor(display, (Cursor) cursor);
848 matty 29 }
849    
850     #define MAKE_XCOLOR(xc,c) \
851     (xc)->red = ((c)->red << 8) | (c)->red; \
852     (xc)->green = ((c)->green << 8) | (c)->green; \
853     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
854     (xc)->flags = DoRed | DoGreen | DoBlue;
855    
856     HCOLOURMAP
857 astrand 64 ui_create_colourmap(COLOURMAP * colours)
858 matty 29 {
859     COLOURENTRY *entry;
860     int i, ncolours = colours->ncolours;
861 n-ki 185 uint32 *map = xmalloc(sizeof(*colmap) * ncolours);
862     XColor xentry;
863     XColor xc_cache[256];
864     uint32 colour;
865     int colLookup = 256;
866     for (i = 0; i < ncolours; i++)
867 matty 28 {
868 n-ki 185 entry = &colours->colours[i];
869     MAKE_XCOLOR(&xentry, entry);
870 matty 29
871 n-ki 185 if (XAllocColor(display, xcolmap, &xentry) == 0)
872 matty 28 {
873 n-ki 185 /* Allocation failed, find closest match. */
874     int j = 256;
875     int nMinDist = 3 * 256 * 256;
876     long nDist = nMinDist;
877 matty 7
878 n-ki 185 /* only get the colors once */
879 astrand 196 while (colLookup--)
880     {
881 n-ki 185 xc_cache[colLookup].pixel = colLookup;
882 astrand 196 xc_cache[colLookup].red = xc_cache[colLookup].green =
883     xc_cache[colLookup].blue = 0;
884 n-ki 185 xc_cache[colLookup].flags = 0;
885 astrand 196 XQueryColor(display,
886     DefaultColormap(display, DefaultScreen(display)),
887     &xc_cache[colLookup]);
888 n-ki 185 }
889     colLookup = 0;
890 matty 28
891 n-ki 185 /* approximate the pixel */
892 astrand 196 while (j--)
893     {
894     if (xc_cache[j].flags)
895     {
896     nDist = ((long) (xc_cache[j].red >> 8) -
897     (long) (xentry.red >> 8)) *
898     ((long) (xc_cache[j].red >> 8) -
899     (long) (xentry.red >> 8)) +
900     ((long) (xc_cache[j].green >> 8) -
901     (long) (xentry.green >> 8)) *
902     ((long) (xc_cache[j].green >> 8) -
903     (long) (xentry.green >> 8)) +
904     ((long) (xc_cache[j].blue >> 8) -
905     (long) (xentry.blue >> 8)) *
906     ((long) (xc_cache[j].blue >> 8) -
907     (long) (xentry.blue >> 8));
908 n-ki 185 }
909 astrand 196 if (nDist < nMinDist)
910     {
911 n-ki 185 nMinDist = nDist;
912     xentry.pixel = j;
913     }
914     }
915     }
916     colour = xentry.pixel;
917 matty 29
918 n-ki 185 /* update our cache */
919 astrand 196 if (xentry.pixel < 256)
920     {
921 n-ki 185 xc_cache[xentry.pixel].red = xentry.red;
922     xc_cache[xentry.pixel].green = xentry.green;
923     xc_cache[xentry.pixel].blue = xentry.blue;
924 matty 29
925     }
926    
927 n-ki 185
928     /* byte swap here to make translate_image faster */
929     map[i] = translate_colour(colour);
930 matty 29 }
931 n-ki 185
932     return map;
933 matty 7 }
934    
935 matty 25 void
936     ui_destroy_colourmap(HCOLOURMAP map)
937 matty 7 {
938 n-ki 185 xfree(map);
939 matty 7 }
940    
941 matty 25 void
942     ui_set_colourmap(HCOLOURMAP map)
943 matty 7 {
944 n-ki 185 colmap = map;
945 matty 7 }
946    
947 matty 25 void
948     ui_set_clip(int x, int y, int cx, int cy)
949 matty 7 {
950 matty 9 XRectangle rect;
951 matty 7
952 matty 9 rect.x = x;
953     rect.y = y;
954     rect.width = cx;
955     rect.height = cy;
956 matty 10 XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
957 matty 9 }
958 matty 7
959 matty 25 void
960 matthewc 192 ui_reset_clip(void)
961 matty 9 {
962     XRectangle rect;
963    
964     rect.x = 0;
965     rect.y = 0;
966 matty 10 rect.width = width;
967     rect.height = height;
968     XSetClipRectangles(display, gc, 0, 0, &rect, 1, YXBanded);
969 matty 7 }
970    
971 matty 25 void
972 matthewc 192 ui_bell(void)
973 matty 10 {
974     XBell(display, 0);
975     }
976    
977 matty 25 void
978     ui_destblt(uint8 opcode,
979     /* dest */ int x, int y, int cx, int cy)
980 matty 9 {
981 matty 29 SET_FUNCTION(opcode);
982 matty 31 FILL_RECTANGLE(x, y, cx, cy);
983 matty 29 RESET_FUNCTION(opcode);
984 matty 9 }
985    
986 matty 25 void
987     ui_patblt(uint8 opcode,
988     /* dest */ int x, int y, int cx, int cy,
989 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
990 matty 9 {
991     Pixmap fill;
992 jsorg71 59 uint8 i, ipattern[8];
993 matty 9
994 matty 29 SET_FUNCTION(opcode);
995 matty 9
996     switch (brush->style)
997     {
998 matty 24 case 0: /* Solid */
999 matty 29 SET_FOREGROUND(fgcolour);
1000 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1001 matty 9 break;
1002    
1003 matty 24 case 3: /* Pattern */
1004 jsorg71 59 for (i = 0; i != 8; i++)
1005     ipattern[7 - i] = brush->pattern[i];
1006     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1007 matty 9
1008 matty 29 SET_FOREGROUND(bgcolour);
1009     SET_BACKGROUND(fgcolour);
1010     XSetFillStyle(display, gc, FillOpaqueStippled);
1011     XSetStipple(display, gc, fill);
1012 astrand 82 XSetTSOrigin(display, gc, brush->xorigin, brush->yorigin);
1013 matty 9
1014 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1015 matty 9
1016 matty 29 XSetFillStyle(display, gc, FillSolid);
1017 jsorg71 80 XSetTSOrigin(display, gc, 0, 0);
1018 astrand 64 ui_destroy_glyph((HGLYPH) fill);
1019 matty 9 break;
1020    
1021     default:
1022 matty 30 unimpl("brush %d\n", brush->style);
1023 matty 9 }
1024 matty 29
1025     RESET_FUNCTION(opcode);
1026 matty 9 }
1027    
1028 matty 25 void
1029     ui_screenblt(uint8 opcode,
1030     /* dest */ int x, int y, int cx, int cy,
1031     /* src */ int srcx, int srcy)
1032 matty 9 {
1033 matty 29 SET_FUNCTION(opcode);
1034 matty 24 XCopyArea(display, wnd, wnd, gc, srcx, srcy, cx, cy, x, y);
1035 matty 31 if (ownbackstore)
1036 astrand 82 XCopyArea(display, backstore, backstore, gc, srcx, srcy, cx, cy, x, y);
1037 matty 29 RESET_FUNCTION(opcode);
1038 matty 9 }
1039    
1040 matty 25 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 matty 9 {
1045 matty 29 SET_FUNCTION(opcode);
1046 astrand 64 XCopyArea(display, (Pixmap) src, wnd, gc, srcx, srcy, cx, cy, x, y);
1047 matty 31 if (ownbackstore)
1048 astrand 82 XCopyArea(display, (Pixmap) src, backstore, gc, srcx, srcy, cx, cy, x, y);
1049 matty 29 RESET_FUNCTION(opcode);
1050 matty 9 }
1051    
1052 matty 25 void
1053     ui_triblt(uint8 opcode,
1054     /* dest */ int x, int y, int cx, int cy,
1055     /* src */ HBITMAP src, int srcx, int srcy,
1056 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1057 matty 9 {
1058     /* This is potentially difficult to do in general. Until someone
1059 matty 10 comes up with a more efficient way of doing it I am using cases. */
1060 matty 9
1061     switch (opcode)
1062     {
1063 matty 24 case 0x69: /* PDSxxn */
1064 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1065 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1066 matty 16 break;
1067    
1068 matty 24 case 0xb8: /* PSDPxax */
1069 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1070 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1071 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1072 matty 9 break;
1073    
1074 matty 29 case 0xc0: /* PSa */
1075 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1076 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1077 matty 28 break;
1078    
1079 matty 9 default:
1080 matty 30 unimpl("triblt 0x%x\n", opcode);
1081 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1082 matty 9 }
1083     }
1084    
1085 matty 25 void
1086     ui_line(uint8 opcode,
1087     /* dest */ int startx, int starty, int endx, int endy,
1088 astrand 64 /* pen */ PEN * pen)
1089 matty 9 {
1090 matty 29 SET_FUNCTION(opcode);
1091     SET_FOREGROUND(pen->colour);
1092 matty 10 XDrawLine(display, wnd, gc, startx, starty, endx, endy);
1093 matty 31 if (ownbackstore)
1094     XDrawLine(display, backstore, gc, startx, starty, endx, endy);
1095 matty 29 RESET_FUNCTION(opcode);
1096 matty 9 }
1097    
1098 matty 25 void
1099     ui_rect(
1100     /* dest */ int x, int y, int cx, int cy,
1101     /* brush */ int colour)
1102 matty 9 {
1103 matty 29 SET_FOREGROUND(colour);
1104 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1105 matty 9 }
1106    
1107 matty 25 void
1108     ui_draw_glyph(int mixmode,
1109     /* dest */ int x, int y, int cx, int cy,
1110 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
1111     int bgcolour, int fgcolour)
1112 matty 9 {
1113 matty 29 SET_FOREGROUND(fgcolour);
1114     SET_BACKGROUND(bgcolour);
1115 matty 9
1116 astrand 66 XSetFillStyle(display, gc,
1117 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1118 astrand 64 XSetStipple(display, gc, (Pixmap) glyph);
1119 matty 29 XSetTSOrigin(display, gc, x, y);
1120 matty 9
1121 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1122 matty 9
1123 matty 29 XSetFillStyle(display, gc, FillSolid);
1124 matty 9 }
1125    
1126 mmihalik 49 #define DO_GLYPH(ttext,idx) \
1127     {\
1128     glyph = cache_get_font (font, ttext[idx]);\
1129     if (!(flags & TEXT2_IMPLICIT_X))\
1130     {\
1131     xyoffset = ttext[++idx];\
1132     if ((xyoffset & 0x80))\
1133     {\
1134     if (flags & TEXT2_VERTICAL) \
1135 astrand 72 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1136 mmihalik 49 else\
1137 astrand 72 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1138     idx += 2;\
1139 mmihalik 49 }\
1140     else\
1141     {\
1142     if (flags & TEXT2_VERTICAL) \
1143     y += xyoffset;\
1144     else\
1145     x += xyoffset;\
1146     }\
1147     }\
1148     if (glyph != NULL)\
1149     {\
1150     ui_draw_glyph (mixmode, x + (short) glyph->offset,\
1151     y + (short) glyph->baseline,\
1152     glyph->width, glyph->height,\
1153     glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1154     if (flags & TEXT2_IMPLICIT_X)\
1155     x += glyph->width;\
1156     }\
1157     }
1158    
1159 matty 25 void
1160     ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1161 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
1162     int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1163 mmihalik 49 int fgcolour, uint8 * text, uint8 length)
1164 matty 9 {
1165 matty 10 FONTGLYPH *glyph;
1166 mmihalik 49 int i, j, xyoffset;
1167     DATABLOB *entry;
1168 matty 9
1169 matty 29 SET_FOREGROUND(bgcolour);
1170 matty 28
1171 matty 9 if (boxcx > 1)
1172 matty 31 {
1173     FILL_RECTANGLE(boxx, boxy, boxcx, boxcy);
1174     }
1175 matty 17 else if (mixmode == MIX_OPAQUE)
1176 matty 31 {
1177     FILL_RECTANGLE(clipx, clipy, clipcx, clipcy);
1178     }
1179 matty 9
1180     /* Paint text, character by character */
1181 astrand 64 for (i = 0; i < length;)
1182     {
1183     switch (text[i])
1184     {
1185     case 0xff:
1186     if (i + 2 < length)
1187 astrand 82 cache_put_text(text[i + 1], text, text[i + 2]);
1188 astrand 64 else
1189     {
1190     error("this shouldn't be happening\n");
1191 astrand 265 exit(1);
1192 astrand 64 }
1193     /* this will move pointer from start to first character after FF command */
1194     length -= i + 3;
1195     text = &(text[i + 3]);
1196     i = 0;
1197 mmihalik 49 break;
1198 matty 9
1199 astrand 64 case 0xfe:
1200     entry = cache_get_text(text[i + 1]);
1201     if (entry != NULL)
1202     {
1203     if ((((uint8 *) (entry->data))[1] ==
1204 astrand 82 0) && (!(flags & TEXT2_IMPLICIT_X)))
1205 astrand 64 {
1206     if (flags & TEXT2_VERTICAL)
1207     y += text[i + 2];
1208     else
1209     x += text[i + 2];
1210     }
1211     if (i + 2 < length)
1212     i += 3;
1213 mmihalik 49 else
1214 astrand 64 i += 2;
1215     length -= i;
1216     /* this will move pointer from start to first character after FE command */
1217     text = &(text[i]);
1218     i = 0;
1219     for (j = 0; j < entry->size; j++)
1220 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
1221 matthewc 44 }
1222 astrand 64 break;
1223 matty 17
1224 astrand 64 default:
1225     DO_GLYPH(text, i);
1226     i++;
1227     break;
1228 matty 29 }
1229 mmihalik 49 }
1230 matty 28
1231 matty 9
1232     }
1233    
1234 matty 25 void
1235     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1236 matty 9 {
1237 matty 28 Pixmap pix;
1238 matty 9 XImage *image;
1239    
1240 matty 31 if (ownbackstore)
1241     {
1242 astrand 82 image = XGetImage(display, backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1243 matty 31 }
1244     else
1245     {
1246     pix = XCreatePixmap(display, wnd, cx, cy, depth);
1247     XCopyArea(display, wnd, pix, gc, x, y, cx, cy, 0, 0);
1248 astrand 82 image = XGetImage(display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1249 matty 31 XFreePixmap(display, pix);
1250     }
1251 matty 28
1252 astrand 64 offset *= bpp / 8;
1253 astrand 82 cache_put_desktop(offset, cx, cy, image->bytes_per_line, bpp / 8, (uint8 *) image->data);
1254 matty 28
1255     XDestroyImage(image);
1256 matty 9 }
1257    
1258 matty 25 void
1259     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1260 matty 9 {
1261     XImage *image;
1262 matty 10 uint8 *data;
1263 matty 9
1264 astrand 64 offset *= bpp / 8;
1265     data = cache_get_desktop(offset, cx, cy, bpp / 8);
1266 matty 10 if (data == NULL)
1267     return;
1268 matty 29
1269 astrand 77 image = XCreateImage(display, visual, depth, ZPixmap, 0,
1270 astrand 82 (char *) data, cx, cy, BitmapPad(display), cx * bpp / 8);
1271 matty 29
1272 matty 31 if (ownbackstore)
1273     {
1274     XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy);
1275     XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y);
1276     }
1277     else
1278     {
1279     XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy);
1280     }
1281    
1282 matty 9 XFree(image);
1283     }

  ViewVC Help
Powered by ViewVC 1.1.26