/[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 1144 - (hide annotations)
Thu Mar 16 10:14:18 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 76199 byte(s)
Only allocate the XWMHints structure where we need it.

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

  ViewVC Help
Powered by ViewVC 1.1.26