/[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 1142 - (hide annotations)
Thu Mar 16 08:11:29 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 76114 byte(s)
Handle initially minimized windows through WM_HINTS.

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

  ViewVC Help
Powered by ViewVC 1.1.26