/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1133 - (hide annotations)
Wed Mar 15 13:15:51 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 75571 byte(s)
Changed default WM_NAME. Changed WM_CLASS to
rdesktop/SeamlessRDP. This makes it easier to identify seamless
windows, but also shows a nicer title in kwin when WM_NAME is empty.

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

  ViewVC Help
Powered by ViewVC 1.1.26