/[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 273 - (hide annotations)
Tue Nov 19 14:22:47 2002 UTC (21 years, 5 months ago) by astrand
File MIME type: text/plain
File size: 28449 byte(s)
Made -g workarea a bit less fatal when the WM does not support _NET_WORKAREA:
defaulting to 800x600.

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

  ViewVC Help
Powered by ViewVC 1.1.26