/[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 1380 - (hide annotations)
Wed Jan 17 07:39:31 2007 UTC (17 years, 4 months ago) by astrand
File MIME type: text/plain
File size: 84208 byte(s)
Call ewmh_set_wm_name for main window as well, not just SeamlessRDP windows. This allows specifying an UTF-8 title with the -T argument.

1 forsberg 415 /* -*- c-basic-offset: 8 -*-
2 matty 6 rdesktop: A Remote Desktop Protocol client.
3 matthewc 38 User interface services - X Window System
4 jsorg71 1365 Copyright (C) Matthew Chapman 1999-2007
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 stargo 1370 #include <X11/Xproto.h>
24 matthewc 537 #include <unistd.h>
25 stargo 609 #include <sys/time.h>
26 matty 10 #include <time.h>
27 matty 33 #include <errno.h>
28 stargo 603 #include <strings.h>
29 matty 10 #include "rdesktop.h"
30 forsberg 415 #include "xproto.h"
31 matty 6
32 jsorg71 447 extern int g_width;
33     extern int g_height;
34 stargo 800 extern int g_xpos;
35     extern int g_ypos;
36 stargo 867 extern int g_pos;
37 jsorg71 1372 extern RD_BOOL g_sendmotion;
38     extern RD_BOOL g_fullscreen;
39     extern RD_BOOL g_grab_keyboard;
40     extern RD_BOOL g_hide_decorations;
41 jsorg71 450 extern char g_title[];
42 astrand 1042 /* Color depth of the RDP session.
43     As of RDP 5.1, it may be 8, 15, 16 or 24. */
44     extern int g_server_depth;
45 jsorg71 450 extern int g_win_button_size;
46 matty 10
47 jsorg71 450 Display *g_display;
48     Time g_last_gesturetime;
49     static int g_x_socket;
50     static Screen *g_screen;
51     Window g_wnd;
52 astrand 1199
53     /* SeamlessRDP support */
54     typedef struct _seamless_group
55     {
56     Window wnd;
57     unsigned long id;
58     unsigned int refcnt;
59     } seamless_group;
60     typedef struct _seamless_window
61     {
62     Window wnd;
63     unsigned long id;
64     unsigned long behind;
65     seamless_group *group;
66     int xoffset, yoffset;
67     int width, height;
68     int state; /* normal/minimized/maximized. */
69     unsigned int desktop;
70     struct timeval *position_timer;
71    
72 jsorg71 1372 RD_BOOL outstanding_position;
73 astrand 1199 unsigned int outpos_serial;
74     int outpos_xoffset, outpos_yoffset;
75     int outpos_width, outpos_height;
76    
77     struct _seamless_window *next;
78     } seamless_window;
79     static seamless_window *g_seamless_windows = NULL;
80     static unsigned long g_seamless_focused = 0;
81 jsorg71 1372 static RD_BOOL g_seamless_started = False; /* Server end is up and running */
82     static RD_BOOL g_seamless_active = False; /* We are currently in seamless mode */
83     static RD_BOOL g_seamless_hidden = False; /* Desktop is hidden on server */
84     extern RD_BOOL g_seamless_rdp;
85 astrand 1199
86 stargo 648 extern uint32 g_embed_wnd;
87 jsorg71 1372 RD_BOOL g_enable_compose = False;
88     RD_BOOL g_Unobscured; /* used for screenblt */
89 stargo 576 static GC g_gc = NULL;
90 jsorg71 725 static GC g_create_bitmap_gc = NULL;
91     static GC g_create_glyph_gc = NULL;
92 astrand 1199 static XRectangle g_clip_rectangle;
93 jsorg71 450 static Visual *g_visual;
94 astrand 1042 /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
95     This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
96     as far as we're concerned. */
97 jsorg71 450 static int g_depth;
98 astrand 1042 /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
99     This may be larger than g_depth, in which case some of the bits would
100     be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
101 jsorg71 450 static int g_bpp;
102     static XIM g_IM;
103     static XIC g_IC;
104     static XModifierKeymap *g_mod_map;
105     static Cursor g_current_cursor;
106 jsorg71 1364 static RD_HCURSOR g_null_cursor = NULL;
107 jsorg71 450 static Atom g_protocol_atom, g_kill_atom;
108 astrand 1199 extern Atom g_net_wm_state_atom;
109     extern Atom g_net_wm_desktop_atom;
110 jsorg71 1372 static RD_BOOL g_focused;
111     static RD_BOOL g_mouse_in_wnd;
112 astrand 1049 /* Indicates that:
113     1) visual has 15, 16 or 24 depth and the same color channel masks
114     as its RDP equivalent (implies X server is LE),
115     2) host is LE
116     This will trigger an optimization whose real value is questionable.
117     */
118 jsorg71 1372 static RD_BOOL g_compatible_arch;
119 astrand 1042 /* Indicates whether RDP's bitmaps and our XImages have the same
120     binary format. If so, we can avoid an expensive translation.
121 astrand 1049 Note that this can be true when g_compatible_arch is false,
122     e.g.:
123    
124     RDP(LE) <-> host(BE) <-> X-Server(LE)
125    
126     ('host' is the machine running rdesktop; the host simply memcpy's
127     so its endianess doesn't matter)
128     */
129 jsorg71 1372 static RD_BOOL g_no_translate_image = False;
130 matty 29
131 matty 33 /* endianness */
132 jsorg71 1372 static RD_BOOL g_host_be;
133     static RD_BOOL g_xserver_be;
134 matthewc 527 static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
135     static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
136 matty 33
137     /* software backing store */
138 jsorg71 1372 extern RD_BOOL g_ownbackstore;
139 stargo 603 static Pixmap g_backstore = 0;
140 matty 31
141 astrand 342 /* Moving in single app mode */
142 jsorg71 1372 static RD_BOOL g_moving_wnd;
143 jsorg71 450 static int g_move_x_offset = 0;
144     static int g_move_y_offset = 0;
145 jsorg71 1372 static RD_BOOL g_using_full_workarea = False;
146 astrand 342
147 matthewc 474 #ifdef WITH_RDPSND
148 jsorg71 1372 extern RD_BOOL g_rdpsnd;
149 matthewc 474 #endif
150    
151 astrand 262 /* MWM decorations */
152     #define MWM_HINTS_DECORATIONS (1L << 1)
153     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
154     typedef struct
155     {
156 astrand 1033 unsigned long flags;
157     unsigned long functions;
158     unsigned long decorations;
159     long inputMode;
160     unsigned long status;
161 astrand 262 }
162     PropMotifWmHints;
163    
164 jsorg71 316 typedef struct
165     {
166     uint32 red;
167     uint32 green;
168     uint32 blue;
169     }
170     PixelColour;
171 astrand 262
172 astrand 1199 #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
173     do { \
174     seamless_window *sw; \
175     XRectangle rect; \
176     if (!g_seamless_windows) break; \
177     for (sw = g_seamless_windows; sw; sw = sw->next) { \
178     rect.x = g_clip_rectangle.x - sw->xoffset; \
179     rect.y = g_clip_rectangle.y - sw->yoffset; \
180     rect.width = g_clip_rectangle.width; \
181     rect.height = g_clip_rectangle.height; \
182     XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
183     func args; \
184     } \
185     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
186     } while (0)
187 forsberg 415
188 astrand 1199 static void
189     seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
190     {
191     points[0].x -= xoffset;
192     points[0].y -= yoffset;
193     XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
194     points[0].x += xoffset;
195     points[0].y += yoffset;
196     }
197    
198     static void
199     seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
200     {
201     points[0].x -= xoffset;
202     points[0].y -= yoffset;
203     XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
204     points[0].x += xoffset;
205     points[0].y += yoffset;
206     }
207    
208 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
209     { \
210 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
211 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
212 jsorg71 450 if (g_ownbackstore) \
213     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
214 matty 31 }
215    
216 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
217 jsorg71 281 { \
218 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
219 jsorg71 281 }
220    
221 jdmeijer 831 #define FILL_POLYGON(p,np)\
222     { \
223     XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
224     if (g_ownbackstore) \
225     XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
226 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
227 jdmeijer 831 }
228    
229     #define DRAW_ELLIPSE(x,y,cx,cy,m)\
230     { \
231     switch (m) \
232     { \
233     case 0: /* Outline */ \
234     XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
235 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
236 jdmeijer 831 if (g_ownbackstore) \
237     XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
238     break; \
239     case 1: /* Filled */ \
240 jsorg71 1022 XFillArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
241 astrand 1249 ON_ALL_SEAMLESS_WINDOWS(XFillArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
242 jdmeijer 831 if (g_ownbackstore) \
243 jsorg71 1022 XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
244 jdmeijer 831 break; \
245     } \
246     }
247    
248 matty 33 /* colour maps */
249 jsorg71 1372 extern RD_BOOL g_owncolmap;
250 jsorg71 450 static Colormap g_xcolmap;
251     static uint32 *g_colmap = NULL;
252 matty 10
253 astrand 1042 #define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
254 jsorg71 450 #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
255     #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
256 matty 28
257     static int rop2_map[] = {
258     GXclear, /* 0 */
259     GXnor, /* DPon */
260     GXandInverted, /* DPna */
261     GXcopyInverted, /* Pn */
262     GXandReverse, /* PDna */
263     GXinvert, /* Dn */
264     GXxor, /* DPx */
265     GXnand, /* DPan */
266     GXand, /* DPa */
267     GXequiv, /* DPxn */
268     GXnoop, /* D */
269     GXorInverted, /* DPno */
270     GXcopy, /* P */
271     GXorReverse, /* PDno */
272     GXor, /* DPo */
273     GXset /* 1 */
274     };
275    
276 jsorg71 450 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
277     #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
278 matty 29
279 astrand 1199 static seamless_window *
280     sw_get_window_by_id(unsigned long id)
281     {
282     seamless_window *sw;
283     for (sw = g_seamless_windows; sw; sw = sw->next)
284     {
285     if (sw->id == id)
286     return sw;
287     }
288     return NULL;
289     }
290    
291    
292     static seamless_window *
293     sw_get_window_by_wnd(Window wnd)
294     {
295     seamless_window *sw;
296     for (sw = g_seamless_windows; sw; sw = sw->next)
297     {
298     if (sw->wnd == wnd)
299     return sw;
300     }
301     return NULL;
302     }
303    
304    
305 astrand 319 static void
306 astrand 1199 sw_remove_window(seamless_window * win)
307 astrand 262 {
308 astrand 1199 seamless_window *sw, **prevnext = &g_seamless_windows;
309     for (sw = g_seamless_windows; sw; sw = sw->next)
310     {
311     if (sw == win)
312     {
313     *prevnext = sw->next;
314     sw->group->refcnt--;
315     if (sw->group->refcnt == 0)
316     {
317     XDestroyWindow(g_display, sw->group->wnd);
318     xfree(sw->group);
319     }
320     xfree(sw->position_timer);
321     xfree(sw);
322     return;
323     }
324     prevnext = &sw->next;
325     }
326     return;
327     }
328    
329    
330     /* Move all windows except wnd to new desktop */
331     static void
332     sw_all_to_desktop(Window wnd, unsigned int desktop)
333     {
334     seamless_window *sw;
335     for (sw = g_seamless_windows; sw; sw = sw->next)
336     {
337     if (sw->wnd == wnd)
338     continue;
339     if (sw->desktop != desktop)
340     {
341     ewmh_move_to_desktop(sw->wnd, desktop);
342     sw->desktop = desktop;
343     }
344     }
345     }
346    
347    
348     /* Send our position */
349     static void
350     sw_update_position(seamless_window * sw)
351     {
352     XWindowAttributes wa;
353     int x, y;
354     Window child_return;
355     unsigned int serial;
356    
357     XGetWindowAttributes(g_display, sw->wnd, &wa);
358     XTranslateCoordinates(g_display, sw->wnd, wa.root,
359     -wa.border_width, -wa.border_width, &x, &y, &child_return);
360    
361     serial = seamless_send_position(sw->id, x, y, wa.width, wa.height, 0);
362    
363     sw->outstanding_position = True;
364     sw->outpos_serial = serial;
365    
366     sw->outpos_xoffset = x;
367     sw->outpos_yoffset = y;
368     sw->outpos_width = wa.width;
369     sw->outpos_height = wa.height;
370     }
371    
372    
373     /* Check if it's time to send our position */
374     static void
375     sw_check_timers()
376     {
377     seamless_window *sw;
378     struct timeval now;
379    
380     gettimeofday(&now, NULL);
381     for (sw = g_seamless_windows; sw; sw = sw->next)
382     {
383     if (timerisset(sw->position_timer) && timercmp(sw->position_timer, &now, <))
384     {
385     timerclear(sw->position_timer);
386     sw_update_position(sw);
387     }
388     }
389     }
390    
391    
392     static void
393     sw_restack_window(seamless_window * sw, unsigned long behind)
394     {
395     seamless_window *sw_above;
396    
397     /* Remove window from stack */
398     for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
399     {
400     if (sw_above->behind == sw->id)
401     break;
402     }
403    
404     if (sw_above)
405     sw_above->behind = sw->behind;
406    
407     /* And then add it at the new position */
408     for (sw_above = g_seamless_windows; sw_above; sw_above = sw_above->next)
409     {
410     if (sw_above->behind == behind)
411     break;
412     }
413    
414     if (sw_above)
415     sw_above->behind = sw->id;
416    
417     sw->behind = behind;
418     }
419    
420    
421     static void
422     sw_handle_restack(seamless_window * sw)
423     {
424     Status status;
425     Window root, parent, *children;
426     unsigned int nchildren, i;
427     seamless_window *sw_below;
428    
429     status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
430     &root, &parent, &children, &nchildren);
431     if (!status || !nchildren)
432     return;
433    
434     sw_below = NULL;
435    
436     i = 0;
437     while (children[i] != sw->wnd)
438     {
439     i++;
440     if (i >= nchildren)
441     goto end;
442     }
443    
444     for (i++; i < nchildren; i++)
445     {
446     sw_below = sw_get_window_by_wnd(children[i]);
447     if (sw_below)
448     break;
449     }
450    
451     if (!sw_below && !sw->behind)
452     goto end;
453     if (sw_below && (sw_below->id == sw->behind))
454     goto end;
455    
456     if (sw_below)
457     {
458     seamless_send_zchange(sw->id, sw_below->id, 0);
459     sw_restack_window(sw, sw_below->id);
460     }
461     else
462     {
463     seamless_send_zchange(sw->id, 0, 0);
464     sw_restack_window(sw, 0);
465     }
466    
467     end:
468     XFree(children);
469     }
470    
471    
472     static seamless_group *
473 jsorg71 1372 sw_find_group(unsigned long id, RD_BOOL dont_create)
474 astrand 1199 {
475     seamless_window *sw;
476     seamless_group *sg;
477     XSetWindowAttributes attribs;
478    
479     for (sw = g_seamless_windows; sw; sw = sw->next)
480     {
481     if (sw->group->id == id)
482     return sw->group;
483     }
484    
485     if (dont_create)
486     return NULL;
487    
488     sg = xmalloc(sizeof(seamless_group));
489    
490     sg->wnd =
491     XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0,
492     CopyFromParent, CopyFromParent, CopyFromParent, 0, &attribs);
493    
494     sg->id = id;
495     sg->refcnt = 0;
496    
497     return sg;
498     }
499    
500    
501     static void
502     mwm_hide_decorations(Window wnd)
503     {
504 astrand 262 PropMotifWmHints motif_hints;
505     Atom hintsatom;
506    
507     /* setup the property */
508     motif_hints.flags = MWM_HINTS_DECORATIONS;
509     motif_hints.decorations = 0;
510    
511     /* get the atom for the property */
512 jsorg71 450 hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
513 astrand 262 if (!hintsatom)
514     {
515 matthewc 297 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
516 astrand 262 return;
517     }
518    
519 astrand 1199 XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
520 astrand 262 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
521 astrand 1199
522 astrand 262 }
523    
524 jdmeijer 821 #define SPLITCOLOUR15(colour, rv) \
525     { \
526     rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
527     rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
528     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
529 jsorg71 311 }
530    
531 jdmeijer 821 #define SPLITCOLOUR16(colour, rv) \
532     { \
533     rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
534     rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
535     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
536     } \
537 jsorg71 311
538 jdmeijer 821 #define SPLITCOLOUR24(colour, rv) \
539     { \
540     rv.blue = (colour & 0xff0000) >> 16; \
541     rv.green = (colour & 0x00ff00) >> 8; \
542     rv.red = (colour & 0x0000ff); \
543 jsorg71 311 }
544    
545 jdmeijer 821 #define MAKECOLOUR(pc) \
546     ((pc.red >> g_red_shift_r) << g_red_shift_l) \
547     | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
548     | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
549 jsorg71 316
550 jsorg71 311 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
551 stargo 534 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
552 jsorg71 311 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
553     x = (x << 16) | (x >> 16); }
554    
555 astrand 1049 /* The following macros output the same octet sequences
556     on both BE and LE hosts: */
557    
558 jdmeijer 821 #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
559     #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
560     #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
561     #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
562     #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
563     #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
564    
565 jsorg71 311 static uint32
566     translate_colour(uint32 colour)
567     {
568 matthewc 527 PixelColour pc;
569 astrand 1042 switch (g_server_depth)
570 jsorg71 311 {
571 jsorg71 316 case 15:
572 jdmeijer 821 SPLITCOLOUR15(colour, pc);
573 jsorg71 316 break;
574 jsorg71 311 case 16:
575 jdmeijer 821 SPLITCOLOUR16(colour, pc);
576 jsorg71 311 break;
577     case 24:
578 jdmeijer 821 SPLITCOLOUR24(colour, pc);
579 jsorg71 311 break;
580 astrand 1042 default:
581     /* Avoid warning */
582     pc.red = 0;
583     pc.green = 0;
584     pc.blue = 0;
585     break;
586 jsorg71 311 }
587 jdmeijer 821 return MAKECOLOUR(pc);
588 jsorg71 311 }
589    
590 jsorg71 709 /* indent is confused by UNROLL8 */
591     /* *INDENT-OFF* */
592    
593     /* repeat and unroll, similar to bitmap.c */
594     /* potentialy any of the following translate */
595     /* functions can use repeat but just doing */
596     /* the most common ones */
597    
598 jsorg71 679 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
599 jsorg71 709 /* 2 byte output repeat */
600     #define REPEAT2(stm) \
601 jsorg71 679 { \
602 jsorg71 709 while (out <= end - 8 * 2) \
603     UNROLL8(stm) \
604     while (out < end) \
605     { stm } \
606     }
607 jdmeijer 821 /* 3 byte output repeat */
608     #define REPEAT3(stm) \
609     { \
610     while (out <= end - 8 * 3) \
611     UNROLL8(stm) \
612     while (out < end) \
613     { stm } \
614     }
615 jsorg71 709 /* 4 byte output repeat */
616     #define REPEAT4(stm) \
617     { \
618 jsorg71 679 while (out <= end - 8 * 4) \
619     UNROLL8(stm) \
620     while (out < end) \
621     { stm } \
622     }
623 jdmeijer 821 /* *INDENT-ON* */
624 jsorg71 679
625 matty 28 static void
626 jdmeijer 821 translate8to8(const uint8 * data, uint8 * out, uint8 * end)
627 matty 28 {
628 matty 29 while (out < end)
629 jsorg71 450 *(out++) = (uint8) g_colmap[*(data++)];
630 matty 29 }
631 matty 28
632 matty 29 static void
633 jdmeijer 821 translate8to16(const uint8 * data, uint8 * out, uint8 * end)
634 matty 29 {
635 stargo 521 uint16 value;
636    
637 astrand 1049 if (g_compatible_arch)
638 stargo 521 {
639 jdmeijer 821 /* *INDENT-OFF* */
640 jsorg71 709 REPEAT2
641     (
642     *((uint16 *) out) = g_colmap[*(data++)];
643     out += 2;
644     )
645 jdmeijer 821 /* *INDENT-ON* */
646 jsorg71 643 }
647 jsorg71 709 else if (g_xserver_be)
648 jsorg71 643 {
649 jsorg71 709 while (out < end)
650     {
651     value = (uint16) g_colmap[*(data++)];
652 jdmeijer 821 BOUT16(out, value);
653 jsorg71 709 }
654 stargo 521 }
655 jsorg71 709 else
656     {
657     while (out < end)
658     {
659     value = (uint16) g_colmap[*(data++)];
660 jdmeijer 821 LOUT16(out, value);
661 jsorg71 709 }
662     }
663 matty 29 }
664    
665 jsorg71 316 /* little endian - conversion happens when colourmap is built */
666 jsorg71 311 static void
667 jdmeijer 821 translate8to24(const uint8 * data, uint8 * out, uint8 * end)
668 jsorg71 311 {
669 jsorg71 316 uint32 value;
670    
671 astrand 1049 if (g_compatible_arch)
672 jsorg71 316 {
673 jsorg71 643 while (out < end)
674 stargo 521 {
675 jsorg71 643 value = g_colmap[*(data++)];
676 jdmeijer 821 BOUT24(out, value);
677 stargo 521 }
678 jsorg71 643 }
679     else
680     {
681     while (out < end)
682 stargo 521 {
683 jsorg71 643 value = g_colmap[*(data++)];
684 jdmeijer 821 LOUT24(out, value);
685 stargo 521 }
686 jsorg71 316 }
687 jsorg71 311 }
688    
689 matty 29 static void
690 jdmeijer 821 translate8to32(const uint8 * data, uint8 * out, uint8 * end)
691 matty 29 {
692 stargo 521 uint32 value;
693    
694 astrand 1049 if (g_compatible_arch)
695 stargo 521 {
696 jdmeijer 821 /* *INDENT-OFF* */
697 jsorg71 709 REPEAT4
698     (
699     *((uint32 *) out) = g_colmap[*(data++)];
700     out += 4;
701     )
702 jdmeijer 821 /* *INDENT-ON* */
703 jsorg71 643 }
704 jsorg71 709 else if (g_xserver_be)
705 jsorg71 643 {
706 jsorg71 709 while (out < end)
707     {
708     value = g_colmap[*(data++)];
709 jdmeijer 821 BOUT32(out, value);
710 jsorg71 709 }
711 stargo 521 }
712 jsorg71 709 else
713     {
714     while (out < end)
715     {
716     value = g_colmap[*(data++)];
717 jdmeijer 821 LOUT32(out, value);
718 jsorg71 709 }
719     }
720 jsorg71 316 }
721    
722     static void
723 jdmeijer 821 translate15to16(const uint16 * data, uint8 * out, uint8 * end)
724 jsorg71 316 {
725 jsorg71 483 uint16 pixel;
726     uint16 value;
727 jdmeijer 821 PixelColour pc;
728 jsorg71 483
729 jdmeijer 821 if (g_xserver_be)
730 jsorg71 483 {
731 jdmeijer 821 while (out < end)
732 jsorg71 483 {
733 jdmeijer 821 pixel = *(data++);
734     if (g_host_be)
735     {
736     BSWAP16(pixel);
737     }
738     SPLITCOLOUR15(pixel, pc);
739     value = MAKECOLOUR(pc);
740     BOUT16(out, value);
741 stargo 521 }
742 jdmeijer 821 }
743     else
744     {
745     while (out < end)
746 jsorg71 483 {
747 jdmeijer 821 pixel = *(data++);
748     if (g_host_be)
749     {
750     BSWAP16(pixel);
751     }
752     SPLITCOLOUR15(pixel, pc);
753     value = MAKECOLOUR(pc);
754     LOUT16(out, value);
755 jsorg71 483 }
756     }
757 jsorg71 316 }
758    
759     static void
760 jdmeijer 821 translate15to24(const uint16 * data, uint8 * out, uint8 * end)
761 jsorg71 316 {
762 matty 29 uint32 value;
763 jsorg71 483 uint16 pixel;
764 jdmeijer 821 PixelColour pc;
765 matty 29
766 astrand 1049 if (g_compatible_arch)
767 matty 28 {
768 jdmeijer 821 /* *INDENT-OFF* */
769     REPEAT3
770     (
771     pixel = *(data++);
772     SPLITCOLOUR15(pixel, pc);
773     *(out++) = pc.blue;
774     *(out++) = pc.green;
775     *(out++) = pc.red;
776     )
777     /* *INDENT-ON* */
778     }
779     else if (g_xserver_be)
780     {
781     while (out < end)
782 jsorg71 483 {
783 jdmeijer 821 pixel = *(data++);
784     if (g_host_be)
785     {
786     BSWAP16(pixel);
787     }
788     SPLITCOLOUR15(pixel, pc);
789     value = MAKECOLOUR(pc);
790     BOUT24(out, value);
791 stargo 521 }
792 jdmeijer 821 }
793     else
794     {
795     while (out < end)
796 jsorg71 483 {
797 jdmeijer 821 pixel = *(data++);
798     if (g_host_be)
799     {
800     BSWAP16(pixel);
801     }
802     SPLITCOLOUR15(pixel, pc);
803     value = MAKECOLOUR(pc);
804     LOUT24(out, value);
805 jsorg71 483 }
806 matty 28 }
807     }
808    
809     static void
810 jdmeijer 821 translate15to32(const uint16 * data, uint8 * out, uint8 * end)
811 jsorg71 316 {
812 jsorg71 472 uint16 pixel;
813 jsorg71 483 uint32 value;
814 jdmeijer 821 PixelColour pc;
815 jsorg71 472
816 astrand 1049 if (g_compatible_arch)
817 jsorg71 472 {
818 jdmeijer 821 /* *INDENT-OFF* */
819     REPEAT4
820     (
821     pixel = *(data++);
822     SPLITCOLOUR15(pixel, pc);
823     *(out++) = pc.blue;
824     *(out++) = pc.green;
825     *(out++) = pc.red;
826     *(out++) = 0;
827     )
828     /* *INDENT-ON* */
829     }
830     else if (g_xserver_be)
831     {
832     while (out < end)
833 jsorg71 472 {
834 jdmeijer 821 pixel = *(data++);
835     if (g_host_be)
836     {
837     BSWAP16(pixel);
838     }
839     SPLITCOLOUR15(pixel, pc);
840     value = MAKECOLOUR(pc);
841     BOUT32(out, value);
842 jsorg71 472 }
843 jdmeijer 821 }
844     else
845     {
846     while (out < end)
847 jsorg71 483 {
848 jdmeijer 821 pixel = *(data++);
849     if (g_host_be)
850     {
851     BSWAP16(pixel);
852     }
853     SPLITCOLOUR15(pixel, pc);
854     value = MAKECOLOUR(pc);
855     LOUT32(out, value);
856 jsorg71 483 }
857 jsorg71 472 }
858 jsorg71 316 }
859    
860     static void
861 jdmeijer 821 translate16to16(const uint16 * data, uint8 * out, uint8 * end)
862 jsorg71 316 {
863 matthewc 528 uint16 pixel;
864 jsorg71 483 uint16 value;
865 jdmeijer 821 PixelColour pc;
866 jsorg71 483
867 jdmeijer 821 if (g_xserver_be)
868 jsorg71 483 {
869 matthewc 528 if (g_host_be)
870 jsorg71 483 {
871 jdmeijer 821 while (out < end)
872     {
873     pixel = *(data++);
874     BSWAP16(pixel);
875     SPLITCOLOUR16(pixel, pc);
876     value = MAKECOLOUR(pc);
877     BOUT16(out, value);
878     }
879 jsorg71 483 }
880 jdmeijer 821 else
881 jsorg71 483 {
882 jdmeijer 821 while (out < end)
883     {
884     pixel = *(data++);
885     SPLITCOLOUR16(pixel, pc);
886     value = MAKECOLOUR(pc);
887     BOUT16(out, value);
888     }
889 jsorg71 483 }
890 jdmeijer 821 }
891     else
892     {
893     if (g_host_be)
894     {
895     while (out < end)
896     {
897     pixel = *(data++);
898     BSWAP16(pixel);
899     SPLITCOLOUR16(pixel, pc);
900     value = MAKECOLOUR(pc);
901     LOUT16(out, value);
902     }
903     }
904 matthewc 528 else
905     {
906 jdmeijer 821 while (out < end)
907     {
908     pixel = *(data++);
909     SPLITCOLOUR16(pixel, pc);
910     value = MAKECOLOUR(pc);
911     LOUT16(out, value);
912     }
913 matthewc 528 }
914 jsorg71 483 }
915 jsorg71 316 }
916    
917     static void
918 jdmeijer 821 translate16to24(const uint16 * data, uint8 * out, uint8 * end)
919 matty 28 {
920 jsorg71 311 uint32 value;
921 jsorg71 483 uint16 pixel;
922 jdmeijer 821 PixelColour pc;
923 jsorg71 311
924 astrand 1049 if (g_compatible_arch)
925 jsorg71 311 {
926 jdmeijer 821 /* *INDENT-OFF* */
927     REPEAT3
928     (
929     pixel = *(data++);
930     SPLITCOLOUR16(pixel, pc);
931     *(out++) = pc.blue;
932     *(out++) = pc.green;
933     *(out++) = pc.red;
934     )
935     /* *INDENT-ON* */
936     }
937     else if (g_xserver_be)
938     {
939 jsorg71 483 if (g_host_be)
940     {
941 jdmeijer 821 while (out < end)
942     {
943     pixel = *(data++);
944     BSWAP16(pixel);
945     SPLITCOLOUR16(pixel, pc);
946     value = MAKECOLOUR(pc);
947     BOUT24(out, value);
948     }
949 stargo 521 }
950 jdmeijer 821 else
951 jsorg71 483 {
952 jdmeijer 821 while (out < end)
953     {
954     pixel = *(data++);
955     SPLITCOLOUR16(pixel, pc);
956     value = MAKECOLOUR(pc);
957     BOUT24(out, value);
958     }
959 jsorg71 483 }
960 jdmeijer 821 }
961     else
962     {
963     if (g_host_be)
964     {
965     while (out < end)
966     {
967     pixel = *(data++);
968     BSWAP16(pixel);
969     SPLITCOLOUR16(pixel, pc);
970     value = MAKECOLOUR(pc);
971     LOUT24(out, value);
972     }
973     }
974 jsorg71 483 else
975     {
976 jdmeijer 821 while (out < end)
977     {
978     pixel = *(data++);
979     SPLITCOLOUR16(pixel, pc);
980     value = MAKECOLOUR(pc);
981     LOUT24(out, value);
982     }
983 jsorg71 483 }
984 jsorg71 311 }
985     }
986    
987     static void
988 jdmeijer 821 translate16to32(const uint16 * data, uint8 * out, uint8 * end)
989 jsorg71 311 {
990 jsorg71 472 uint16 pixel;
991 jsorg71 483 uint32 value;
992 jdmeijer 821 PixelColour pc;
993 jsorg71 472
994 astrand 1049 if (g_compatible_arch)
995 jsorg71 472 {
996 jdmeijer 821 /* *INDENT-OFF* */
997     REPEAT4
998     (
999     pixel = *(data++);
1000     SPLITCOLOUR16(pixel, pc);
1001     *(out++) = pc.blue;
1002     *(out++) = pc.green;
1003     *(out++) = pc.red;
1004     *(out++) = 0;
1005     )
1006     /* *INDENT-ON* */
1007     }
1008     else if (g_xserver_be)
1009     {
1010 jsorg71 472 if (g_host_be)
1011     {
1012 jdmeijer 821 while (out < end)
1013     {
1014     pixel = *(data++);
1015     BSWAP16(pixel);
1016     SPLITCOLOUR16(pixel, pc);
1017     value = MAKECOLOUR(pc);
1018     BOUT32(out, value);
1019     }
1020 stargo 534 }
1021 jdmeijer 821 else
1022 jsorg71 472 {
1023 stargo 823 while (out < end)
1024 jdmeijer 821 {
1025     pixel = *(data++);
1026     SPLITCOLOUR16(pixel, pc);
1027     value = MAKECOLOUR(pc);
1028     BOUT32(out, value);
1029     }
1030 astrand 499 }
1031 jdmeijer 821 }
1032     else
1033     {
1034     if (g_host_be)
1035     {
1036     while (out < end)
1037     {
1038     pixel = *(data++);
1039     BSWAP16(pixel);
1040     SPLITCOLOUR16(pixel, pc);
1041     value = MAKECOLOUR(pc);
1042     LOUT32(out, value);
1043     }
1044     }
1045 astrand 499 else
1046     {
1047 jdmeijer 821 while (out < end)
1048     {
1049     pixel = *(data++);
1050     SPLITCOLOUR16(pixel, pc);
1051     value = MAKECOLOUR(pc);
1052     LOUT32(out, value);
1053     }
1054 astrand 499 }
1055     }
1056 matty 28 }
1057    
1058 jsorg71 311 static void
1059 jdmeijer 821 translate24to16(const uint8 * data, uint8 * out, uint8 * end)
1060 jsorg71 311 {
1061 jsorg71 316 uint32 pixel = 0;
1062 jsorg71 483 uint16 value;
1063 jdmeijer 821 PixelColour pc;
1064    
1065 jsorg71 311 while (out < end)
1066 jsorg71 316 {
1067     pixel = *(data++) << 16;
1068     pixel |= *(data++) << 8;
1069     pixel |= *(data++);
1070 jdmeijer 821 SPLITCOLOUR24(pixel, pc);
1071     value = MAKECOLOUR(pc);
1072 jsorg71 483 if (g_xserver_be)
1073     {
1074 jdmeijer 821 BOUT16(out, value);
1075 jsorg71 483 }
1076     else
1077     {
1078 jdmeijer 821 LOUT16(out, value);
1079 jsorg71 483 }
1080 jsorg71 316 }
1081 jsorg71 311 }
1082    
1083 jsorg71 316 static void
1084 jdmeijer 821 translate24to24(const uint8 * data, uint8 * out, uint8 * end)
1085 jsorg71 316 {
1086 stargo 534 uint32 pixel;
1087     uint32 value;
1088 jdmeijer 821 PixelColour pc;
1089 stargo 534
1090 jdmeijer 821 if (g_xserver_be)
1091 jsorg71 316 {
1092 jdmeijer 821 while (out < end)
1093 stargo 534 {
1094 jdmeijer 821 pixel = *(data++) << 16;
1095     pixel |= *(data++) << 8;
1096     pixel |= *(data++);
1097     SPLITCOLOUR24(pixel, pc);
1098     value = MAKECOLOUR(pc);
1099     BOUT24(out, value);
1100 stargo 534 }
1101 jdmeijer 821 }
1102     else
1103     {
1104     while (out < end)
1105 stargo 534 {
1106 jdmeijer 821 pixel = *(data++) << 16;
1107     pixel |= *(data++) << 8;
1108     pixel |= *(data++);
1109     SPLITCOLOUR24(pixel, pc);
1110     value = MAKECOLOUR(pc);
1111     LOUT24(out, value);
1112 stargo 534 }
1113 jsorg71 316 }
1114     }
1115    
1116     static void
1117 jdmeijer 821 translate24to32(const uint8 * data, uint8 * out, uint8 * end)
1118 jsorg71 316 {
1119 stargo 534 uint32 pixel;
1120     uint32 value;
1121 jdmeijer 821 PixelColour pc;
1122 stargo 534
1123 astrand 1049 if (g_compatible_arch)
1124 jsorg71 316 {
1125 jdmeijer 821 /* *INDENT-OFF* */
1126 stargo 822 #ifdef NEED_ALIGN
1127 jdmeijer 821 REPEAT4
1128     (
1129     *(out++) = *(data++);
1130     *(out++) = *(data++);
1131     *(out++) = *(data++);
1132     *(out++) = 0;
1133 stargo 822 )
1134 jdmeijer 821 #else
1135 stargo 822 REPEAT4
1136     (
1137 astrand 1041 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
1138 astrand 1040 *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
1139     out += 4;
1140     data += 3;
1141 stargo 822 )
1142 jdmeijer 821 #endif
1143     /* *INDENT-ON* */
1144     }
1145     else if (g_xserver_be)
1146     {
1147     while (out < end)
1148 jsorg71 472 {
1149 jdmeijer 821 pixel = *(data++) << 16;
1150     pixel |= *(data++) << 8;
1151     pixel |= *(data++);
1152     SPLITCOLOUR24(pixel, pc);
1153     value = MAKECOLOUR(pc);
1154     BOUT32(out, value);
1155 jsorg71 472 }
1156 jdmeijer 821 }
1157     else
1158     {
1159     while (out < end)
1160 jsorg71 472 {
1161 jdmeijer 821 pixel = *(data++) << 16;
1162     pixel |= *(data++) << 8;
1163     pixel |= *(data++);
1164     SPLITCOLOUR24(pixel, pc);
1165     value = MAKECOLOUR(pc);
1166     LOUT32(out, value);
1167 jsorg71 472 }
1168 jsorg71 316 }
1169     }
1170    
1171 matty 29 static uint8 *
1172 astrand 64 translate_image(int width, int height, uint8 * data)
1173 matty 28 {
1174 jsorg71 644 int size;
1175     uint8 *out;
1176     uint8 *end;
1177 matty 29
1178 astrand 1042 /*
1179     If RDP depth and X Visual depths match,
1180     and arch(endian) matches, no need to translate:
1181     just return data.
1182     Note: select_visual should've already ensured g_no_translate
1183     is only set for compatible depths, but the RDP depth might've
1184     changed during connection negotiations.
1185     */
1186     if (g_no_translate_image)
1187 jsorg71 645 {
1188 astrand 1042 if ((g_depth == 15 && g_server_depth == 15) ||
1189     (g_depth == 16 && g_server_depth == 16) ||
1190     (g_depth == 24 && g_server_depth == 24))
1191 jsorg71 645 return data;
1192     }
1193 jsorg71 644
1194     size = width * height * (g_bpp / 8);
1195     out = (uint8 *) xmalloc(size);
1196     end = out + size;
1197    
1198 astrand 1042 switch (g_server_depth)
1199 jsorg71 311 {
1200 jsorg71 316 case 24:
1201 jsorg71 450 switch (g_bpp)
1202 jsorg71 316 {
1203     case 32:
1204 jsorg71 483 translate24to32(data, out, end);
1205 jsorg71 316 break;
1206     case 24:
1207     translate24to24(data, out, end);
1208     break;
1209     case 16:
1210 jsorg71 483 translate24to16(data, out, end);
1211 jsorg71 316 break;
1212     }
1213 matty 29 break;
1214     case 16:
1215 jsorg71 450 switch (g_bpp)
1216 jsorg71 316 {
1217     case 32:
1218 jsorg71 483 translate16to32((uint16 *) data, out, end);
1219 jsorg71 316 break;
1220     case 24:
1221     translate16to24((uint16 *) data, out, end);
1222     break;
1223     case 16:
1224 matthewc 528 translate16to16((uint16 *) data, out, end);
1225 jsorg71 316 break;
1226     }
1227 matty 29 break;
1228 jsorg71 316 case 15:
1229 jsorg71 450 switch (g_bpp)
1230 jsorg71 316 {
1231     case 32:
1232 jsorg71 483 translate15to32((uint16 *) data, out, end);
1233 jsorg71 316 break;
1234     case 24:
1235     translate15to24((uint16 *) data, out, end);
1236     break;
1237     case 16:
1238 jsorg71 483 translate15to16((uint16 *) data, out, end);
1239 jsorg71 316 break;
1240     }
1241 matty 29 break;
1242 jsorg71 316 case 8:
1243 jsorg71 450 switch (g_bpp)
1244 jsorg71 316 {
1245     case 8:
1246     translate8to8(data, out, end);
1247     break;
1248     case 16:
1249 stargo 521 translate8to16(data, out, end);
1250 jsorg71 316 break;
1251     case 24:
1252     translate8to24(data, out, end);
1253     break;
1254     case 32:
1255 stargo 521 translate8to32(data, out, end);
1256 jsorg71 316 break;
1257     }
1258 matty 29 break;
1259     }
1260     return out;
1261 matty 28 }
1262    
1263 jsorg71 1372 RD_BOOL
1264 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
1265 astrand 102 {
1266 matthewc 203 int modifierpos, key, keysymMask = 0;
1267 astrand 102 int offset;
1268    
1269 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1270 astrand 102
1271     if (keycode == NoSymbol)
1272     return False;
1273    
1274     for (modifierpos = 0; modifierpos < 8; modifierpos++)
1275     {
1276 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
1277 astrand 102
1278 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
1279 astrand 102 {
1280 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
1281 matthewc 203 keysymMask |= 1 << modifierpos;
1282 astrand 102 }
1283     }
1284    
1285 matthewc 203 return (state & keysymMask) ? True : False;
1286 astrand 102 }
1287    
1288 matthewc 527 static void
1289     calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1290     {
1291     *shift_l = ffs(mask) - 1;
1292     mask >>= *shift_l;
1293     *shift_r = 8 - ffs(mask & ~(mask >> 1));
1294     }
1295    
1296 astrand 1042 /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1297     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1298     */
1299     static unsigned
1300     calculate_mask_weight(uint32 mask)
1301 jsorg71 81 {
1302 astrand 1042 unsigned weight = 0;
1303     do
1304     {
1305     weight += (mask & 1);
1306     }
1307     while (mask >>= 1);
1308     return weight;
1309     }
1310    
1311 jsorg71 1372 static RD_BOOL
1312 stargo 1246 select_visual(int screen_num)
1313 astrand 1042 {
1314 matthewc 121 XPixmapFormatValues *pfm;
1315 astrand 1042 int pixmap_formats_count, visuals_count;
1316 stargo 565 XVisualInfo *vmatches = NULL;
1317     XVisualInfo template;
1318 astrand 1042 int i;
1319     unsigned red_weight, blue_weight, green_weight;
1320 matthewc 121
1321 astrand 1042 red_weight = blue_weight = green_weight = 0;
1322    
1323 astrand 1226 if (g_server_depth == -1)
1324     {
1325     g_server_depth = DisplayPlanes(g_display, DefaultScreen(g_display));
1326     }
1327    
1328 astrand 1042 pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1329     if (pfm == NULL)
1330 jsorg71 81 {
1331 astrand 1042 error("Unable to get list of pixmap formats from display.\n");
1332     XCloseDisplay(g_display);
1333 jsorg71 81 return False;
1334     }
1335 matthewc 121
1336 astrand 1042 /* Search for best TrueColor visual */
1337 stargo 565 template.class = TrueColor;
1338 stargo 1246 template.screen = screen_num;
1339 astrand 1250 vmatches =
1340     XGetVisualInfo(g_display, VisualClassMask | VisualScreenMask, &template,
1341     &visuals_count);
1342 astrand 1042 g_visual = NULL;
1343     g_no_translate_image = False;
1344 astrand 1049 g_compatible_arch = False;
1345 astrand 1042 if (vmatches != NULL)
1346 matthewc 527 {
1347 astrand 1042 for (i = 0; i < visuals_count; ++i)
1348 stargo 565 {
1349 astrand 1042 XVisualInfo *visual_info = &vmatches[i];
1350 jsorg71 1372 RD_BOOL can_translate_to_bpp = False;
1351 astrand 1223 int j;
1352 stargo 565
1353 astrand 1042 /* Try to find a no-translation visual that'll
1354     allow us to use RDP bitmaps directly as ZPixmaps. */
1355     if (!g_xserver_be && (((visual_info->depth == 15) &&
1356     /* R5G5B5 */
1357     (visual_info->red_mask == 0x7c00) &&
1358     (visual_info->green_mask == 0x3e0) &&
1359     (visual_info->blue_mask == 0x1f)) ||
1360     ((visual_info->depth == 16) &&
1361     /* R5G6B5 */
1362     (visual_info->red_mask == 0xf800) &&
1363     (visual_info->green_mask == 0x7e0) &&
1364     (visual_info->blue_mask == 0x1f)) ||
1365     ((visual_info->depth == 24) &&
1366     /* R8G8B8 */
1367     (visual_info->red_mask == 0xff0000) &&
1368     (visual_info->green_mask == 0xff00) &&
1369     (visual_info->blue_mask == 0xff))))
1370     {
1371     g_visual = visual_info->visual;
1372     g_depth = visual_info->depth;
1373 astrand 1049 g_compatible_arch = !g_host_be;
1374 astrand 1042 g_no_translate_image = (visual_info->depth == g_server_depth);
1375     if (g_no_translate_image)
1376     /* We found the best visual */
1377     break;
1378     }
1379     else
1380     {
1381 astrand 1049 g_compatible_arch = False;
1382 astrand 1042 }
1383 jsorg71 644
1384 astrand 1042 if (visual_info->depth > 24)
1385     {
1386     /* Avoid 32-bit visuals and likes like the plague.
1387     They're either untested or proven to work bad
1388     (e.g. nvidia's Composite 32-bit visual).
1389     Most implementation offer a 24-bit visual anyway. */
1390     continue;
1391     }
1392 stargo 565
1393 astrand 1042 /* Only care for visuals, for whose BPPs (not depths!)
1394     we have a translateXtoY function. */
1395     for (j = 0; j < pixmap_formats_count; ++j)
1396     {
1397     if (pfm[j].depth == visual_info->depth)
1398     {
1399     if ((pfm[j].bits_per_pixel == 16) ||
1400     (pfm[j].bits_per_pixel == 24) ||
1401     (pfm[j].bits_per_pixel == 32))
1402     {
1403     can_translate_to_bpp = True;
1404     }
1405     break;
1406     }
1407     }
1408    
1409     /* Prefer formats which have the most colour depth.
1410     We're being truly aristocratic here, minding each
1411     weight on its own. */
1412     if (can_translate_to_bpp)
1413     {
1414     unsigned vis_red_weight =
1415     calculate_mask_weight(visual_info->red_mask);
1416     unsigned vis_green_weight =
1417     calculate_mask_weight(visual_info->green_mask);
1418     unsigned vis_blue_weight =
1419     calculate_mask_weight(visual_info->blue_mask);
1420     if ((vis_red_weight >= red_weight)
1421     && (vis_green_weight >= green_weight)
1422     && (vis_blue_weight >= blue_weight))
1423     {
1424     red_weight = vis_red_weight;
1425     green_weight = vis_green_weight;
1426     blue_weight = vis_blue_weight;
1427     g_visual = visual_info->visual;
1428     g_depth = visual_info->depth;
1429     }
1430     }
1431 stargo 565 }
1432 astrand 1042 XFree(vmatches);
1433 matthewc 527 }
1434 astrand 1042
1435     if (g_visual != NULL)
1436     {
1437     g_owncolmap = False;
1438     calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1439     calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1440     calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1441     }
1442 matthewc 527 else
1443     {
1444 astrand 1042 template.class = PseudoColor;
1445     template.depth = 8;
1446     template.colormap_size = 256;
1447     vmatches =
1448     XGetVisualInfo(g_display,
1449     VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1450     &template, &visuals_count);
1451     if (vmatches == NULL)
1452 matthewc 527 {
1453 astrand 1042 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1454     XCloseDisplay(g_display);
1455     XFree(pfm);
1456 matthewc 527 return False;
1457     }
1458    
1459 astrand 1042 /* we use a colourmap, so the default visual should do */
1460     g_owncolmap = True;
1461     g_visual = vmatches[0].visual;
1462     g_depth = vmatches[0].depth;
1463     }
1464 jsorg71 644
1465 astrand 1042 g_bpp = 0;
1466     for (i = 0; i < pixmap_formats_count; ++i)
1467     {
1468     XPixmapFormatValues *pf = &pfm[i];
1469     if (pf->depth == g_depth)
1470 jdmeijer 821 {
1471 astrand 1042 g_bpp = pf->bits_per_pixel;
1472    
1473     if (g_no_translate_image)
1474 jdmeijer 821 {
1475 astrand 1042 switch (g_server_depth)
1476     {
1477     case 15:
1478     case 16:
1479     if (g_bpp != 16)
1480     g_no_translate_image = False;
1481     break;
1482     case 24:
1483     /* Yes, this will force image translation
1484     on most modern servers which use 32 bits
1485     for R8G8B8. */
1486     if (g_bpp != 24)
1487     g_no_translate_image = False;
1488     break;
1489     default:
1490     g_no_translate_image = False;
1491     break;
1492     }
1493 jdmeijer 821 }
1494    
1495 astrand 1042 /* Pixmap formats list is a depth-to-bpp mapping --
1496     there's just a single entry for every depth,
1497     so we can safely break here */
1498     break;
1499 jdmeijer 821 }
1500 matthewc 527 }
1501 astrand 1042 XFree(pfm);
1502     pfm = NULL;
1503     return True;
1504     }
1505 matthewc 527
1506 astrand 1199 static XErrorHandler g_old_error_handler;
1507    
1508     static int
1509     error_handler(Display * dpy, XErrorEvent * eev)
1510     {
1511     if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1512     {
1513     fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1514     fprintf(stderr,
1515     "This is most likely caused by a broken window manager (commonly KWin).\n");
1516     return 0;
1517     }
1518    
1519     return g_old_error_handler(dpy, eev);
1520     }
1521    
1522 jsorg71 1372 RD_BOOL
1523 astrand 1042 ui_init(void)
1524     {
1525     int screen_num;
1526    
1527     g_display = XOpenDisplay(NULL);
1528     if (g_display == NULL)
1529 matthewc 121 {
1530 astrand 1042 error("Failed to open display: %s\n", XDisplayName(NULL));
1531     return False;
1532 matthewc 121 }
1533    
1534     {
1535 astrand 1042 uint16 endianess_test = 1;
1536 jsorg71 1372 g_host_be = !(RD_BOOL) (*(uint8 *) (&endianess_test));
1537 astrand 1042 }
1538    
1539 astrand 1199 g_old_error_handler = XSetErrorHandler(error_handler);
1540 astrand 1042 g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1541     screen_num = DefaultScreen(g_display);
1542     g_x_socket = ConnectionNumber(g_display);
1543     g_screen = ScreenOfDisplay(g_display, screen_num);
1544     g_depth = DefaultDepthOfScreen(g_screen);
1545    
1546 stargo 1246 if (!select_visual(screen_num))
1547 matthewc 121 return False;
1548 astrand 1042
1549     if (g_no_translate_image)
1550     {
1551     DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1552 matthewc 121 }
1553    
1554 astrand 1042 if (g_server_depth > g_bpp)
1555     {
1556     warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1557     g_server_depth, g_bpp);
1558     }
1559    
1560     DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1561     g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1562    
1563 matthewc 517 if (!g_owncolmap)
1564 n-ki 279 {
1565 astrand 580 g_xcolmap =
1566     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1567     AllocNone);
1568 jsorg71 450 if (g_depth <= 8)
1569 astrand 1042 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1570 n-ki 279 }
1571    
1572 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1573     {
1574 astrand 1042 warning("External BackingStore not available. Using internal.\n");
1575 jsorg71 450 g_ownbackstore = True;
1576 stargo 609 }
1577 matthewc 121
1578 astrand 500 /*
1579     * Determine desktop size
1580     */
1581 astrand 547 if (g_fullscreen)
1582 astrand 263 {
1583 astrand 547 g_width = WidthOfScreen(g_screen);
1584     g_height = HeightOfScreen(g_screen);
1585 astrand 1057 g_using_full_workarea = True;
1586 astrand 547 }
1587     else if (g_width < 0)
1588     {
1589 astrand 500 /* Percent of screen */
1590 astrand 991 if (-g_width >= 100)
1591     g_using_full_workarea = True;
1592 astrand 500 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1593     g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1594     }
1595     else if (g_width == 0)
1596     {
1597 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1598 matthewc 300 uint32 x, y, cx, cy;
1599     if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1600 astrand 263 {
1601 jsorg71 447 g_width = cx;
1602     g_height = cy;
1603 astrand 1057 g_using_full_workarea = True;
1604 matthewc 300 }
1605     else
1606     {
1607 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1608 astrand 1057 g_width = WidthOfScreen(g_screen);
1609     g_height = HeightOfScreen(g_screen);
1610 astrand 263 }
1611     }
1612 matthewc 121
1613 matthewc 160 /* make sure width is a multiple of 4 */
1614 jsorg71 447 g_width = (g_width + 3) & ~3;
1615 matthewc 160
1616 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1617 matthewc 203
1618 astrand 498 xkeymap_init();
1619    
1620 jsorg71 447 if (g_enable_compose)
1621 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1622 matthewc 188
1623 matthewc 432 xclip_init();
1624 astrand 1199 ewmh_init();
1625     if (g_seamless_rdp)
1626     seamless_init();
1627 jsorg71 316
1628 astrand 1042 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1629 jsorg71 316
1630 jsorg71 81 return True;
1631     }
1632 astrand 66
1633 matthewc 188 void
1634 matthewc 192 ui_deinit(void)
1635 matthewc 188 {
1636 astrand 1199 while (g_seamless_windows)
1637     {
1638     XDestroyWindow(g_display, g_seamless_windows->wnd);
1639     sw_remove_window(g_seamless_windows);
1640     }
1641    
1642 ossman_ 1214 xclip_deinit();
1643    
1644 jsorg71 450 if (g_IM != NULL)
1645     XCloseIM(g_IM);
1646 astrand 580
1647 stargo 576 if (g_null_cursor != NULL)
1648     ui_destroy_cursor(g_null_cursor);
1649 matthewc 188
1650 jsorg71 450 XFreeModifiermap(g_mod_map);
1651 matthewc 203
1652 jsorg71 450 if (g_ownbackstore)
1653     XFreePixmap(g_display, g_backstore);
1654 matthewc 188
1655 jsorg71 450 XFreeGC(g_display, g_gc);
1656     XCloseDisplay(g_display);
1657     g_display = NULL;
1658 matthewc 188 }
1659    
1660 astrand 1199
1661     static void
1662     get_window_attribs(XSetWindowAttributes * attribs)
1663     {
1664     attribs->background_pixel = BlackPixelOfScreen(g_screen);
1665     attribs->background_pixel = WhitePixelOfScreen(g_screen);
1666     attribs->border_pixel = WhitePixelOfScreen(g_screen);
1667     attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1668     attribs->override_redirect = g_fullscreen;
1669     attribs->colormap = g_xcolmap;
1670     }
1671    
1672     static void
1673     get_input_mask(long *input_mask)
1674     {
1675     *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1676     VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1677    
1678     if (g_sendmotion)
1679     *input_mask |= PointerMotionMask;
1680     if (g_ownbackstore)
1681     *input_mask |= ExposureMask;
1682     if (g_fullscreen || g_grab_keyboard)
1683     *input_mask |= EnterWindowMask;
1684     if (g_grab_keyboard)
1685     *input_mask |= LeaveWindowMask;
1686     }
1687    
1688 jsorg71 1372 RD_BOOL
1689 matthewc 192 ui_create_window(void)
1690 matty 6 {
1691 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1692 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1693    
1694 matthewc 121 XSetWindowAttributes attribs;
1695 matty 28 XClassHint *classhints;
1696     XSizeHints *sizehints;
1697 matthewc 188 int wndwidth, wndheight;
1698 matthewc 432 long input_mask, ic_input_mask;
1699 jsorg71 100 XEvent xevent;
1700    
1701 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1702     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1703 matthewc 188
1704 stargo 867 /* Handle -x-y portion of geometry string */
1705     if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1706     g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1707     if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1708     g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1709    
1710 astrand 1199 get_window_attribs(&attribs);
1711 matthewc 188
1712 astrand 801 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1713     wndheight, 0, g_depth, InputOutput, g_visual,
1714     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1715     CWBorderPixel, &attribs);
1716 jsorg71 100
1717 stargo 576 if (g_gc == NULL)
1718 astrand 1199 {
1719 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1720 astrand 1199 ui_reset_clip();
1721     }
1722 stargo 565
1723 jsorg71 725 if (g_create_bitmap_gc == NULL)
1724     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1725    
1726 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
1727 stargo 565 {
1728 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1729 stargo 565
1730     /* clear to prevent rubbish being exposed at startup */
1731     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1732     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1733     }
1734    
1735 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
1736 astrand 1380 ewmh_set_wm_name(g_wnd, g_title);
1737 jsorg71 100
1738 jsorg71 450 if (g_hide_decorations)
1739 astrand 1199 mwm_hide_decorations(g_wnd);
1740 astrand 262
1741 jsorg71 100 classhints = XAllocClassHint();
1742     if (classhints != NULL)
1743     {
1744     classhints->res_name = classhints->res_class = "rdesktop";
1745 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
1746 jsorg71 100 XFree(classhints);
1747     }
1748    
1749     sizehints = XAllocSizeHints();
1750     if (sizehints)
1751     {
1752     sizehints->flags = PMinSize | PMaxSize;
1753 stargo 867 if (g_pos)
1754     sizehints->flags |= PPosition;
1755 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
1756     sizehints->min_height = sizehints->max_height = g_height;
1757 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
1758 jsorg71 100 XFree(sizehints);
1759     }
1760    
1761 astrand 651 if (g_embed_wnd)
1762     {
1763     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1764     }
1765 stargo 636
1766 astrand 1199 get_input_mask(&input_mask);
1767 matthewc 121
1768 jsorg71 450 if (g_IM != NULL)
1769 matthewc 188 {
1770 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1771 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1772 matthewc 188
1773 jsorg71 450 if ((g_IC != NULL)
1774     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1775 matthewc 188 input_mask |= ic_input_mask;
1776     }
1777    
1778 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
1779     XMapWindow(g_display, g_wnd);
1780 jsorg71 100
1781 matthewc 208 /* wait for VisibilityNotify */
1782 astrand 196 do
1783     {
1784 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1785 astrand 196 }
1786 matthewc 208 while (xevent.type != VisibilityNotify);
1787 jsorg71 688 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1788 matthewc 123
1789 jsorg71 447 g_focused = False;
1790     g_mouse_in_wnd = False;
1791 jsorg71 257
1792 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
1793 jsorg71 450 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1794     g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1795     XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1796 astrand 275
1797 astrand 508 /* create invisible 1x1 cursor to be used as null cursor */
1798 stargo 576 if (g_null_cursor == NULL)
1799     g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1800 astrand 508
1801 matty 10 return True;
1802 matty 6 }
1803    
1804 matty 25 void
1805 n-ki 677 ui_resize_window()
1806     {
1807     XSizeHints *sizehints;
1808 jsorg71 708 Pixmap bs;
1809 n-ki 677
1810     sizehints = XAllocSizeHints();
1811     if (sizehints)
1812     {
1813     sizehints->flags = PMinSize | PMaxSize;
1814     sizehints->min_width = sizehints->max_width = g_width;
1815     sizehints->min_height = sizehints->max_height = g_height;
1816     XSetWMNormalHints(g_display, g_wnd, sizehints);
1817     XFree(sizehints);
1818     }
1819    
1820     if (!(g_fullscreen || g_embed_wnd))
1821     {
1822     XResizeWindow(g_display, g_wnd, g_width, g_height);
1823     }
1824 jsorg71 708
1825     /* create new backstore pixmap */
1826     if (g_backstore != 0)
1827     {
1828     bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1829     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1830     XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1831     XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1832     XFreePixmap(g_display, g_backstore);
1833     g_backstore = bs;
1834     }
1835 n-ki 677 }
1836    
1837     void
1838 matthewc 192 ui_destroy_window(void)
1839 matty 6 {
1840 jsorg71 450 if (g_IC != NULL)
1841     XDestroyIC(g_IC);
1842 matty 31
1843 jsorg71 450 XDestroyWindow(g_display, g_wnd);
1844 matty 6 }
1845    
1846 jsorg71 100 void
1847 matthewc 192 xwin_toggle_fullscreen(void)
1848 jsorg71 100 {
1849 matthewc 188 Pixmap contents = 0;
1850 matthewc 123
1851 astrand 1199 if (g_seamless_active)
1852     /* Turn off SeamlessRDP mode */
1853     ui_seamless_toggle();
1854    
1855 jsorg71 450 if (!g_ownbackstore)
1856 matthewc 188 {
1857     /* need to save contents of window */
1858 jsorg71 450 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1859     XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1860 matthewc 188 }
1861    
1862     ui_destroy_window();
1863 jsorg71 447 g_fullscreen = !g_fullscreen;
1864 matthewc 188 ui_create_window();
1865 matthewc 123
1866 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
1867 matthewc 188
1868 jsorg71 450 if (!g_ownbackstore)
1869 matthewc 188 {
1870 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1871     XFreePixmap(g_display, contents);
1872 matthewc 188 }
1873 jsorg71 100 }
1874    
1875 astrand 988 static void
1876 jsorg71 1372 handle_button_event(XEvent xevent, RD_BOOL down)
1877 astrand 988 {
1878     uint16 button, flags = 0;
1879     g_last_gesturetime = xevent.xbutton.time;
1880     button = xkeymap_translate_button(xevent.xbutton.button);
1881     if (button == 0)
1882     return;
1883    
1884     if (down)
1885     flags = MOUSE_FLAG_DOWN;
1886    
1887     /* Stop moving window when button is released, regardless of cursor position */
1888     if (g_moving_wnd && (xevent.type == ButtonRelease))
1889     g_moving_wnd = False;
1890    
1891     /* If win_button_size is nonzero, enable single app mode */
1892     if (xevent.xbutton.y < g_win_button_size)
1893     {
1894     /* Check from right to left: */
1895     if (xevent.xbutton.x >= g_width - g_win_button_size)
1896     {
1897     /* The close button, continue */
1898     ;
1899     }
1900     else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1901     {
1902     /* The maximize/restore button. Do not send to
1903     server. It might be a good idea to change the
1904     cursor or give some other visible indication
1905     that rdesktop inhibited this click */
1906     if (xevent.type == ButtonPress)
1907     return;
1908     }
1909     else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1910     {
1911     /* The minimize button. Iconify window. */
1912     if (xevent.type == ButtonRelease)
1913     {
1914     /* Release the mouse button outside the minimize button, to prevent the
1915     actual minimazation to happen */
1916     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1917     XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1918     return;
1919     }
1920     }
1921     else if (xevent.xbutton.x <= g_win_button_size)
1922     {
1923     /* The system menu. Ignore. */
1924     if (xevent.type == ButtonPress)
1925     return;
1926     }
1927     else
1928     {
1929     /* The title bar. */
1930     if (xevent.type == ButtonPress)
1931     {
1932 astrand 991 if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1933 astrand 988 {
1934     g_moving_wnd = True;
1935     g_move_x_offset = xevent.xbutton.x;
1936     g_move_y_offset = xevent.xbutton.y;
1937     }
1938     return;
1939     }
1940     }
1941     }
1942    
1943 astrand 1199 if (xevent.xmotion.window == g_wnd)
1944     {
1945     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1946     flags | button, xevent.xbutton.x, xevent.xbutton.y);
1947     }
1948     else
1949     {
1950     /* SeamlessRDP */
1951     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1952     flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1953     }
1954 astrand 988 }
1955    
1956 astrand 1199
1957 stargo 887 /* Process events in Xlib queue
1958 astrand 275 Returns 0 after user quit, 1 otherwise */
1959     static int
1960 matthewc 192 xwin_process_events(void)
1961 matty 9 {
1962 n-ki 54 XEvent xevent;
1963 matthewc 38 KeySym keysym;
1964 matty 10 uint32 ev_time;
1965 astrand 66 char str[256];
1966     Status status;
1967 stargo 887 int events = 0;
1968 astrand 1199 seamless_window *sw;
1969 matty 9
1970 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
1971 matty 9 {
1972 jsorg71 450 XNextEvent(g_display, &xevent);
1973 matthewc 123
1974 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1975 astrand 66 {
1976 astrand 84 DEBUG_KBD(("Filtering event\n"));
1977 astrand 66 continue;
1978     }
1979    
1980 n-ki 54 switch (xevent.type)
1981 matty 9 {
1982 jsorg71 688 case VisibilityNotify:
1983 astrand 1199 if (xevent.xvisibility.window == g_wnd)
1984     g_Unobscured =
1985     xevent.xvisibility.state == VisibilityUnobscured;
1986    
1987 jsorg71 688 break;
1988 astrand 275 case ClientMessage:
1989     /* the window manager told us to quit */
1990 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
1991     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1992 astrand 275 /* Quit */
1993     return 0;
1994     break;
1995    
1996 matty 9 case KeyPress:
1997 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1998     if (g_IC != NULL)
1999 astrand 66 /* Multi_key compatible version */
2000     {
2001 jsorg71 450 XmbLookupString(g_IC,
2002 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
2003     &status);
2004 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
2005 astrand 66 {
2006 astrand 82 error("XmbLookupString failed with status 0x%x\n",
2007     status);
2008 astrand 66 break;
2009     }
2010     }
2011     else
2012     {
2013     /* Plain old XLookupString */
2014 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
2015 astrand 66 XLookupString((XKeyEvent *) & xevent,
2016 astrand 82 str, sizeof(str), &keysym, NULL);
2017 astrand 66 }
2018    
2019 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2020 astrand 261 get_ksname(keysym)));
2021 astrand 66
2022 matthewc 203 ev_time = time(NULL);
2023     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2024 astrand 118 break;
2025    
2026 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2027 astrand 976 ev_time, True, 0);
2028 astrand 66 break;
2029 matthewc 203
2030 astrand 66 case KeyRelease:
2031 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
2032 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
2033     sizeof(str), &keysym, NULL);
2034 n-ki 52
2035 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2036 matthewc 203 get_ksname(keysym)));
2037 n-ki 52
2038 matthewc 203 ev_time = time(NULL);
2039     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2040 astrand 118 break;
2041    
2042 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2043 astrand 976 ev_time, False, 0);
2044 matty 9 break;
2045    
2046     case ButtonPress:
2047 astrand 988 handle_button_event(xevent, True);
2048     break;
2049 matty 9
2050     case ButtonRelease:
2051 astrand 988 handle_button_event(xevent, False);
2052 matty 10 break;
2053    
2054     case MotionNotify:
2055 jsorg71 450 if (g_moving_wnd)
2056 astrand 342 {
2057 jsorg71 450 XMoveWindow(g_display, g_wnd,
2058     xevent.xmotion.x_root - g_move_x_offset,
2059     xevent.xmotion.y_root - g_move_y_offset);
2060 astrand 342 break;
2061     }
2062    
2063 jsorg71 447 if (g_fullscreen && !g_focused)
2064 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2065 jsorg71 288 CurrentTime);
2066 astrand 1199
2067     if (xevent.xmotion.window == g_wnd)
2068     {
2069     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2070     xevent.xmotion.x, xevent.xmotion.y);
2071     }
2072     else
2073     {
2074     /* SeamlessRDP */
2075     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2076     xevent.xmotion.x_root,
2077     xevent.xmotion.y_root);
2078     }
2079 matty 28 break;
2080    
2081 matthewc 194 case FocusIn:
2082 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
2083     break;
2084 jsorg71 447 g_focused = True;
2085 astrand 543 reset_modifier_keys();
2086 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
2087     XGrabKeyboard(g_display, g_wnd, True,
2088 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
2089 astrand 1199
2090     sw = sw_get_window_by_wnd(xevent.xfocus.window);
2091     if (!sw)
2092     break;
2093    
2094     if (sw->id != g_seamless_focused)
2095     {
2096     seamless_send_focus(sw->id, 0);
2097     g_seamless_focused = sw->id;
2098     }
2099 matty 28 break;
2100    
2101 matthewc 194 case FocusOut:
2102 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
2103     break;
2104 jsorg71 447 g_focused = False;
2105 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
2106 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2107 matty 28 break;
2108 matty 31
2109 matthewc 250 case EnterNotify:
2110     /* we only register for this event when in fullscreen mode */
2111 jsorg71 257 /* or grab_keyboard */
2112 jsorg71 447 g_mouse_in_wnd = True;
2113     if (g_fullscreen)
2114 jsorg71 257 {
2115 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2116 astrand 261 CurrentTime);
2117 jsorg71 257 break;
2118     }
2119 jsorg71 447 if (g_focused)
2120 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
2121 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
2122 matthewc 250 break;
2123    
2124 matthewc 253 case LeaveNotify:
2125 jsorg71 257 /* we only register for this event when grab_keyboard */
2126 jsorg71 447 g_mouse_in_wnd = False;
2127 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2128 matthewc 253 break;
2129    
2130 matty 31 case Expose:
2131 astrand 1199 if (xevent.xexpose.window == g_wnd)
2132     {
2133     XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2134     g_gc,
2135     xevent.xexpose.x, xevent.xexpose.y,
2136     xevent.xexpose.width, xevent.xexpose.height,
2137     xevent.xexpose.x, xevent.xexpose.y);
2138     }
2139     else
2140     {
2141     sw = sw_get_window_by_wnd(xevent.xexpose.window);
2142     if (!sw)
2143     break;
2144     XCopyArea(g_display, g_backstore,
2145     xevent.xexpose.window, g_gc,
2146     xevent.xexpose.x + sw->xoffset,
2147     xevent.xexpose.y + sw->yoffset,
2148     xevent.xexpose.width,
2149     xevent.xexpose.height, xevent.xexpose.x,
2150     xevent.xexpose.y);
2151     }
2152    
2153 matty 31 break;
2154 astrand 119
2155     case MappingNotify:
2156     /* Refresh keyboard mapping if it has changed. This is important for
2157     Xvnc, since it allocates keycodes dynamically */
2158     if (xevent.xmapping.request == MappingKeyboard
2159     || xevent.xmapping.request == MappingModifier)
2160     XRefreshKeyboardMapping(&xevent.xmapping);
2161 matthewc 203
2162     if (xevent.xmapping.request == MappingModifier)
2163     {
2164 jsorg71 450 XFreeModifiermap(g_mod_map);
2165     g_mod_map = XGetModifierMapping(g_display);
2166 matthewc 203 }
2167 astrand 119 break;
2168 matthewc 432
2169 astrand 435 /* clipboard stuff */
2170 forsberg 415 case SelectionNotify:
2171 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
2172 forsberg 415 break;
2173     case SelectionRequest:
2174 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2175 forsberg 415 break;
2176 matthewc 432 case SelectionClear:
2177     xclip_handle_SelectionClear();
2178     break;
2179 forsberg 415 case PropertyNotify:
2180 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
2181 astrand 1199 if (xevent.xproperty.window == g_wnd)
2182     break;
2183     if (xevent.xproperty.window == DefaultRootWindow(g_display))
2184     break;
2185    
2186     /* seamless */
2187     sw = sw_get_window_by_wnd(xevent.xproperty.window);
2188     if (!sw)
2189     break;
2190    
2191     if ((xevent.xproperty.atom == g_net_wm_state_atom)
2192     && (xevent.xproperty.state == PropertyNewValue))
2193     {
2194     sw->state = ewmh_get_window_state(sw->wnd);
2195     seamless_send_state(sw->id, sw->state, 0);
2196     }
2197    
2198     if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2199     && (xevent.xproperty.state == PropertyNewValue))
2200     {
2201     sw->desktop = ewmh_get_window_desktop(sw->wnd);
2202     sw_all_to_desktop(sw->wnd, sw->desktop);
2203     }
2204    
2205 forsberg 415 break;
2206 jdmeijer 905 case MapNotify:
2207 astrand 1199 if (!g_seamless_active)
2208     rdp_send_client_window_status(1);
2209 jdmeijer 905 break;
2210     case UnmapNotify:
2211 astrand 1199 if (!g_seamless_active)
2212     rdp_send_client_window_status(0);
2213 jdmeijer 905 break;
2214 astrand 1199 case ConfigureNotify:
2215     if (!g_seamless_active)
2216     break;
2217    
2218     sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2219     if (!sw)
2220     break;
2221    
2222     gettimeofday(sw->position_timer, NULL);
2223     if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2224     1000000)
2225     {
2226     sw->position_timer->tv_usec +=
2227     SEAMLESSRDP_POSITION_TIMER - 1000000;
2228     sw->position_timer->tv_sec += 1;
2229     }
2230     else
2231     {
2232     sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2233     }
2234    
2235     sw_handle_restack(sw);
2236     break;
2237 matty 9 }
2238     }
2239 astrand 275 /* Keep going */
2240     return 1;
2241 matty 9 }
2242    
2243 astrand 275 /* Returns 0 after user quit, 1 otherwise */
2244     int
2245 matty 33 ui_select(int rdp_socket)
2246     {
2247 stargo 606 int n;
2248 matthewc 474 fd_set rfds, wfds;
2249 n-ki 592 struct timeval tv;
2250 jsorg71 1372 RD_BOOL s_timeout = False;
2251 matty 33
2252     while (True)
2253     {
2254 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2255 matthewc 121 /* Process any events already waiting */
2256 astrand 275 if (!xwin_process_events())
2257     /* User quit */
2258     return 0;
2259 astrand 119
2260 astrand 1199 if (g_seamless_active)
2261     sw_check_timers();
2262    
2263 matty 33 FD_ZERO(&rfds);
2264 matthewc 474 FD_ZERO(&wfds);
2265 matty 33 FD_SET(rdp_socket, &rfds);
2266 jsorg71 450 FD_SET(g_x_socket, &rfds);
2267 matty 33
2268 n-ki 592 /* default timeout */
2269     tv.tv_sec = 60;
2270     tv.tv_usec = 0;
2271 matthewc 474
2272 ossman_ 1302 #ifdef WITH_RDPSND
2273     rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
2274     #endif
2275    
2276 n-ki 592 /* add redirection handles */
2277     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2278 astrand 1199 seamless_select_timeout(&tv);
2279 n-ki 592
2280     n++;
2281    
2282     switch (select(n, &rfds, &wfds, NULL, &tv))
2283 matthewc 474 {
2284 matty 33 case -1:
2285     error("select: %s\n", strerror(errno));
2286    
2287     case 0:
2288 ossman_ 1302 #ifdef WITH_RDPSND
2289     rdpsnd_check_fds(&rfds, &wfds);
2290     #endif
2291    
2292 stargo 795 /* Abort serial read calls */
2293     if (s_timeout)
2294 jsorg71 1372 rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) True);
2295 matty 33 continue;
2296     }
2297    
2298 ossman_ 1302 #ifdef WITH_RDPSND
2299     rdpsnd_check_fds(&rfds, &wfds);
2300     #endif
2301    
2302 jsorg71 1372 rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
2303 n-ki 592
2304 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2305     return 1;
2306    
2307 matty 33 }
2308     }
2309    
2310     void
2311 matty 25 ui_move_pointer(int x, int y)
2312 matty 9 {
2313 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2314 matty 9 }
2315    
2316 jsorg71 1364 RD_HBITMAP
2317 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2318 matty 6 {
2319     XImage *image;
2320 matty 9 Pixmap bitmap;
2321 matty 28 uint8 *tdata;
2322 stargo 521 int bitmap_pad;
2323 matty 29
2324 astrand 1042 if (g_server_depth == 8)
2325 stargo 521 {
2326     bitmap_pad = 8;
2327     }
2328     else
2329     {
2330     bitmap_pad = g_bpp;
2331    
2332     if (g_bpp == 24)
2333     bitmap_pad = 32;
2334     }
2335    
2336 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2337     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2338     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2339 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2340 matty 6
2341 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2342 matty 9
2343     XFree(image);
2344 jsorg71 644 if (tdata != data)
2345 n-ki 279 xfree(tdata);
2346 jsorg71 1364 return (RD_HBITMAP) bitmap;
2347 matty 6 }
2348    
2349 matty 25 void
2350 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2351 matty 6 {
2352 matty 10 XImage *image;
2353 matty 29 uint8 *tdata;
2354 stargo 521 int bitmap_pad;
2355    
2356 astrand 1042 if (g_server_depth == 8)
2357 stargo 521 {
2358     bitmap_pad = 8;
2359     }
2360     else
2361     {
2362     bitmap_pad = g_bpp;
2363    
2364     if (g_bpp == 24)
2365     bitmap_pad = 32;
2366     }
2367    
2368 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2369     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2370 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2371 matty 28
2372 jsorg71 450 if (g_ownbackstore)
2373 matty 31 {
2374 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2375     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2376 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2377     (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2378     x - sw->xoffset, y - sw->yoffset));
2379 matty 31 }
2380     else
2381     {
2382 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2383 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2384     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2385     x - sw->xoffset, y - sw->yoffset));
2386 matty 31 }
2387 matty 29
2388 matty 24 XFree(image);
2389 jsorg71 644 if (tdata != data)
2390 n-ki 279 xfree(tdata);
2391 matty 6 }
2392    
2393 matty 25 void
2394 jsorg71 1364 ui_destroy_bitmap(RD_HBITMAP bmp)
2395 matty 6 {
2396 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2397 matty 10 }
2398    
2399 jsorg71 1364 RD_HGLYPH
2400 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2401 matty 10 {
2402 matty 9 XImage *image;
2403     Pixmap bitmap;
2404     int scanline;
2405 matty 6
2406 matty 9 scanline = (width + 7) / 8;
2407 matty 6
2408 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2409 jsorg71 725 if (g_create_glyph_gc == 0)
2410     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2411 matty 9
2412 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2413 astrand 73 width, height, 8, scanline);
2414 matty 23 image->byte_order = MSBFirst;
2415     image->bitmap_bit_order = MSBFirst;
2416     XInitImage(image);
2417    
2418 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2419 matty 29
2420 matty 9 XFree(image);
2421 jsorg71 1364 return (RD_HGLYPH) bitmap;
2422 matty 6 }
2423 matty 7
2424 matty 25 void
2425 jsorg71 1364 ui_destroy_glyph(RD_HGLYPH glyph)
2426 matty 7 {
2427 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2428 matty 9 }
2429    
2430 jsorg71 1364 RD_HCURSOR
2431 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2432     uint8 * andmask, uint8 * xormask)
2433 matty 9 {
2434 jsorg71 1364 RD_HGLYPH maskglyph, cursorglyph;
2435 matty 29 XColor bg, fg;
2436     Cursor xcursor;
2437     uint8 *cursor, *pcursor;
2438     uint8 *mask, *pmask;
2439     uint8 nextbit;
2440     int scanline, offset;
2441     int i, j;
2442    
2443     scanline = (width + 7) / 8;
2444     offset = scanline * height;
2445    
2446 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2447 matty 29 memset(cursor, 0, offset);
2448    
2449 forsberg 415 mask = (uint8 *) xmalloc(offset);
2450 matty 29 memset(mask, 0, offset);
2451    
2452     /* approximate AND and XOR masks with a monochrome X pointer */
2453     for (i = 0; i < height; i++)
2454 matty 7 {
2455 matty 29 offset -= scanline;
2456     pcursor = &cursor[offset];
2457     pmask = &mask[offset];
2458    
2459     for (j = 0; j < scanline; j++)
2460 matty 28 {
2461 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2462     {
2463     if (xormask[0] || xormask[1] || xormask[2])
2464     {
2465     *pcursor |= (~(*andmask) & nextbit);
2466     *pmask |= nextbit;
2467     }
2468     else
2469     {
2470     *pcursor |= ((*andmask) & nextbit);
2471     *pmask |= (~(*andmask) & nextbit);
2472     }
2473    
2474     xormask += 3;
2475     }
2476    
2477     andmask++;
2478     pcursor++;
2479     pmask++;
2480 matty 28 }
2481 matty 7 }
2482 matty 29
2483     fg.red = fg.blue = fg.green = 0xffff;
2484     bg.red = bg.blue = bg.green = 0x0000;
2485     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2486    
2487     cursorglyph = ui_create_glyph(width, height, cursor);
2488     maskglyph = ui_create_glyph(width, height, mask);
2489    
2490 astrand 66 xcursor =
2491 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2492 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2493 astrand 64
2494 matty 29 ui_destroy_glyph(maskglyph);
2495     ui_destroy_glyph(cursorglyph);
2496     xfree(mask);
2497     xfree(cursor);
2498 jsorg71 1364 return (RD_HCURSOR) xcursor;
2499 matty 29 }
2500    
2501     void
2502 jsorg71 1364 ui_set_cursor(RD_HCURSOR cursor)
2503 matty 29 {
2504 jsorg71 450 g_current_cursor = (Cursor) cursor;
2505     XDefineCursor(g_display, g_wnd, g_current_cursor);
2506 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2507 matty 29 }
2508    
2509     void
2510 jsorg71 1364 ui_destroy_cursor(RD_HCURSOR cursor)
2511 matty 29 {
2512 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2513 matty 29 }
2514    
2515 astrand 508 void
2516     ui_set_null_cursor(void)
2517     {
2518     ui_set_cursor(g_null_cursor);
2519     }
2520    
2521 matty 29 #define MAKE_XCOLOR(xc,c) \
2522     (xc)->red = ((c)->red << 8) | (c)->red; \
2523     (xc)->green = ((c)->green << 8) | (c)->green; \
2524     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2525     (xc)->flags = DoRed | DoGreen | DoBlue;
2526    
2527 n-ki 279
2528 jsorg71 1364 RD_HCOLOURMAP
2529 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2530 matty 29 {
2531     COLOURENTRY *entry;
2532     int i, ncolours = colours->ncolours;
2533 jsorg71 450 if (!g_owncolmap)
2534 matty 28 {
2535 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2536 n-ki 279 XColor xentry;
2537     XColor xc_cache[256];
2538     uint32 colour;
2539     int colLookup = 256;
2540     for (i = 0; i < ncolours; i++)
2541 matty 28 {
2542 n-ki 279 entry = &colours->colours[i];
2543     MAKE_XCOLOR(&xentry, entry);
2544 matty 7
2545 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2546 astrand 196 {
2547 n-ki 279 /* Allocation failed, find closest match. */
2548     int j = 256;
2549     int nMinDist = 3 * 256 * 256;
2550     long nDist = nMinDist;
2551 matty 28
2552 n-ki 279 /* only get the colors once */
2553     while (colLookup--)
2554 astrand 196 {
2555 n-ki 279 xc_cache[colLookup].pixel = colLookup;
2556     xc_cache[colLookup].red = xc_cache[colLookup].green =
2557     xc_cache[colLookup].blue = 0;
2558     xc_cache[colLookup].flags = 0;
2559 jsorg71 450 XQueryColor(g_display,
2560     DefaultColormap(g_display,
2561     DefaultScreen(g_display)),
2562 n-ki 279 &xc_cache[colLookup]);
2563 n-ki 185 }
2564 n-ki 279 colLookup = 0;
2565    
2566     /* approximate the pixel */
2567     while (j--)
2568 astrand 196 {
2569 n-ki 279 if (xc_cache[j].flags)
2570     {
2571     nDist = ((long) (xc_cache[j].red >> 8) -
2572     (long) (xentry.red >> 8)) *
2573     ((long) (xc_cache[j].red >> 8) -
2574     (long) (xentry.red >> 8)) +
2575     ((long) (xc_cache[j].green >> 8) -
2576     (long) (xentry.green >> 8)) *
2577     ((long) (xc_cache[j].green >> 8) -
2578     (long) (xentry.green >> 8)) +
2579     ((long) (xc_cache[j].blue >> 8) -
2580     (long) (xentry.blue >> 8)) *
2581     ((long) (xc_cache[j].blue >> 8) -
2582     (long) (xentry.blue >> 8));
2583     }
2584     if (nDist < nMinDist)
2585     {
2586     nMinDist = nDist;
2587     xentry.pixel = j;
2588     }
2589 n-ki 185 }
2590     }
2591 n-ki 279 colour = xentry.pixel;
2592    
2593     /* update our cache */
2594     if (xentry.pixel < 256)
2595     {
2596     xc_cache[xentry.pixel].red = xentry.red;
2597     xc_cache[xentry.pixel].green = xentry.green;
2598     xc_cache[xentry.pixel].blue = xentry.blue;
2599    
2600     }
2601    
2602 matthewc 527 map[i] = colour;
2603 n-ki 185 }
2604 n-ki 279 return map;
2605     }
2606     else
2607     {
2608     XColor *xcolours, *xentry;
2609     Colormap map;
2610 matty 29
2611 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2612 n-ki 279 for (i = 0; i < ncolours; i++)
2613 astrand 196 {
2614 n-ki 279 entry = &colours->colours[i];
2615     xentry = &xcolours[i];
2616     xentry->pixel = i;
2617     MAKE_XCOLOR(xentry, entry);
2618 matty 29 }
2619    
2620 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2621     XStoreColors(g_display, map, xcolours, ncolours);
2622 n-ki 185
2623 n-ki 279 xfree(xcolours);
2624 jsorg71 1364 return (RD_HCOLOURMAP) map;
2625 matty 29 }
2626 matty 7 }
2627    
2628 matty 25 void
2629 jsorg71 1364 ui_destroy_colourmap(RD_HCOLOURMAP map)
2630 matty 7 {
2631 jsorg71 450 if (!g_owncolmap)
2632 n-ki 279 xfree(map);
2633     else
2634 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2635 matty 7 }
2636    
2637 matty 25 void
2638 jsorg71 1364 ui_set_colourmap(RD_HCOLOURMAP map)
2639 matty 7 {
2640 jsorg71 450 if (!g_owncolmap)
2641 astrand 448 {
2642 jsorg71 450 if (g_colmap)
2643     xfree(g_colmap);
2644 astrand 448
2645 jsorg71 450 g_colmap = (uint32 *) map;
2646 astrand 448 }
2647 n-ki 279 else
2648 astrand 1199 {
2649 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2650 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2651     }
2652 matty 7 }
2653    
2654 matty 25 void
2655     ui_set_clip(int x, int y, int cx, int cy)
2656 matty 7 {
2657 astrand 1199 g_clip_rectangle.x = x;
2658     g_clip_rectangle.y = y;
2659     g_clip_rectangle.width = cx;
2660     g_clip_rectangle.height = cy;
2661     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2662 matty 9 }
2663 matty 7
2664 matty 25 void
2665 matthewc 192 ui_reset_clip(void)
2666 matty 9 {
2667 astrand 1199 g_clip_rectangle.x = 0;
2668     g_clip_rectangle.y = 0;
2669     g_clip_rectangle.width = g_width;
2670     g_clip_rectangle.height = g_height;
2671     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2672 matty 7 }
2673    
2674 matty 25 void
2675 matthewc 192 ui_bell(void)
2676 matty 10 {
2677 jsorg71 450 XBell(g_display, 0);
2678 matty 10 }
2679    
2680 matty 25 void
2681     ui_destblt(uint8 opcode,
2682     /* dest */ int x, int y, int cx, int cy)
2683 matty 9 {
2684 matty 29 SET_FUNCTION(opcode);
2685 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2686 matty 29 RESET_FUNCTION(opcode);
2687 matty 9 }
2688    
2689 jsorg71 373 static uint8 hatch_patterns[] = {
2690 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2691     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2692     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2693     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2694     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2695     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2696 jsorg71 373 };
2697    
2698 matty 25 void
2699     ui_patblt(uint8 opcode,
2700     /* dest */ int x, int y, int cx, int cy,
2701 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2702 matty 9 {
2703     Pixmap fill;
2704 jsorg71 59 uint8 i, ipattern[8];
2705 matty 9
2706 matty 29 SET_FUNCTION(opcode);
2707 matty 9
2708     switch (brush->style)
2709     {
2710 matty 24 case 0: /* Solid */
2711 matty 29 SET_FOREGROUND(fgcolour);
2712 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2713 matty 9 break;
2714    
2715 jsorg71 373 case 2: /* Hatch */
2716 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2717     hatch_patterns + brush->pattern[0] * 8);
2718 astrand 487 SET_FOREGROUND(fgcolour);
2719     SET_BACKGROUND(bgcolour);
2720 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2721     XSetStipple(g_display, g_gc, fill);
2722     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2723 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2724 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2725     XSetTSOrigin(g_display, g_gc, 0, 0);
2726 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2727 jsorg71 373 break;
2728    
2729 matty 24 case 3: /* Pattern */
2730 jsorg71 59 for (i = 0; i != 8; i++)
2731     ipattern[7 - i] = brush->pattern[i];
2732     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2733 matty 29 SET_FOREGROUND(bgcolour);
2734     SET_BACKGROUND(fgcolour);
2735 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2736     XSetStipple(g_display, g_gc, fill);
2737     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2738 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2739 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2740     XSetTSOrigin(g_display, g_gc, 0, 0);
2741 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2742 matty 9 break;
2743    
2744     default:
2745 matty 30 unimpl("brush %d\n", brush->style);
2746 matty 9 }
2747 matty 29
2748     RESET_FUNCTION(opcode);
2749 jsorg71 680
2750     if (g_ownbackstore)
2751     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2752 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2753     (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2754     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2755 matty 9 }
2756    
2757 matty 25 void
2758     ui_screenblt(uint8 opcode,
2759     /* dest */ int x, int y, int cx, int cy,
2760     /* src */ int srcx, int srcy)
2761 matty 9 {
2762 matty 29 SET_FUNCTION(opcode);
2763 jsorg71 450 if (g_ownbackstore)
2764 stargo 609 {
2765 astrand 1199 XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2766     g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2767     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2768 stargo 609 }
2769     else
2770     {
2771     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2772     }
2773 astrand 1199
2774     ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2775     (g_display, g_ownbackstore ? g_backstore : g_wnd,
2776     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2777    
2778 matty 29 RESET_FUNCTION(opcode);
2779 matty 9 }
2780    
2781 matty 25 void
2782     ui_memblt(uint8 opcode,
2783     /* dest */ int x, int y, int cx, int cy,
2784 jsorg71 1364 /* src */ RD_HBITMAP src, int srcx, int srcy)
2785 matty 9 {
2786 matty 29 SET_FUNCTION(opcode);
2787 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2788 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2789     (g_display, (Pixmap) src, sw->wnd, g_gc,
2790     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2791 jsorg71 450 if (g_ownbackstore)
2792     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2793 matty 29 RESET_FUNCTION(opcode);
2794 matty 9 }
2795    
2796 matty 25 void
2797     ui_triblt(uint8 opcode,
2798     /* dest */ int x, int y, int cx, int cy,
2799 jsorg71 1364 /* src */ RD_HBITMAP src, int srcx, int srcy,
2800 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2801 matty 9 {
2802     /* This is potentially difficult to do in general. Until someone
2803 matty 10 comes up with a more efficient way of doing it I am using cases. */
2804 matty 9
2805     switch (opcode)
2806     {
2807 matty 24 case 0x69: /* PDSxxn */
2808 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2809 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2810 matty 16 break;
2811    
2812 matty 24 case 0xb8: /* PSDPxax */
2813 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2814 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2815 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2816 matty 9 break;
2817    
2818 matty 29 case 0xc0: /* PSa */
2819 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2820 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2821 matty 28 break;
2822    
2823 matty 9 default:
2824 matty 30 unimpl("triblt 0x%x\n", opcode);
2825 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2826 matty 9 }
2827     }
2828    
2829 matty 25 void
2830     ui_line(uint8 opcode,
2831     /* dest */ int startx, int starty, int endx, int endy,
2832 astrand 64 /* pen */ PEN * pen)
2833 matty 9 {
2834 matty 29 SET_FUNCTION(opcode);
2835     SET_FOREGROUND(pen->colour);
2836 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2837 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2838     startx - sw->xoffset, starty - sw->yoffset,
2839     endx - sw->xoffset, endy - sw->yoffset));
2840 jsorg71 450 if (g_ownbackstore)
2841     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2842 matty 29 RESET_FUNCTION(opcode);
2843 matty 9 }
2844    
2845 matty 25 void
2846     ui_rect(
2847     /* dest */ int x, int y, int cx, int cy,
2848     /* brush */ int colour)
2849 matty 9 {
2850 matty 29 SET_FOREGROUND(colour);
2851 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2852 matty 9 }
2853    
2854 jdmeijer 831 void
2855     ui_polygon(uint8 opcode,
2856     /* mode */ uint8 fillmode,
2857 jsorg71 1364 /* dest */ RD_POINT * point, int npoints,
2858 jdmeijer 831 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2859     {
2860     uint8 style, i, ipattern[8];
2861     Pixmap fill;
2862    
2863     SET_FUNCTION(opcode);
2864    
2865     switch (fillmode)
2866     {
2867     case ALTERNATE:
2868     XSetFillRule(g_display, g_gc, EvenOddRule);
2869     break;
2870     case WINDING:
2871     XSetFillRule(g_display, g_gc, WindingRule);
2872     break;
2873     default:
2874     unimpl("fill mode %d\n", fillmode);
2875     }
2876    
2877     if (brush)
2878     style = brush->style;
2879     else
2880     style = 0;
2881    
2882     switch (style)
2883     {
2884     case 0: /* Solid */
2885     SET_FOREGROUND(fgcolour);
2886     FILL_POLYGON((XPoint *) point, npoints);
2887     break;
2888    
2889     case 2: /* Hatch */
2890     fill = (Pixmap) ui_create_glyph(8, 8,
2891     hatch_patterns + brush->pattern[0] * 8);
2892     SET_FOREGROUND(fgcolour);
2893     SET_BACKGROUND(bgcolour);
2894     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2895     XSetStipple(g_display, g_gc, fill);
2896     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2897     FILL_POLYGON((XPoint *) point, npoints);
2898     XSetFillStyle(g_display, g_gc, FillSolid);
2899     XSetTSOrigin(g_display, g_gc, 0, 0);
2900 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2901 jdmeijer 831 break;
2902    
2903     case 3: /* Pattern */
2904     for (i = 0; i != 8; i++)
2905     ipattern[7 - i] = brush->pattern[i];
2906     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2907     SET_FOREGROUND(bgcolour);
2908     SET_BACKGROUND(fgcolour);
2909     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2910     XSetStipple(g_display, g_gc, fill);
2911     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2912     FILL_POLYGON((XPoint *) point, npoints);
2913     XSetFillStyle(g_display, g_gc, FillSolid);
2914     XSetTSOrigin(g_display, g_gc, 0, 0);
2915 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2916 jdmeijer 831 break;
2917    
2918     default:
2919     unimpl("brush %d\n", brush->style);
2920     }
2921    
2922     RESET_FUNCTION(opcode);
2923     }
2924    
2925     void
2926 jdmeijer 844 ui_polyline(uint8 opcode,
2927 jsorg71 1364 /* dest */ RD_POINT * points, int npoints,
2928 jdmeijer 844 /* pen */ PEN * pen)
2929     {
2930     /* TODO: set join style */
2931     SET_FUNCTION(opcode);
2932     SET_FOREGROUND(pen->colour);
2933     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2934     if (g_ownbackstore)
2935     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2936     CoordModePrevious);
2937 astrand 1199
2938     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2939     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2940    
2941 jdmeijer 844 RESET_FUNCTION(opcode);
2942     }
2943    
2944     void
2945 jdmeijer 831 ui_ellipse(uint8 opcode,
2946     /* mode */ uint8 fillmode,
2947     /* dest */ int x, int y, int cx, int cy,
2948     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2949     {
2950     uint8 style, i, ipattern[8];
2951     Pixmap fill;
2952    
2953     SET_FUNCTION(opcode);
2954    
2955     if (brush)
2956     style = brush->style;
2957     else
2958     style = 0;
2959    
2960     switch (style)
2961     {
2962     case 0: /* Solid */
2963     SET_FOREGROUND(fgcolour);
2964     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2965     break;
2966    
2967     case 2: /* Hatch */
2968     fill = (Pixmap) ui_create_glyph(8, 8,
2969     hatch_patterns + brush->pattern[0] * 8);
2970     SET_FOREGROUND(fgcolour);
2971     SET_BACKGROUND(bgcolour);
2972     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2973     XSetStipple(g_display, g_gc, fill);
2974     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2975     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2976     XSetFillStyle(g_display, g_gc, FillSolid);
2977     XSetTSOrigin(g_display, g_gc, 0, 0);
2978 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2979 jdmeijer 831 break;
2980    
2981     case 3: /* Pattern */
2982     for (i = 0; i != 8; i++)
2983     ipattern[7 - i] = brush->pattern[i];
2984     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2985     SET_FOREGROUND(bgcolour);
2986     SET_BACKGROUND(fgcolour);
2987     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2988     XSetStipple(g_display, g_gc, fill);
2989     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2990     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2991     XSetFillStyle(g_display, g_gc, FillSolid);
2992     XSetTSOrigin(g_display, g_gc, 0, 0);
2993 jsorg71 1364 ui_destroy_glyph((RD_HGLYPH) fill);
2994 jdmeijer 831 break;
2995    
2996     default:
2997     unimpl("brush %d\n", brush->style);
2998     }
2999    
3000     RESET_FUNCTION(opcode);
3001     }
3002    
3003 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
3004 matty 25 void
3005     ui_draw_glyph(int mixmode,
3006     /* dest */ int x, int y, int cx, int cy,
3007 jsorg71 1364 /* src */ RD_HGLYPH glyph, int srcx, int srcy,
3008 astrand 66 int bgcolour, int fgcolour)
3009 matty 9 {
3010 matty 29 SET_FOREGROUND(fgcolour);
3011     SET_BACKGROUND(bgcolour);
3012 matty 9
3013 jsorg71 450 XSetFillStyle(g_display, g_gc,
3014 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3015 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
3016     XSetTSOrigin(g_display, g_gc, x, y);
3017 matty 9
3018 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3019 matty 9
3020 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3021 matty 9 }
3022    
3023 mmihalik 49 #define DO_GLYPH(ttext,idx) \
3024     {\
3025     glyph = cache_get_font (font, ttext[idx]);\
3026     if (!(flags & TEXT2_IMPLICIT_X))\
3027 jsorg71 564 {\
3028     xyoffset = ttext[++idx];\
3029     if ((xyoffset & 0x80))\
3030 mmihalik 49 {\
3031 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3032     y += ttext[idx+1] | (ttext[idx+2] << 8);\
3033 mmihalik 49 else\
3034 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
3035     idx += 2;\
3036 mmihalik 49 }\
3037 jsorg71 564 else\
3038 mmihalik 49 {\
3039 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3040     y += xyoffset;\
3041     else\
3042     x += xyoffset;\
3043 mmihalik 49 }\
3044 jsorg71 564 }\
3045     if (glyph != NULL)\
3046     {\
3047     x1 = x + glyph->offset;\
3048     y1 = y + glyph->baseline;\
3049     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3050     XSetTSOrigin(g_display, g_gc, x1, y1);\
3051     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3052     if (flags & TEXT2_IMPLICIT_X)\
3053     x += glyph->width;\
3054     }\
3055 mmihalik 49 }
3056    
3057 matty 25 void
3058 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
3059 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
3060 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3061     int bgcolour, int fgcolour, uint8 * text, uint8 length)
3062 matty 9 {
3063 jdmeijer 843 /* TODO: use brush appropriately */
3064    
3065 matty 10 FONTGLYPH *glyph;
3066 jsorg71 564 int i, j, xyoffset, x1, y1;
3067 mmihalik 49 DATABLOB *entry;
3068 matty 9
3069 matty 29 SET_FOREGROUND(bgcolour);
3070 matty 28
3071 astrand 620 /* Sometimes, the boxcx value is something really large, like
3072     32691. This makes XCopyArea fail with Xvnc. The code below
3073     is a quick fix. */
3074     if (boxx + boxcx > g_width)
3075     boxcx = g_width - boxx;
3076    
3077 matty 9 if (boxcx > 1)
3078 matty 31 {
3079 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3080 matty 31 }
3081 matty 17 else if (mixmode == MIX_OPAQUE)
3082 matty 31 {
3083 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3084 matty 31 }
3085 matty 9
3086 jsorg71 564 SET_FOREGROUND(fgcolour);
3087     SET_BACKGROUND(bgcolour);
3088     XSetFillStyle(g_display, g_gc, FillStippled);
3089    
3090 matty 9 /* Paint text, character by character */
3091 astrand 64 for (i = 0; i < length;)
3092     {
3093     switch (text[i])
3094     {
3095     case 0xff:
3096 astrand 1031 /* At least two bytes needs to follow */
3097 astrand 1029 if (i + 3 > length)
3098 astrand 64 {
3099 astrand 1031 warning("Skipping short 0xff command:");
3100     for (j = 0; j < length; j++)
3101     fprintf(stderr, "%02x ", text[j]);
3102     fprintf(stderr, "\n");
3103 astrand 1029 i = length = 0;
3104     break;
3105 astrand 64 }
3106 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
3107     i += 3;
3108     length -= i;
3109 astrand 64 /* this will move pointer from start to first character after FF command */
3110 astrand 1029 text = &(text[i]);
3111 astrand 64 i = 0;
3112 mmihalik 49 break;
3113 matty 9
3114 astrand 64 case 0xfe:
3115 astrand 1031 /* At least one byte needs to follow */
3116     if (i + 2 > length)
3117 astrand 1029 {
3118 astrand 1031 warning("Skipping short 0xfe command:");
3119     for (j = 0; j < length; j++)
3120     fprintf(stderr, "%02x ", text[j]);
3121     fprintf(stderr, "\n");
3122 astrand 1029 i = length = 0;
3123     break;
3124     }
3125 astrand 64 entry = cache_get_text(text[i + 1]);
3126 astrand 1030 if (entry->data != NULL)
3127 astrand 64 {
3128 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
3129     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3130 astrand 64 {
3131     if (flags & TEXT2_VERTICAL)
3132     y += text[i + 2];
3133     else
3134     x += text[i + 2];
3135     }
3136     for (j = 0; j < entry->size; j++)
3137 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
3138 matthewc 44 }
3139 astrand 1031 if (i + 2 < length)
3140     i += 3;
3141     else
3142     i += 2;
3143 jsorg71 286 length -= i;
3144     /* this will move pointer from start to first character after FE command */
3145     text = &(text[i]);
3146     i = 0;
3147 astrand 64 break;
3148 matty 17
3149 astrand 64 default:
3150     DO_GLYPH(text, i);
3151     i++;
3152     break;
3153 matty 29 }
3154 mmihalik 49 }
3155 jsorg71 564
3156     XSetFillStyle(g_display, g_gc, FillSolid);
3157    
3158 jsorg71 450 if (g_ownbackstore)
3159 jsorg71 278 {
3160     if (boxcx > 1)
3161 astrand 1199 {
3162 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3163 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
3164 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3165     (g_display, g_backstore, sw->wnd, g_gc,
3166     boxx, boxy,
3167     boxcx, boxcy,
3168     boxx - sw->xoffset, boxy - sw->yoffset));
3169     }
3170 jsorg71 278 else
3171 astrand 1199 {
3172 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3173 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
3174 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3175     (g_display, g_backstore, sw->wnd, g_gc,
3176     clipx, clipy,
3177     clipcx, clipcy, clipx - sw->xoffset,
3178     clipy - sw->yoffset));
3179     }
3180 jsorg71 278 }
3181 matty 9 }
3182    
3183 matty 25 void
3184     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
3185 matty 9 {
3186 matty 28 Pixmap pix;
3187 matty 9 XImage *image;
3188    
3189 jsorg71 450 if (g_ownbackstore)
3190 matty 31 {
3191 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3192 astrand 1306 exit_if_null(image);
3193 matty 31 }
3194     else
3195     {
3196 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3197     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3198     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3199 astrand 1306 exit_if_null(image);
3200 jsorg71 450 XFreePixmap(g_display, pix);
3201 matty 31 }
3202 matty 28
3203 jsorg71 450 offset *= g_bpp / 8;
3204     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
3205 matty 28
3206     XDestroyImage(image);
3207 matty 9 }
3208    
3209 matty 25 void
3210     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
3211 matty 9 {
3212     XImage *image;
3213 matty 10 uint8 *data;
3214 matty 9
3215 jsorg71 450 offset *= g_bpp / 8;
3216     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3217 matty 10 if (data == NULL)
3218     return;
3219 matty 29
3220 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3221     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
3222 matty 29
3223 jsorg71 450 if (g_ownbackstore)
3224 matty 31 {
3225 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3226     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3227 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3228     (g_display, g_backstore, sw->wnd, g_gc,
3229     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3230 matty 31 }
3231     else
3232     {
3233 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3234 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3235     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3236     x - sw->xoffset, y - sw->yoffset));
3237 matty 31 }
3238    
3239 matty 9 XFree(image);
3240     }
3241 jsorg71 713
3242     /* these do nothing here but are used in uiports */
3243     void
3244     ui_begin_update(void)
3245     {
3246     }
3247    
3248     void
3249     ui_end_update(void)
3250     {
3251     }
3252 astrand 1199
3253    
3254     void
3255 jsorg71 1372 ui_seamless_begin(RD_BOOL hidden)
3256 astrand 1199 {
3257     if (!g_seamless_rdp)
3258     return;
3259    
3260     if (g_seamless_started)
3261     return;
3262    
3263     g_seamless_started = True;
3264     g_seamless_hidden = hidden;
3265    
3266     if (!hidden)
3267     ui_seamless_toggle();
3268     }
3269    
3270    
3271     void
3272     ui_seamless_hide_desktop()
3273     {
3274     if (!g_seamless_rdp)
3275     return;
3276    
3277     if (!g_seamless_started)
3278     return;
3279    
3280     if (g_seamless_active)
3281     ui_seamless_toggle();
3282    
3283     g_seamless_hidden = True;
3284     }
3285    
3286    
3287     void
3288     ui_seamless_unhide_desktop()
3289     {
3290     if (!g_seamless_rdp)
3291     return;
3292    
3293     if (!g_seamless_started)
3294     return;
3295    
3296     g_seamless_hidden = False;
3297    
3298     ui_seamless_toggle();
3299     }
3300    
3301    
3302     void
3303     ui_seamless_toggle()
3304     {
3305     if (!g_seamless_rdp)
3306     return;
3307    
3308     if (!g_seamless_started)
3309     return;
3310    
3311     if (g_seamless_hidden)
3312     return;
3313    
3314     if (g_seamless_active)
3315     {
3316     /* Deactivate */
3317     while (g_seamless_windows)
3318     {
3319     XDestroyWindow(g_display, g_seamless_windows->wnd);
3320     sw_remove_window(g_seamless_windows);
3321     }
3322     XMapWindow(g_display, g_wnd);
3323     }
3324     else
3325     {
3326     /* Activate */
3327     XUnmapWindow(g_display, g_wnd);
3328     seamless_send_sync();
3329     }
3330    
3331     g_seamless_active = !g_seamless_active;
3332     }
3333    
3334    
3335     void
3336     ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3337     unsigned long flags)
3338     {
3339     Window wnd;
3340     XSetWindowAttributes attribs;
3341     XClassHint *classhints;
3342     XSizeHints *sizehints;
3343     XWMHints *wmhints;
3344     long input_mask;
3345     seamless_window *sw, *sw_parent;
3346    
3347     if (!g_seamless_active)
3348     return;
3349    
3350     /* Ignore CREATEs for existing windows */
3351     sw = sw_get_window_by_id(id);
3352     if (sw)
3353     return;
3354    
3355     get_window_attribs(&attribs);
3356     wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3357     InputOutput, g_visual,
3358     CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3359    
3360     XStoreName(g_display, wnd, "SeamlessRDP");
3361     ewmh_set_wm_name(wnd, "SeamlessRDP");
3362    
3363     mwm_hide_decorations(wnd);
3364    
3365     classhints = XAllocClassHint();
3366     if (classhints != NULL)
3367     {
3368     classhints->res_name = "rdesktop";
3369     classhints->res_class = "SeamlessRDP";
3370     XSetClassHint(g_display, wnd, classhints);
3371     XFree(classhints);
3372     }
3373    
3374     /* WM_NORMAL_HINTS */
3375     sizehints = XAllocSizeHints();
3376     if (sizehints != NULL)
3377     {
3378     sizehints->flags = USPosition;
3379     XSetWMNormalHints(g_display, wnd, sizehints);
3380     XFree(sizehints);
3381     }
3382    
3383     /* Parent-less transient windows */
3384     if (parent == 0xFFFFFFFF)
3385     {
3386     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3387     /* Some buggy wm:s (kwin) do not handle the above, so fake it
3388     using some other hints. */
3389     ewmh_set_window_popup(wnd);
3390     }
3391     /* Normal transient windows */
3392     else if (parent != 0x00000000)
3393     {
3394     sw_parent = sw_get_window_by_id(parent);
3395     if (sw_parent)
3396     XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3397     else
3398     warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3399     }
3400    
3401     if (flags & SEAMLESSRDP_CREATE_MODAL)
3402     {
3403     /* We do this to support buggy wm:s (*cough* metacity *cough*)
3404     somewhat at least */
3405     if (parent == 0x00000000)
3406     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3407     ewmh_set_window_modal(wnd);
3408     }
3409    
3410     /* FIXME: Support for Input Context:s */
3411    
3412     get_input_mask(&input_mask);
3413     input_mask |= PropertyChangeMask;
3414    
3415     XSelectInput(g_display, wnd, input_mask);
3416    
3417     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3418     seamless window, we could try to close the window on the
3419     serverside, instead of terminating rdesktop */
3420     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3421    
3422     sw = xmalloc(sizeof(seamless_window));
3423     sw->wnd = wnd;
3424     sw->id = id;
3425     sw->behind = 0;
3426     sw->group = sw_find_group(group, False);
3427     sw->group->refcnt++;
3428     sw->xoffset = 0;
3429     sw->yoffset = 0;
3430     sw->width = 0;
3431     sw->height = 0;
3432     sw->state = SEAMLESSRDP_NOTYETMAPPED;
3433     sw->desktop = 0;
3434     sw->position_timer = xmalloc(sizeof(struct timeval));
3435     timerclear(sw->position_timer);
3436    
3437     sw->outstanding_position = False;
3438     sw->outpos_serial = 0;
3439     sw->outpos_xoffset = sw->outpos_yoffset = 0;
3440     sw->outpos_width = sw->outpos_height = 0;
3441    
3442     sw->next = g_seamless_windows;
3443     g_seamless_windows = sw;
3444    
3445     /* WM_HINTS */
3446     wmhints = XAllocWMHints();
3447     if (wmhints)
3448     {
3449     wmhints->flags = WindowGroupHint;
3450     wmhints->window_group = sw->group->wnd;
3451     XSetWMHints(g_display, sw->wnd, wmhints);
3452     XFree(wmhints);
3453     }
3454     }
3455    
3456    
3457     void
3458     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3459     {
3460     seamless_window *sw;
3461    
3462     if (!g_seamless_active)
3463     return;
3464    
3465     sw = sw_get_window_by_id(id);
3466     if (!sw)
3467     {
3468     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3469     return;
3470     }
3471    
3472     XDestroyWindow(g_display, sw->wnd);
3473     sw_remove_window(sw);
3474     }
3475    
3476    
3477     void
3478 ossman_ 1232 ui_seamless_destroy_group(unsigned long id, unsigned long flags)
3479     {
3480     seamless_window *sw, *sw_next;
3481    
3482     if (!g_seamless_active)
3483     return;
3484    
3485     for (sw = g_seamless_windows; sw; sw = sw_next)
3486     {
3487     sw_next = sw->next;
3488    
3489     if (sw->group->id == id)
3490     {
3491     XDestroyWindow(g_display, sw->wnd);
3492     sw_remove_window(sw);
3493     }
3494     }
3495     }
3496    
3497    
3498     void
3499 astrand 1199 ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3500     {
3501     seamless_window *sw;
3502    
3503     if (!g_seamless_active)
3504     return;
3505    
3506     sw = sw_get_window_by_id(id);
3507     if (!sw)
3508     {
3509     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3510     return;
3511     }
3512    
3513     /* We ignore server updates until it has handled our request. */
3514     if (sw->outstanding_position)
3515     return;
3516    
3517     if (!width || !height)
3518     /* X11 windows must be at least 1x1 */
3519     return;
3520    
3521     sw->xoffset = x;
3522     sw->yoffset = y;
3523     sw->width = width;
3524     sw->height = height;
3525    
3526     /* If we move the window in a maximized state, then KDE won't
3527     accept restoration */
3528     switch (sw->state)
3529     {
3530     case SEAMLESSRDP_MINIMIZED:
3531     case SEAMLESSRDP_MAXIMIZED:
3532     return;
3533     }
3534    
3535     /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3536     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3537     }
3538    
3539    
3540     void
3541     ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3542     {
3543     seamless_window *sw;
3544    
3545     if (!g_seamless_active)
3546     return;
3547    
3548     sw = sw_get_window_by_id(id);
3549     if (!sw)
3550     {
3551     warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3552     return;
3553     }
3554    
3555     if (behind)
3556     {
3557     seamless_window *sw_behind;
3558     Window wnds[2];
3559    
3560     sw_behind = sw_get_window_by_id(behind);
3561     if (!sw_behind)
3562     {
3563     warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3564     behind);
3565     return;
3566     }
3567    
3568     wnds[1] = sw_behind->wnd;
3569     wnds[0] = sw->wnd;
3570    
3571     XRestackWindows(g_display, wnds, 2);
3572     }
3573     else
3574     {
3575     XRaiseWindow(g_display, sw->wnd);
3576     }
3577    
3578     sw_restack_window(sw, behind);
3579     }
3580    
3581    
3582     void
3583     ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3584     {
3585     seamless_window *sw;
3586    
3587     if (!g_seamless_active)
3588     return;
3589    
3590     sw = sw_get_window_by_id(id);
3591     if (!sw)
3592     {
3593     warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3594     return;
3595     }
3596    
3597     /* FIXME: Might want to convert the name for non-EWMH WMs */
3598     XStoreName(g_display, sw->wnd, title);
3599     ewmh_set_wm_name(sw->wnd, title);
3600     }
3601    
3602    
3603     void
3604     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3605     {
3606     seamless_window *sw;
3607    
3608     if (!g_seamless_active)
3609     return;
3610    
3611     sw = sw_get_window_by_id(id);
3612     if (!sw)
3613     {
3614     warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3615     return;
3616     }
3617    
3618     switch (state)
3619     {
3620     case SEAMLESSRDP_NORMAL:
3621     case SEAMLESSRDP_MAXIMIZED:
3622     ewmh_change_state(sw->wnd, state);
3623     XMapWindow(g_display, sw->wnd);
3624     break;
3625     case SEAMLESSRDP_MINIMIZED:
3626     /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3627     the Window Manager should probably just ignore the request, since
3628     _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3629     such as minimization, rather than an independent state." Besides,
3630     XIconifyWindow is easier. */
3631     if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3632     {
3633     XWMHints *hints;
3634     hints = XGetWMHints(g_display, sw->wnd);
3635     if (hints)
3636     {
3637     hints->flags |= StateHint;
3638     hints->initial_state = IconicState;
3639     XSetWMHints(g_display, sw->wnd, hints);
3640     XFree(hints);
3641     }
3642     XMapWindow(g_display, sw->wnd);
3643     }
3644     else
3645     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3646     break;
3647     default:
3648     warning("SeamlessRDP: Invalid state %d\n", state);
3649     break;
3650     }
3651    
3652     sw->state = state;
3653     }
3654    
3655    
3656     void
3657     ui_seamless_syncbegin(unsigned long flags)
3658     {
3659     if (!g_seamless_active)
3660     return;
3661    
3662     /* Destroy all seamless windows */
3663     while (g_seamless_windows)
3664     {
3665     XDestroyWindow(g_display, g_seamless_windows->wnd);
3666     sw_remove_window(g_seamless_windows);
3667     }
3668     }
3669    
3670    
3671     void
3672     ui_seamless_ack(unsigned int serial)
3673     {
3674     seamless_window *sw;
3675     for (sw = g_seamless_windows; sw; sw = sw->next)
3676     {
3677     if (sw->outstanding_position && (sw->outpos_serial == serial))
3678     {
3679     sw->xoffset = sw->outpos_xoffset;
3680     sw->yoffset = sw->outpos_yoffset;
3681     sw->width = sw->outpos_width;
3682     sw->height = sw->outpos_height;
3683     sw->outstanding_position = False;
3684    
3685     /* Do a complete redraw of the window as part of the
3686     completion of the move. This is to remove any
3687     artifacts caused by our lack of synchronization. */
3688     XCopyArea(g_display, g_backstore,
3689     sw->wnd, g_gc,
3690     sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3691    
3692     break;
3693     }
3694     }
3695     }

  ViewVC Help
Powered by ViewVC 1.1.26