/[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 1143 - (hide annotations)
Thu Mar 16 08:41:53 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 76236 byte(s)
Set _NET_WM_STATE atoms via the window manager (as required by the spec.).
Unfortunately, this means we have to wait for the window to leave the
withdrawn state.

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

  ViewVC Help
Powered by ViewVC 1.1.26