/[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 1453 - (hide annotations)
Fri Mar 14 07:39:38 2008 UTC (16 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 87587 byte(s)
SeamlessRDP bugfix: The first window to XRestackWindows should be the
reference window (the "behind" window); not the window to restack.

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

  ViewVC Help
Powered by ViewVC 1.1.26