/[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 1413 - (hide annotations)
Mon Jun 18 12:00:34 2007 UTC (17 years ago) by ossman_
File MIME type: text/plain
File size: 87100 byte(s)
Implement support for icons in SeamlessRDP.

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

  ViewVC Help
Powered by ViewVC 1.1.26