/[rdesktop]/jpeg/rdesktop/trunk/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 /jpeg/rdesktop/trunk/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1407 - (hide annotations)
Mon May 14 12:11:15 2007 UTC (17 years, 1 month ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 85263 byte(s)
Send physical mouse buttons over RDP rather than logical ones. Fixes bug 1693905. Patch from Ilya Konstantinov (slightly modified)

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

  ViewVC Help
Powered by ViewVC 1.1.26