/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1443 - (hide annotations)
Thu Mar 6 15:39:21 2008 UTC (16 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 87418 byte(s)
Applied rdesktop part of patch:

[ 1715359 ] seamlessrdp topmost windows

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

  ViewVC Help
Powered by ViewVC 1.1.26