/[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 1149 - (hide annotations)
Thu Mar 16 15:27:59 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 76514 byte(s)
Don't activate seamless mode until we have a working connection with the
remote server (i.e. when we get a HELLO).

Also change g_seamless_rdp to mean that -A was specified on the command line.
g_seamless_active now indicates if we're in seamless or "normal" mode.

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 ossman_ 1149 static BOOL g_seamless_started = False; /* Server end is up and running */
66     static BOOL g_seamless_active = False; /* We are currently in seamless mode */
67 astrand 1089 extern BOOL g_seamless_rdp;
68    
69 stargo 648 extern uint32 g_embed_wnd;
70 matthewc 481 BOOL g_enable_compose = False;
71 astrand 691 BOOL g_Unobscured; /* used for screenblt */
72 stargo 576 static GC g_gc = NULL;
73 jsorg71 725 static GC g_create_bitmap_gc = NULL;
74     static GC g_create_glyph_gc = NULL;
75 astrand 1089 static XRectangle g_clip_rectangle;
76 jsorg71 450 static Visual *g_visual;
77 astrand 1042 /* Color depth of the X11 visual of our window (e.g. 24 for True Color R8G8B visual).
78     This may be 32 for R8G8B8 visuals, and then the rest of the bits are undefined
79     as far as we're concerned. */
80 jsorg71 450 static int g_depth;
81 astrand 1042 /* Bits-per-Pixel of the pixmaps we'll be using to draw on our window.
82     This may be larger than g_depth, in which case some of the bits would
83     be kept solely for alignment (e.g. 32bpp pixmaps on a 24bpp visual). */
84 jsorg71 450 static int g_bpp;
85     static XIM g_IM;
86     static XIC g_IC;
87     static XModifierKeymap *g_mod_map;
88     static Cursor g_current_cursor;
89 stargo 576 static HCURSOR g_null_cursor = NULL;
90 jsorg71 450 static Atom g_protocol_atom, g_kill_atom;
91 astrand 1118 extern Atom g_net_wm_state_atom;
92 astrand 1119 extern Atom g_net_wm_desktop_atom;
93 matthewc 481 static BOOL g_focused;
94     static BOOL g_mouse_in_wnd;
95 astrand 1049 /* Indicates that:
96     1) visual has 15, 16 or 24 depth and the same color channel masks
97     as its RDP equivalent (implies X server is LE),
98     2) host is LE
99     This will trigger an optimization whose real value is questionable.
100     */
101     static BOOL g_compatible_arch;
102 astrand 1042 /* Indicates whether RDP's bitmaps and our XImages have the same
103     binary format. If so, we can avoid an expensive translation.
104 astrand 1049 Note that this can be true when g_compatible_arch is false,
105     e.g.:
106    
107     RDP(LE) <-> host(BE) <-> X-Server(LE)
108    
109     ('host' is the machine running rdesktop; the host simply memcpy's
110     so its endianess doesn't matter)
111     */
112 astrand 1042 static BOOL g_no_translate_image = False;
113 matty 29
114 matty 33 /* endianness */
115 jsorg71 450 static BOOL g_host_be;
116     static BOOL g_xserver_be;
117 matthewc 527 static int g_red_shift_r, g_blue_shift_r, g_green_shift_r;
118     static int g_red_shift_l, g_blue_shift_l, g_green_shift_l;
119 matty 33
120     /* software backing store */
121 stargo 648 extern BOOL g_ownbackstore;
122 stargo 603 static Pixmap g_backstore = 0;
123 matty 31
124 astrand 342 /* Moving in single app mode */
125 jsorg71 450 static BOOL g_moving_wnd;
126     static int g_move_x_offset = 0;
127     static int g_move_y_offset = 0;
128 astrand 991 static BOOL g_using_full_workarea = False;
129 astrand 342
130 matthewc 474 #ifdef WITH_RDPSND
131     extern int g_dsp_fd;
132     extern BOOL g_dsp_busy;
133 stargo 501 extern BOOL g_rdpsnd;
134 matthewc 474 #endif
135    
136 astrand 262 /* MWM decorations */
137     #define MWM_HINTS_DECORATIONS (1L << 1)
138     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
139     typedef struct
140     {
141 astrand 1033 unsigned long flags;
142     unsigned long functions;
143     unsigned long decorations;
144     long inputMode;
145     unsigned long status;
146 astrand 262 }
147     PropMotifWmHints;
148    
149 jsorg71 316 typedef struct
150     {
151     uint32 red;
152     uint32 green;
153     uint32 blue;
154     }
155     PixelColour;
156 astrand 262
157 astrand 1089 #define ON_ALL_SEAMLESS_WINDOWS(func, args) \
158     do { \
159     seamless_window *sw; \
160     XRectangle rect; \
161     for (sw = g_seamless_windows; sw; sw = sw->next) { \
162     rect.x = g_clip_rectangle.x - sw->xoffset; \
163     rect.y = g_clip_rectangle.y - sw->yoffset; \
164     rect.width = g_clip_rectangle.width; \
165     rect.height = g_clip_rectangle.height; \
166     XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded); \
167     func args; \
168     } \
169     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded); \
170     } while (0)
171 forsberg 415
172 astrand 1089 static void
173     seamless_XFillPolygon(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
174     {
175     points[0].x -= xoffset;
176     points[0].y -= yoffset;
177     XFillPolygon(g_display, d, g_gc, points, npoints, Complex, CoordModePrevious);
178     points[0].x += xoffset;
179     points[0].y += yoffset;
180     }
181    
182     static void
183     seamless_XDrawLines(Drawable d, XPoint * points, int npoints, int xoffset, int yoffset)
184     {
185     points[0].x -= xoffset;
186     points[0].y -= yoffset;
187     XDrawLines(g_display, d, g_gc, points, npoints, CoordModePrevious);
188     points[0].x += xoffset;
189     points[0].y += yoffset;
190     }
191    
192 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
193     { \
194 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
195 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XFillRectangle, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy)); \
196 jsorg71 450 if (g_ownbackstore) \
197     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
198 matty 31 }
199    
200 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
201 jsorg71 281 { \
202 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
203 jsorg71 281 }
204    
205 jdmeijer 831 #define FILL_POLYGON(p,np)\
206     { \
207     XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
208     if (g_ownbackstore) \
209     XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
210 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(seamless_XFillPolygon, (sw->wnd, p, np, sw->xoffset, sw->yoffset)); \
211 jdmeijer 831 }
212    
213     #define DRAW_ELLIPSE(x,y,cx,cy,m)\
214     { \
215     switch (m) \
216     { \
217     case 0: /* Outline */ \
218     XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
219 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XDrawArc, (g_display, sw->wnd, g_gc, x-sw->xoffset, y-sw->yoffset, cx, cy, 0, 360*64)); \
220 jdmeijer 831 if (g_ownbackstore) \
221     XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
222     break; \
223     case 1: /* Filled */ \
224 astrand 1089 XFillArc(g_display, g_wnd, g_gc, x, y, \
225     cx, cy, 0, 360*64); \
226     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)); \
227 jdmeijer 831 if (g_ownbackstore) \
228 jsorg71 1022 XFillArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
229 jdmeijer 831 break; \
230     } \
231     }
232    
233 matty 33 /* colour maps */
234 stargo 648 extern BOOL g_owncolmap;
235 jsorg71 450 static Colormap g_xcolmap;
236     static uint32 *g_colmap = NULL;
237 matty 10
238 astrand 1042 #define TRANSLATE(col) ( g_server_depth != 8 ? translate_colour(col) : g_owncolmap ? col : g_colmap[col] )
239 jsorg71 450 #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
240     #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
241 matty 28
242     static int rop2_map[] = {
243     GXclear, /* 0 */
244     GXnor, /* DPon */
245     GXandInverted, /* DPna */
246     GXcopyInverted, /* Pn */
247     GXandReverse, /* PDna */
248     GXinvert, /* Dn */
249     GXxor, /* DPx */
250     GXnand, /* DPan */
251     GXand, /* DPa */
252     GXequiv, /* DPxn */
253     GXnoop, /* D */
254     GXorInverted, /* DPno */
255     GXcopy, /* P */
256     GXorReverse, /* PDno */
257     GXor, /* DPo */
258     GXset /* 1 */
259     };
260    
261 jsorg71 450 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
262     #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
263 matty 29
264 astrand 1089 static seamless_window *
265     seamless_get_window_by_id(unsigned long id)
266     {
267     seamless_window *sw;
268     for (sw = g_seamless_windows; sw; sw = sw->next)
269     {
270     if (sw->id == id)
271     return sw;
272     }
273     return NULL;
274     }
275    
276    
277     static seamless_window *
278     seamless_get_window_by_wnd(Window wnd)
279     {
280     seamless_window *sw;
281     for (sw = g_seamless_windows; sw; sw = sw->next)
282     {
283     if (sw->wnd == wnd)
284     return sw;
285     }
286     return NULL;
287     }
288    
289    
290 astrand 319 static void
291 astrand 1089 seamless_remove_window(seamless_window * win)
292 astrand 262 {
293 astrand 1089 seamless_window *sw, **prevnext = &g_seamless_windows;
294     for (sw = g_seamless_windows; sw; sw = sw->next)
295     {
296     if (sw == win)
297     {
298     *prevnext = sw->next;
299     xfree(sw);
300     return;
301     }
302     prevnext = &sw->next;
303     }
304     return;
305     }
306    
307    
308 astrand 1119 /* Move all windows except wnd to new desktop */
309 astrand 1089 static void
310 astrand 1119 seamless_all_to_desktop(Window wnd, unsigned int desktop)
311     {
312     seamless_window *sw;
313     for (sw = g_seamless_windows; sw; sw = sw->next)
314     {
315     if (sw->wnd == wnd)
316     continue;
317     if (sw->desktop != desktop)
318     {
319     ewmh_move_to_desktop(sw->wnd, desktop);
320     sw->desktop = desktop;
321     }
322     }
323     }
324    
325    
326     static void
327 astrand 1089 mwm_hide_decorations(Window wnd)
328     {
329 astrand 262 PropMotifWmHints motif_hints;
330     Atom hintsatom;
331    
332     /* setup the property */
333     motif_hints.flags = MWM_HINTS_DECORATIONS;
334     motif_hints.decorations = 0;
335    
336     /* get the atom for the property */
337 jsorg71 450 hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
338 astrand 262 if (!hintsatom)
339     {
340 matthewc 297 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
341 astrand 262 return;
342     }
343    
344 astrand 1089 XChangeProperty(g_display, wnd, hintsatom, hintsatom, 32, PropModeReplace,
345 astrand 262 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
346 astrand 1089
347 astrand 262 }
348    
349 jdmeijer 821 #define SPLITCOLOUR15(colour, rv) \
350     { \
351     rv.red = ((colour >> 7) & 0xf8) | ((colour >> 12) & 0x7); \
352     rv.green = ((colour >> 2) & 0xf8) | ((colour >> 8) & 0x7); \
353     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
354 jsorg71 311 }
355    
356 jdmeijer 821 #define SPLITCOLOUR16(colour, rv) \
357     { \
358     rv.red = ((colour >> 8) & 0xf8) | ((colour >> 13) & 0x7); \
359     rv.green = ((colour >> 3) & 0xfc) | ((colour >> 9) & 0x3); \
360     rv.blue = ((colour << 3) & 0xf8) | ((colour >> 2) & 0x7); \
361     } \
362 jsorg71 311
363 jdmeijer 821 #define SPLITCOLOUR24(colour, rv) \
364     { \
365     rv.blue = (colour & 0xff0000) >> 16; \
366     rv.green = (colour & 0x00ff00) >> 8; \
367     rv.red = (colour & 0x0000ff); \
368 jsorg71 311 }
369    
370 jdmeijer 821 #define MAKECOLOUR(pc) \
371     ((pc.red >> g_red_shift_r) << g_red_shift_l) \
372     | ((pc.green >> g_green_shift_r) << g_green_shift_l) \
373     | ((pc.blue >> g_blue_shift_r) << g_blue_shift_l) \
374 jsorg71 316
375 jsorg71 311 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
376 stargo 534 #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | (x & 0xff00)); }
377 jsorg71 311 #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
378     x = (x << 16) | (x >> 16); }
379    
380 astrand 1049 /* The following macros output the same octet sequences
381     on both BE and LE hosts: */
382    
383 jdmeijer 821 #define BOUT16(o, x) { *(o++) = x >> 8; *(o++) = x; }
384     #define BOUT24(o, x) { *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
385     #define BOUT32(o, x) { *(o++) = x >> 24; *(o++) = x >> 16; *(o++) = x >> 8; *(o++) = x; }
386     #define LOUT16(o, x) { *(o++) = x; *(o++) = x >> 8; }
387     #define LOUT24(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; }
388     #define LOUT32(o, x) { *(o++) = x; *(o++) = x >> 8; *(o++) = x >> 16; *(o++) = x >> 24; }
389    
390 jsorg71 311 static uint32
391     translate_colour(uint32 colour)
392     {
393 matthewc 527 PixelColour pc;
394 astrand 1042 switch (g_server_depth)
395 jsorg71 311 {
396 jsorg71 316 case 15:
397 jdmeijer 821 SPLITCOLOUR15(colour, pc);
398 jsorg71 316 break;
399 jsorg71 311 case 16:
400 jdmeijer 821 SPLITCOLOUR16(colour, pc);
401 jsorg71 311 break;
402     case 24:
403 jdmeijer 821 SPLITCOLOUR24(colour, pc);
404 jsorg71 311 break;
405 astrand 1042 default:
406     /* Avoid warning */
407     pc.red = 0;
408     pc.green = 0;
409     pc.blue = 0;
410     break;
411 jsorg71 311 }
412 jdmeijer 821 return MAKECOLOUR(pc);
413 jsorg71 311 }
414    
415 jsorg71 709 /* indent is confused by UNROLL8 */
416     /* *INDENT-OFF* */
417    
418     /* repeat and unroll, similar to bitmap.c */
419     /* potentialy any of the following translate */
420     /* functions can use repeat but just doing */
421     /* the most common ones */
422    
423 jsorg71 679 #define UNROLL8(stm) { stm stm stm stm stm stm stm stm }
424 jsorg71 709 /* 2 byte output repeat */
425     #define REPEAT2(stm) \
426 jsorg71 679 { \
427 jsorg71 709 while (out <= end - 8 * 2) \
428     UNROLL8(stm) \
429     while (out < end) \
430     { stm } \
431     }
432 jdmeijer 821 /* 3 byte output repeat */
433     #define REPEAT3(stm) \
434     { \
435     while (out <= end - 8 * 3) \
436     UNROLL8(stm) \
437     while (out < end) \
438     { stm } \
439     }
440 jsorg71 709 /* 4 byte output repeat */
441     #define REPEAT4(stm) \
442     { \
443 jsorg71 679 while (out <= end - 8 * 4) \
444     UNROLL8(stm) \
445     while (out < end) \
446     { stm } \
447     }
448 jdmeijer 821 /* *INDENT-ON* */
449 jsorg71 679
450 matty 28 static void
451 jdmeijer 821 translate8to8(const uint8 * data, uint8 * out, uint8 * end)
452 matty 28 {
453 matty 29 while (out < end)
454 jsorg71 450 *(out++) = (uint8) g_colmap[*(data++)];
455 matty 29 }
456 matty 28
457 matty 29 static void
458 jdmeijer 821 translate8to16(const uint8 * data, uint8 * out, uint8 * end)
459 matty 29 {
460 stargo 521 uint16 value;
461    
462 astrand 1049 if (g_compatible_arch)
463 stargo 521 {
464 jdmeijer 821 /* *INDENT-OFF* */
465 jsorg71 709 REPEAT2
466     (
467     *((uint16 *) out) = g_colmap[*(data++)];
468     out += 2;
469     )
470 jdmeijer 821 /* *INDENT-ON* */
471 jsorg71 643 }
472 jsorg71 709 else if (g_xserver_be)
473 jsorg71 643 {
474 jsorg71 709 while (out < end)
475     {
476     value = (uint16) g_colmap[*(data++)];
477 jdmeijer 821 BOUT16(out, value);
478 jsorg71 709 }
479 stargo 521 }
480 jsorg71 709 else
481     {
482     while (out < end)
483     {
484     value = (uint16) g_colmap[*(data++)];
485 jdmeijer 821 LOUT16(out, value);
486 jsorg71 709 }
487     }
488 matty 29 }
489    
490 jsorg71 316 /* little endian - conversion happens when colourmap is built */
491 jsorg71 311 static void
492 jdmeijer 821 translate8to24(const uint8 * data, uint8 * out, uint8 * end)
493 jsorg71 311 {
494 jsorg71 316 uint32 value;
495    
496 astrand 1049 if (g_compatible_arch)
497 jsorg71 316 {
498 jsorg71 643 while (out < end)
499 stargo 521 {
500 jsorg71 643 value = g_colmap[*(data++)];
501 jdmeijer 821 BOUT24(out, value);
502 stargo 521 }
503 jsorg71 643 }
504     else
505     {
506     while (out < end)
507 stargo 521 {
508 jsorg71 643 value = g_colmap[*(data++)];
509 jdmeijer 821 LOUT24(out, value);
510 stargo 521 }
511 jsorg71 316 }
512 jsorg71 311 }
513    
514 matty 29 static void
515 jdmeijer 821 translate8to32(const uint8 * data, uint8 * out, uint8 * end)
516 matty 29 {
517 stargo 521 uint32 value;
518    
519 astrand 1049 if (g_compatible_arch)
520 stargo 521 {
521 jdmeijer 821 /* *INDENT-OFF* */
522 jsorg71 709 REPEAT4
523     (
524     *((uint32 *) out) = g_colmap[*(data++)];
525     out += 4;
526     )
527 jdmeijer 821 /* *INDENT-ON* */
528 jsorg71 643 }
529 jsorg71 709 else if (g_xserver_be)
530 jsorg71 643 {
531 jsorg71 709 while (out < end)
532     {
533     value = g_colmap[*(data++)];
534 jdmeijer 821 BOUT32(out, value);
535 jsorg71 709 }
536 stargo 521 }
537 jsorg71 709 else
538     {
539     while (out < end)
540     {
541     value = g_colmap[*(data++)];
542 jdmeijer 821 LOUT32(out, value);
543 jsorg71 709 }
544     }
545 jsorg71 316 }
546    
547     static void
548 jdmeijer 821 translate15to16(const uint16 * data, uint8 * out, uint8 * end)
549 jsorg71 316 {
550 jsorg71 483 uint16 pixel;
551     uint16 value;
552 jdmeijer 821 PixelColour pc;
553 jsorg71 483
554 jdmeijer 821 if (g_xserver_be)
555 jsorg71 483 {
556 jdmeijer 821 while (out < end)
557 jsorg71 483 {
558 jdmeijer 821 pixel = *(data++);
559     if (g_host_be)
560     {
561     BSWAP16(pixel);
562     }
563     SPLITCOLOUR15(pixel, pc);
564     value = MAKECOLOUR(pc);
565     BOUT16(out, value);
566 stargo 521 }
567 jdmeijer 821 }
568     else
569     {
570     while (out < end)
571 jsorg71 483 {
572 jdmeijer 821 pixel = *(data++);
573     if (g_host_be)
574     {
575     BSWAP16(pixel);
576     }
577     SPLITCOLOUR15(pixel, pc);
578     value = MAKECOLOUR(pc);
579     LOUT16(out, value);
580 jsorg71 483 }
581     }
582 jsorg71 316 }
583    
584     static void
585 jdmeijer 821 translate15to24(const uint16 * data, uint8 * out, uint8 * end)
586 jsorg71 316 {
587 matty 29 uint32 value;
588 jsorg71 483 uint16 pixel;
589 jdmeijer 821 PixelColour pc;
590 matty 29
591 astrand 1049 if (g_compatible_arch)
592 matty 28 {
593 jdmeijer 821 /* *INDENT-OFF* */
594     REPEAT3
595     (
596     pixel = *(data++);
597     SPLITCOLOUR15(pixel, pc);
598     *(out++) = pc.blue;
599     *(out++) = pc.green;
600     *(out++) = pc.red;
601     )
602     /* *INDENT-ON* */
603     }
604     else if (g_xserver_be)
605     {
606     while (out < end)
607 jsorg71 483 {
608 jdmeijer 821 pixel = *(data++);
609     if (g_host_be)
610     {
611     BSWAP16(pixel);
612     }
613     SPLITCOLOUR15(pixel, pc);
614     value = MAKECOLOUR(pc);
615     BOUT24(out, value);
616 stargo 521 }
617 jdmeijer 821 }
618     else
619     {
620     while (out < end)
621 jsorg71 483 {
622 jdmeijer 821 pixel = *(data++);
623     if (g_host_be)
624     {
625     BSWAP16(pixel);
626     }
627     SPLITCOLOUR15(pixel, pc);
628     value = MAKECOLOUR(pc);
629     LOUT24(out, value);
630 jsorg71 483 }
631 matty 28 }
632     }
633    
634     static void
635 jdmeijer 821 translate15to32(const uint16 * data, uint8 * out, uint8 * end)
636 jsorg71 316 {
637 jsorg71 472 uint16 pixel;
638 jsorg71 483 uint32 value;
639 jdmeijer 821 PixelColour pc;
640 jsorg71 472
641 astrand 1049 if (g_compatible_arch)
642 jsorg71 472 {
643 jdmeijer 821 /* *INDENT-OFF* */
644     REPEAT4
645     (
646     pixel = *(data++);
647     SPLITCOLOUR15(pixel, pc);
648     *(out++) = pc.blue;
649     *(out++) = pc.green;
650     *(out++) = pc.red;
651     *(out++) = 0;
652     )
653     /* *INDENT-ON* */
654     }
655     else if (g_xserver_be)
656     {
657     while (out < end)
658 jsorg71 472 {
659 jdmeijer 821 pixel = *(data++);
660     if (g_host_be)
661     {
662     BSWAP16(pixel);
663     }
664     SPLITCOLOUR15(pixel, pc);
665     value = MAKECOLOUR(pc);
666     BOUT32(out, value);
667 jsorg71 472 }
668 jdmeijer 821 }
669     else
670     {
671     while (out < end)
672 jsorg71 483 {
673 jdmeijer 821 pixel = *(data++);
674     if (g_host_be)
675     {
676     BSWAP16(pixel);
677     }
678     SPLITCOLOUR15(pixel, pc);
679     value = MAKECOLOUR(pc);
680     LOUT32(out, value);
681 jsorg71 483 }
682 jsorg71 472 }
683 jsorg71 316 }
684    
685     static void
686 jdmeijer 821 translate16to16(const uint16 * data, uint8 * out, uint8 * end)
687 jsorg71 316 {
688 matthewc 528 uint16 pixel;
689 jsorg71 483 uint16 value;
690 jdmeijer 821 PixelColour pc;
691 jsorg71 483
692 jdmeijer 821 if (g_xserver_be)
693 jsorg71 483 {
694 matthewc 528 if (g_host_be)
695 jsorg71 483 {
696 jdmeijer 821 while (out < end)
697     {
698     pixel = *(data++);
699     BSWAP16(pixel);
700     SPLITCOLOUR16(pixel, pc);
701     value = MAKECOLOUR(pc);
702     BOUT16(out, value);
703     }
704 jsorg71 483 }
705 jdmeijer 821 else
706 jsorg71 483 {
707 jdmeijer 821 while (out < end)
708     {
709     pixel = *(data++);
710     SPLITCOLOUR16(pixel, pc);
711     value = MAKECOLOUR(pc);
712     BOUT16(out, value);
713     }
714 jsorg71 483 }
715 jdmeijer 821 }
716     else
717     {
718     if (g_host_be)
719     {
720     while (out < end)
721     {
722     pixel = *(data++);
723     BSWAP16(pixel);
724     SPLITCOLOUR16(pixel, pc);
725     value = MAKECOLOUR(pc);
726     LOUT16(out, value);
727     }
728     }
729 matthewc 528 else
730     {
731 jdmeijer 821 while (out < end)
732     {
733     pixel = *(data++);
734     SPLITCOLOUR16(pixel, pc);
735     value = MAKECOLOUR(pc);
736     LOUT16(out, value);
737     }
738 matthewc 528 }
739 jsorg71 483 }
740 jsorg71 316 }
741    
742     static void
743 jdmeijer 821 translate16to24(const uint16 * data, uint8 * out, uint8 * end)
744 matty 28 {
745 jsorg71 311 uint32 value;
746 jsorg71 483 uint16 pixel;
747 jdmeijer 821 PixelColour pc;
748 jsorg71 311
749 astrand 1049 if (g_compatible_arch)
750 jsorg71 311 {
751 jdmeijer 821 /* *INDENT-OFF* */
752     REPEAT3
753     (
754     pixel = *(data++);
755     SPLITCOLOUR16(pixel, pc);
756     *(out++) = pc.blue;
757     *(out++) = pc.green;
758     *(out++) = pc.red;
759     )
760     /* *INDENT-ON* */
761     }
762     else if (g_xserver_be)
763     {
764 jsorg71 483 if (g_host_be)
765     {
766 jdmeijer 821 while (out < end)
767     {
768     pixel = *(data++);
769     BSWAP16(pixel);
770     SPLITCOLOUR16(pixel, pc);
771     value = MAKECOLOUR(pc);
772     BOUT24(out, value);
773     }
774 stargo 521 }
775 jdmeijer 821 else
776 jsorg71 483 {
777 jdmeijer 821 while (out < end)
778     {
779     pixel = *(data++);
780     SPLITCOLOUR16(pixel, pc);
781     value = MAKECOLOUR(pc);
782     BOUT24(out, value);
783     }
784 jsorg71 483 }
785 jdmeijer 821 }
786     else
787     {
788     if (g_host_be)
789     {
790     while (out < end)
791     {
792     pixel = *(data++);
793     BSWAP16(pixel);
794     SPLITCOLOUR16(pixel, pc);
795     value = MAKECOLOUR(pc);
796     LOUT24(out, value);
797     }
798     }
799 jsorg71 483 else
800     {
801 jdmeijer 821 while (out < end)
802     {
803     pixel = *(data++);
804     SPLITCOLOUR16(pixel, pc);
805     value = MAKECOLOUR(pc);
806     LOUT24(out, value);
807     }
808 jsorg71 483 }
809 jsorg71 311 }
810     }
811    
812     static void
813 jdmeijer 821 translate16to32(const uint16 * data, uint8 * out, uint8 * end)
814 jsorg71 311 {
815 jsorg71 472 uint16 pixel;
816 jsorg71 483 uint32 value;
817 jdmeijer 821 PixelColour pc;
818 jsorg71 472
819 astrand 1049 if (g_compatible_arch)
820 jsorg71 472 {
821 jdmeijer 821 /* *INDENT-OFF* */
822     REPEAT4
823     (
824     pixel = *(data++);
825     SPLITCOLOUR16(pixel, pc);
826     *(out++) = pc.blue;
827     *(out++) = pc.green;
828     *(out++) = pc.red;
829     *(out++) = 0;
830     )
831     /* *INDENT-ON* */
832     }
833     else if (g_xserver_be)
834     {
835 jsorg71 472 if (g_host_be)
836     {
837 jdmeijer 821 while (out < end)
838     {
839     pixel = *(data++);
840     BSWAP16(pixel);
841     SPLITCOLOUR16(pixel, pc);
842     value = MAKECOLOUR(pc);
843     BOUT32(out, value);
844     }
845 stargo 534 }
846 jdmeijer 821 else
847 jsorg71 472 {
848 stargo 823 while (out < end)
849 jdmeijer 821 {
850     pixel = *(data++);
851     SPLITCOLOUR16(pixel, pc);
852     value = MAKECOLOUR(pc);
853     BOUT32(out, value);
854     }
855 astrand 499 }
856 jdmeijer 821 }
857     else
858     {
859     if (g_host_be)
860     {
861     while (out < end)
862     {
863     pixel = *(data++);
864     BSWAP16(pixel);
865     SPLITCOLOUR16(pixel, pc);
866     value = MAKECOLOUR(pc);
867     LOUT32(out, value);
868     }
869     }
870 astrand 499 else
871     {
872 jdmeijer 821 while (out < end)
873     {
874     pixel = *(data++);
875     SPLITCOLOUR16(pixel, pc);
876     value = MAKECOLOUR(pc);
877     LOUT32(out, value);
878     }
879 astrand 499 }
880     }
881 matty 28 }
882    
883 jsorg71 311 static void
884 jdmeijer 821 translate24to16(const uint8 * data, uint8 * out, uint8 * end)
885 jsorg71 311 {
886 jsorg71 316 uint32 pixel = 0;
887 jsorg71 483 uint16 value;
888 jdmeijer 821 PixelColour pc;
889    
890 jsorg71 311 while (out < end)
891 jsorg71 316 {
892     pixel = *(data++) << 16;
893     pixel |= *(data++) << 8;
894     pixel |= *(data++);
895 jdmeijer 821 SPLITCOLOUR24(pixel, pc);
896     value = MAKECOLOUR(pc);
897 jsorg71 483 if (g_xserver_be)
898     {
899 jdmeijer 821 BOUT16(out, value);
900 jsorg71 483 }
901     else
902     {
903 jdmeijer 821 LOUT16(out, value);
904 jsorg71 483 }
905 jsorg71 316 }
906 jsorg71 311 }
907    
908 jsorg71 316 static void
909 jdmeijer 821 translate24to24(const uint8 * data, uint8 * out, uint8 * end)
910 jsorg71 316 {
911 stargo 534 uint32 pixel;
912     uint32 value;
913 jdmeijer 821 PixelColour pc;
914 stargo 534
915 jdmeijer 821 if (g_xserver_be)
916 jsorg71 316 {
917 jdmeijer 821 while (out < end)
918 stargo 534 {
919 jdmeijer 821 pixel = *(data++) << 16;
920     pixel |= *(data++) << 8;
921     pixel |= *(data++);
922     SPLITCOLOUR24(pixel, pc);
923     value = MAKECOLOUR(pc);
924     BOUT24(out, value);
925 stargo 534 }
926 jdmeijer 821 }
927     else
928     {
929     while (out < end)
930 stargo 534 {
931 jdmeijer 821 pixel = *(data++) << 16;
932     pixel |= *(data++) << 8;
933     pixel |= *(data++);
934     SPLITCOLOUR24(pixel, pc);
935     value = MAKECOLOUR(pc);
936     LOUT24(out, value);
937 stargo 534 }
938 jsorg71 316 }
939     }
940    
941     static void
942 jdmeijer 821 translate24to32(const uint8 * data, uint8 * out, uint8 * end)
943 jsorg71 316 {
944 stargo 534 uint32 pixel;
945     uint32 value;
946 jdmeijer 821 PixelColour pc;
947 stargo 534
948 astrand 1049 if (g_compatible_arch)
949 jsorg71 316 {
950 jdmeijer 821 /* *INDENT-OFF* */
951 stargo 822 #ifdef NEED_ALIGN
952 jdmeijer 821 REPEAT4
953     (
954     *(out++) = *(data++);
955     *(out++) = *(data++);
956     *(out++) = *(data++);
957     *(out++) = 0;
958 stargo 822 )
959 jdmeijer 821 #else
960 stargo 822 REPEAT4
961     (
962 astrand 1041 /* Only read 3 bytes. Reading 4 bytes means reading beyond buffer. */
963 astrand 1040 *((uint32 *) out) = *((uint16 *) data) + (*((uint8 *) data + 2) << 16);
964     out += 4;
965     data += 3;
966 stargo 822 )
967 jdmeijer 821 #endif
968     /* *INDENT-ON* */
969     }
970     else if (g_xserver_be)
971     {
972     while (out < end)
973 jsorg71 472 {
974 jdmeijer 821 pixel = *(data++) << 16;
975     pixel |= *(data++) << 8;
976     pixel |= *(data++);
977     SPLITCOLOUR24(pixel, pc);
978     value = MAKECOLOUR(pc);
979     BOUT32(out, value);
980 jsorg71 472 }
981 jdmeijer 821 }
982     else
983     {
984     while (out < end)
985 jsorg71 472 {
986 jdmeijer 821 pixel = *(data++) << 16;
987     pixel |= *(data++) << 8;
988     pixel |= *(data++);
989     SPLITCOLOUR24(pixel, pc);
990     value = MAKECOLOUR(pc);
991     LOUT32(out, value);
992 jsorg71 472 }
993 jsorg71 316 }
994     }
995    
996 matty 29 static uint8 *
997 astrand 64 translate_image(int width, int height, uint8 * data)
998 matty 28 {
999 jsorg71 644 int size;
1000     uint8 *out;
1001     uint8 *end;
1002 matty 29
1003 astrand 1042 /*
1004     If RDP depth and X Visual depths match,
1005     and arch(endian) matches, no need to translate:
1006     just return data.
1007     Note: select_visual should've already ensured g_no_translate
1008     is only set for compatible depths, but the RDP depth might've
1009     changed during connection negotiations.
1010     */
1011     if (g_no_translate_image)
1012 jsorg71 645 {
1013 astrand 1042 if ((g_depth == 15 && g_server_depth == 15) ||
1014     (g_depth == 16 && g_server_depth == 16) ||
1015     (g_depth == 24 && g_server_depth == 24))
1016 jsorg71 645 return data;
1017     }
1018 jsorg71 644
1019     size = width * height * (g_bpp / 8);
1020     out = (uint8 *) xmalloc(size);
1021     end = out + size;
1022    
1023 astrand 1042 switch (g_server_depth)
1024 jsorg71 311 {
1025 jsorg71 316 case 24:
1026 jsorg71 450 switch (g_bpp)
1027 jsorg71 316 {
1028     case 32:
1029 jsorg71 483 translate24to32(data, out, end);
1030 jsorg71 316 break;
1031     case 24:
1032     translate24to24(data, out, end);
1033     break;
1034     case 16:
1035 jsorg71 483 translate24to16(data, out, end);
1036 jsorg71 316 break;
1037     }
1038 matty 29 break;
1039     case 16:
1040 jsorg71 450 switch (g_bpp)
1041 jsorg71 316 {
1042     case 32:
1043 jsorg71 483 translate16to32((uint16 *) data, out, end);
1044 jsorg71 316 break;
1045     case 24:
1046     translate16to24((uint16 *) data, out, end);
1047     break;
1048     case 16:
1049 matthewc 528 translate16to16((uint16 *) data, out, end);
1050 jsorg71 316 break;
1051     }
1052 matty 29 break;
1053 jsorg71 316 case 15:
1054 jsorg71 450 switch (g_bpp)
1055 jsorg71 316 {
1056     case 32:
1057 jsorg71 483 translate15to32((uint16 *) data, out, end);
1058 jsorg71 316 break;
1059     case 24:
1060     translate15to24((uint16 *) data, out, end);
1061     break;
1062     case 16:
1063 jsorg71 483 translate15to16((uint16 *) data, out, end);
1064 jsorg71 316 break;
1065     }
1066 matty 29 break;
1067 jsorg71 316 case 8:
1068 jsorg71 450 switch (g_bpp)
1069 jsorg71 316 {
1070     case 8:
1071     translate8to8(data, out, end);
1072     break;
1073     case 16:
1074 stargo 521 translate8to16(data, out, end);
1075 jsorg71 316 break;
1076     case 24:
1077     translate8to24(data, out, end);
1078     break;
1079     case 32:
1080 stargo 521 translate8to32(data, out, end);
1081 jsorg71 316 break;
1082     }
1083 matty 29 break;
1084     }
1085     return out;
1086 matty 28 }
1087    
1088 astrand 118 BOOL
1089 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
1090 astrand 102 {
1091 matthewc 203 int modifierpos, key, keysymMask = 0;
1092 astrand 102 int offset;
1093    
1094 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
1095 astrand 102
1096     if (keycode == NoSymbol)
1097     return False;
1098    
1099     for (modifierpos = 0; modifierpos < 8; modifierpos++)
1100     {
1101 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
1102 astrand 102
1103 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
1104 astrand 102 {
1105 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
1106 matthewc 203 keysymMask |= 1 << modifierpos;
1107 astrand 102 }
1108     }
1109    
1110 matthewc 203 return (state & keysymMask) ? True : False;
1111 astrand 102 }
1112    
1113 matthewc 527 static void
1114     calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
1115     {
1116     *shift_l = ffs(mask) - 1;
1117     mask >>= *shift_l;
1118     *shift_r = 8 - ffs(mask & ~(mask >> 1));
1119     }
1120    
1121 astrand 1042 /* Given a mask of a colour channel (e.g. XVisualInfo.red_mask),
1122     calculates the bits-per-pixel of this channel (a.k.a. colour weight).
1123     */
1124     static unsigned
1125     calculate_mask_weight(uint32 mask)
1126 jsorg71 81 {
1127 astrand 1042 unsigned weight = 0;
1128     do
1129     {
1130     weight += (mask & 1);
1131     }
1132     while (mask >>= 1);
1133     return weight;
1134     }
1135    
1136     static BOOL
1137     select_visual()
1138     {
1139 matthewc 121 XPixmapFormatValues *pfm;
1140 astrand 1042 int pixmap_formats_count, visuals_count;
1141 stargo 565 XVisualInfo *vmatches = NULL;
1142     XVisualInfo template;
1143 astrand 1042 int i;
1144     unsigned red_weight, blue_weight, green_weight;
1145 matthewc 121
1146 astrand 1042 red_weight = blue_weight = green_weight = 0;
1147    
1148     pfm = XListPixmapFormats(g_display, &pixmap_formats_count);
1149     if (pfm == NULL)
1150 jsorg71 81 {
1151 astrand 1042 error("Unable to get list of pixmap formats from display.\n");
1152     XCloseDisplay(g_display);
1153 jsorg71 81 return False;
1154     }
1155 matthewc 121
1156 astrand 1042 /* Search for best TrueColor visual */
1157 stargo 565 template.class = TrueColor;
1158 astrand 1042 vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1159     g_visual = NULL;
1160     g_no_translate_image = False;
1161 astrand 1049 g_compatible_arch = False;
1162 astrand 1042 if (vmatches != NULL)
1163 matthewc 527 {
1164 astrand 1042 for (i = 0; i < visuals_count; ++i)
1165 stargo 565 {
1166 astrand 1042 XVisualInfo *visual_info = &vmatches[i];
1167 stargo 565
1168 astrand 1042 /* Try to find a no-translation visual that'll
1169     allow us to use RDP bitmaps directly as ZPixmaps. */
1170     if (!g_xserver_be && (((visual_info->depth == 15) &&
1171     /* R5G5B5 */
1172     (visual_info->red_mask == 0x7c00) &&
1173     (visual_info->green_mask == 0x3e0) &&
1174     (visual_info->blue_mask == 0x1f)) ||
1175     ((visual_info->depth == 16) &&
1176     /* R5G6B5 */
1177     (visual_info->red_mask == 0xf800) &&
1178     (visual_info->green_mask == 0x7e0) &&
1179     (visual_info->blue_mask == 0x1f)) ||
1180     ((visual_info->depth == 24) &&
1181     /* R8G8B8 */
1182     (visual_info->red_mask == 0xff0000) &&
1183     (visual_info->green_mask == 0xff00) &&
1184     (visual_info->blue_mask == 0xff))))
1185     {
1186     g_visual = visual_info->visual;
1187     g_depth = visual_info->depth;
1188 astrand 1049 g_compatible_arch = !g_host_be;
1189 astrand 1042 g_no_translate_image = (visual_info->depth == g_server_depth);
1190     if (g_no_translate_image)
1191     /* We found the best visual */
1192     break;
1193     }
1194     else
1195     {
1196 astrand 1049 g_compatible_arch = False;
1197 astrand 1042 }
1198 jsorg71 644
1199 astrand 1042 if (visual_info->depth > 24)
1200     {
1201     /* Avoid 32-bit visuals and likes like the plague.
1202     They're either untested or proven to work bad
1203     (e.g. nvidia's Composite 32-bit visual).
1204     Most implementation offer a 24-bit visual anyway. */
1205     continue;
1206     }
1207 stargo 565
1208 astrand 1042 /* Only care for visuals, for whose BPPs (not depths!)
1209     we have a translateXtoY function. */
1210     BOOL can_translate_to_bpp = False;
1211     int j;
1212     for (j = 0; j < pixmap_formats_count; ++j)
1213     {
1214     if (pfm[j].depth == visual_info->depth)
1215     {
1216     if ((pfm[j].bits_per_pixel == 16) ||
1217     (pfm[j].bits_per_pixel == 24) ||
1218     (pfm[j].bits_per_pixel == 32))
1219     {
1220     can_translate_to_bpp = True;
1221     }
1222     break;
1223     }
1224     }
1225    
1226     /* Prefer formats which have the most colour depth.
1227     We're being truly aristocratic here, minding each
1228     weight on its own. */
1229     if (can_translate_to_bpp)
1230     {
1231     unsigned vis_red_weight =
1232     calculate_mask_weight(visual_info->red_mask);
1233     unsigned vis_green_weight =
1234     calculate_mask_weight(visual_info->green_mask);
1235     unsigned vis_blue_weight =
1236     calculate_mask_weight(visual_info->blue_mask);
1237     if ((vis_red_weight >= red_weight)
1238     && (vis_green_weight >= green_weight)
1239     && (vis_blue_weight >= blue_weight))
1240     {
1241     red_weight = vis_red_weight;
1242     green_weight = vis_green_weight;
1243     blue_weight = vis_blue_weight;
1244     g_visual = visual_info->visual;
1245     g_depth = visual_info->depth;
1246     }
1247     }
1248 stargo 565 }
1249 astrand 1042 XFree(vmatches);
1250 matthewc 527 }
1251 astrand 1042
1252     if (g_visual != NULL)
1253     {
1254     g_owncolmap = False;
1255     calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1256     calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1257     calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1258     }
1259 matthewc 527 else
1260     {
1261 astrand 1042 template.class = PseudoColor;
1262     template.depth = 8;
1263     template.colormap_size = 256;
1264     vmatches =
1265     XGetVisualInfo(g_display,
1266     VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1267     &template, &visuals_count);
1268     if (vmatches == NULL)
1269 matthewc 527 {
1270 astrand 1042 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1271     XCloseDisplay(g_display);
1272     XFree(pfm);
1273 matthewc 527 return False;
1274     }
1275    
1276 astrand 1042 /* we use a colourmap, so the default visual should do */
1277     g_owncolmap = True;
1278     g_visual = vmatches[0].visual;
1279     g_depth = vmatches[0].depth;
1280     }
1281 jsorg71 644
1282 astrand 1042 g_bpp = 0;
1283     for (i = 0; i < pixmap_formats_count; ++i)
1284     {
1285     XPixmapFormatValues *pf = &pfm[i];
1286     if (pf->depth == g_depth)
1287 jdmeijer 821 {
1288 astrand 1042 g_bpp = pf->bits_per_pixel;
1289    
1290     if (g_no_translate_image)
1291 jdmeijer 821 {
1292 astrand 1042 switch (g_server_depth)
1293     {
1294     case 15:
1295     case 16:
1296     if (g_bpp != 16)
1297     g_no_translate_image = False;
1298     break;
1299     case 24:
1300     /* Yes, this will force image translation
1301     on most modern servers which use 32 bits
1302     for R8G8B8. */
1303     if (g_bpp != 24)
1304     g_no_translate_image = False;
1305     break;
1306     default:
1307     g_no_translate_image = False;
1308     break;
1309     }
1310 jdmeijer 821 }
1311    
1312 astrand 1042 /* Pixmap formats list is a depth-to-bpp mapping --
1313     there's just a single entry for every depth,
1314     so we can safely break here */
1315     break;
1316 jdmeijer 821 }
1317 matthewc 527 }
1318 astrand 1042 XFree(pfm);
1319     pfm = NULL;
1320     return True;
1321     }
1322 matthewc 527
1323 astrand 1042 BOOL
1324     ui_init(void)
1325     {
1326     int screen_num;
1327    
1328     g_display = XOpenDisplay(NULL);
1329     if (g_display == NULL)
1330 matthewc 121 {
1331 astrand 1042 error("Failed to open display: %s\n", XDisplayName(NULL));
1332     return False;
1333 matthewc 121 }
1334    
1335     {
1336 astrand 1042 uint16 endianess_test = 1;
1337     g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1338     }
1339    
1340     g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1341     screen_num = DefaultScreen(g_display);
1342     g_x_socket = ConnectionNumber(g_display);
1343     g_screen = ScreenOfDisplay(g_display, screen_num);
1344     g_depth = DefaultDepthOfScreen(g_screen);
1345    
1346     if (!select_visual())
1347 matthewc 121 return False;
1348 astrand 1042
1349     if (g_no_translate_image)
1350     {
1351     DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1352 matthewc 121 }
1353    
1354 astrand 1042 if (g_server_depth > g_bpp)
1355     {
1356     warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1357     g_server_depth, g_bpp);
1358     }
1359    
1360     DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1361     g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1362    
1363 matthewc 517 if (!g_owncolmap)
1364 n-ki 279 {
1365 astrand 580 g_xcolmap =
1366     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1367     AllocNone);
1368 jsorg71 450 if (g_depth <= 8)
1369 astrand 1042 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1370 n-ki 279 }
1371    
1372 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1373     {
1374 astrand 1042 warning("External BackingStore not available. Using internal.\n");
1375 jsorg71 450 g_ownbackstore = True;
1376 stargo 609 }
1377 matthewc 121
1378 astrand 500 /*
1379     * Determine desktop size
1380     */
1381 astrand 547 if (g_fullscreen)
1382 astrand 263 {
1383 astrand 547 g_width = WidthOfScreen(g_screen);
1384     g_height = HeightOfScreen(g_screen);
1385 astrand 1057 g_using_full_workarea = True;
1386 astrand 547 }
1387     else if (g_width < 0)
1388     {
1389 astrand 500 /* Percent of screen */
1390 astrand 991 if (-g_width >= 100)
1391     g_using_full_workarea = True;
1392 astrand 500 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1393     g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1394     }
1395     else if (g_width == 0)
1396     {
1397 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1398 matthewc 300 uint32 x, y, cx, cy;
1399     if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1400 astrand 263 {
1401 jsorg71 447 g_width = cx;
1402     g_height = cy;
1403 astrand 1057 g_using_full_workarea = True;
1404 matthewc 300 }
1405     else
1406     {
1407 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1408 astrand 1057 g_width = WidthOfScreen(g_screen);
1409     g_height = HeightOfScreen(g_screen);
1410 astrand 263 }
1411     }
1412 matthewc 121
1413 matthewc 160 /* make sure width is a multiple of 4 */
1414 jsorg71 447 g_width = (g_width + 3) & ~3;
1415 matthewc 160
1416 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1417 matthewc 203
1418 astrand 498 xkeymap_init();
1419    
1420 jsorg71 447 if (g_enable_compose)
1421 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1422 matthewc 188
1423 matthewc 432 xclip_init();
1424 astrand 1118 ewmh_init();
1425 astrand 1089 if (g_seamless_rdp)
1426     seamless_init();
1427 jsorg71 316
1428 astrand 1042 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1429 jsorg71 316
1430 jsorg71 81 return True;
1431     }
1432 astrand 66
1433 matthewc 188 void
1434 matthewc 192 ui_deinit(void)
1435 matthewc 188 {
1436 jsorg71 450 if (g_IM != NULL)
1437     XCloseIM(g_IM);
1438 astrand 580
1439 stargo 576 if (g_null_cursor != NULL)
1440     ui_destroy_cursor(g_null_cursor);
1441 matthewc 188
1442 jsorg71 450 XFreeModifiermap(g_mod_map);
1443 matthewc 203
1444 jsorg71 450 if (g_ownbackstore)
1445     XFreePixmap(g_display, g_backstore);
1446 matthewc 188
1447 jsorg71 450 XFreeGC(g_display, g_gc);
1448     XCloseDisplay(g_display);
1449     g_display = NULL;
1450 matthewc 188 }
1451    
1452 astrand 1089
1453     static void
1454     get_window_attribs(XSetWindowAttributes * attribs)
1455     {
1456     attribs->background_pixel = BlackPixelOfScreen(g_screen);
1457     attribs->background_pixel = WhitePixelOfScreen(g_screen);
1458     attribs->border_pixel = WhitePixelOfScreen(g_screen);
1459     attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1460     attribs->override_redirect = g_fullscreen;
1461     attribs->colormap = g_xcolmap;
1462     }
1463    
1464     static void
1465     get_input_mask(long *input_mask)
1466     {
1467     *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1468     VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1469    
1470     if (g_sendmotion)
1471     *input_mask |= PointerMotionMask;
1472     if (g_ownbackstore)
1473     *input_mask |= ExposureMask;
1474     if (g_fullscreen || g_grab_keyboard)
1475     *input_mask |= EnterWindowMask;
1476     if (g_grab_keyboard)
1477     *input_mask |= LeaveWindowMask;
1478     }
1479    
1480 matthewc 121 BOOL
1481 matthewc 192 ui_create_window(void)
1482 matty 6 {
1483 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1484 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1485    
1486 matthewc 121 XSetWindowAttributes attribs;
1487 matty 28 XClassHint *classhints;
1488     XSizeHints *sizehints;
1489 matthewc 188 int wndwidth, wndheight;
1490 matthewc 432 long input_mask, ic_input_mask;
1491 jsorg71 100 XEvent xevent;
1492    
1493 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1494     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1495 matthewc 188
1496 stargo 867 /* Handle -x-y portion of geometry string */
1497     if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1498     g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1499     if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1500     g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1501    
1502 astrand 1089 get_window_attribs(&attribs);
1503 matthewc 188
1504 astrand 801 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1505     wndheight, 0, g_depth, InputOutput, g_visual,
1506     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1507     CWBorderPixel, &attribs);
1508 jsorg71 100
1509 stargo 576 if (g_gc == NULL)
1510 astrand 1089 {
1511 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1512 astrand 1089 ui_reset_clip();
1513     }
1514 stargo 565
1515 jsorg71 725 if (g_create_bitmap_gc == NULL)
1516     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1517    
1518 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
1519 stargo 565 {
1520 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1521 stargo 565
1522     /* clear to prevent rubbish being exposed at startup */
1523     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1524     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1525     }
1526    
1527 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
1528 jsorg71 100
1529 jsorg71 450 if (g_hide_decorations)
1530 astrand 1089 mwm_hide_decorations(g_wnd);
1531 astrand 262
1532 jsorg71 100 classhints = XAllocClassHint();
1533     if (classhints != NULL)
1534     {
1535     classhints->res_name = classhints->res_class = "rdesktop";
1536 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
1537 jsorg71 100 XFree(classhints);
1538     }
1539    
1540     sizehints = XAllocSizeHints();
1541     if (sizehints)
1542     {
1543     sizehints->flags = PMinSize | PMaxSize;
1544 stargo 867 if (g_pos)
1545     sizehints->flags |= PPosition;
1546 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
1547     sizehints->min_height = sizehints->max_height = g_height;
1548 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
1549 jsorg71 100 XFree(sizehints);
1550     }
1551    
1552 astrand 651 if (g_embed_wnd)
1553     {
1554     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1555     }
1556 stargo 636
1557 astrand 1089 get_input_mask(&input_mask);
1558 matthewc 121
1559 jsorg71 450 if (g_IM != NULL)
1560 matthewc 188 {
1561 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1562 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1563 matthewc 188
1564 jsorg71 450 if ((g_IC != NULL)
1565     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1566 matthewc 188 input_mask |= ic_input_mask;
1567     }
1568    
1569 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
1570 ossman_ 1149
1571     XMapWindow(g_display, g_wnd);
1572     /* wait for VisibilityNotify */
1573     do
1574 astrand 196 {
1575 ossman_ 1149 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1576 astrand 196 }
1577 ossman_ 1149 while (xevent.type != VisibilityNotify);
1578     g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
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 ossman_ 1149 if (g_seamless_active)
1643 astrand 1089 /* 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 ossman_ 1149 if (!g_seamless_active)
1992 astrand 1089 rdp_send_client_window_status(1);
1993 jdmeijer 905 break;
1994     case UnmapNotify:
1995 ossman_ 1149 if (!g_seamless_active)
1996 astrand 1089 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 ossman_ 1149 ui_seamless_begin()
3010     {
3011     if (!g_seamless_rdp)
3012     return;
3013    
3014     if (g_seamless_started)
3015     return;
3016    
3017     g_seamless_started = True;
3018    
3019     ui_seamless_toggle();
3020     }
3021    
3022     void
3023 astrand 1089 ui_seamless_toggle()
3024     {
3025 ossman_ 1149 if (!g_seamless_rdp)
3026     return;
3027    
3028     if (!g_seamless_started)
3029     return;
3030    
3031     if (g_seamless_active)
3032 astrand 1089 {
3033     /* Deactivate */
3034     while (g_seamless_windows)
3035     {
3036     XDestroyWindow(g_display, g_seamless_windows->wnd);
3037     seamless_remove_window(g_seamless_windows);
3038     }
3039     XMapWindow(g_display, g_wnd);
3040     }
3041     else
3042     {
3043     /* Activate */
3044     XUnmapWindow(g_display, g_wnd);
3045     seamless_send_sync();
3046     }
3047    
3048 ossman_ 1149 g_seamless_active = !g_seamless_active;
3049 astrand 1089 }
3050    
3051     void
3052 astrand 1098 ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3053 astrand 1089 {
3054     Window wnd;
3055     XSetWindowAttributes attribs;
3056     XClassHint *classhints;
3057 astrand 1132 XSizeHints *sizehints;
3058 astrand 1089 long input_mask;
3059 astrand 1101 seamless_window *sw, *sw_parent;
3060 astrand 1089
3061 ossman_ 1149 if (!g_seamless_active)
3062     return;
3063    
3064 astrand 1122 /* Ignore CREATEs for existing windows */
3065     sw = seamless_get_window_by_id(id);
3066     if (sw)
3067     return;
3068    
3069 astrand 1089 get_window_attribs(&attribs);
3070     attribs.override_redirect = False;
3071    
3072 astrand 1132 wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3073 astrand 1089 InputOutput, g_visual,
3074     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3075     CWBorderPixel, &attribs);
3076    
3077 astrand 1133 XStoreName(g_display, wnd, "SeamlessRDP");
3078 astrand 1139 ewmh_set_wm_name(wnd, "SeamlessRDP");
3079 astrand 1089
3080     mwm_hide_decorations(wnd);
3081    
3082     classhints = XAllocClassHint();
3083     if (classhints != NULL)
3084     {
3085 astrand 1133 classhints->res_name = "rdesktop";
3086     classhints->res_class = "SeamlessRDP";
3087 astrand 1089 XSetClassHint(g_display, wnd, classhints);
3088     XFree(classhints);
3089     }
3090    
3091 astrand 1132 /* WM_NORMAL_HINTS */
3092     sizehints = XAllocSizeHints();
3093     if (sizehints != NULL)
3094     {
3095     sizehints->flags = USPosition;
3096     XSetWMNormalHints(g_display, wnd, sizehints);
3097     XFree(sizehints);
3098     }
3099    
3100 astrand 1101 /* Set WM_TRANSIENT_FOR, if necessary */
3101 ossman_ 1143 if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3102 astrand 1103 {
3103     sw_parent = seamless_get_window_by_id(parent);
3104     if (sw_parent)
3105     XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3106     else
3107     warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3108     }
3109 astrand 1101
3110 ossman_ 1137
3111 astrand 1089 /* FIXME: Support for Input Context:s */
3112    
3113     get_input_mask(&input_mask);
3114 astrand 1118 input_mask |= PropertyChangeMask;
3115 astrand 1089
3116     XSelectInput(g_display, wnd, input_mask);
3117    
3118     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3119     seamless window, we could try to close the window on the
3120     serverside, instead of terminating rdesktop */
3121     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3122    
3123     sw = malloc(sizeof(seamless_window));
3124     sw->wnd = wnd;
3125     sw->id = id;
3126 ossman_ 1143 sw->parent = parent;
3127 astrand 1089 sw->xoffset = 0;
3128     sw->yoffset = 0;
3129     sw->width = 0;
3130     sw->height = 0;
3131 astrand 1132 sw->state = SEAMLESSRDP_NOTYETMAPPED;
3132     sw->desktop = 0;
3133 astrand 1089 sw->next = g_seamless_windows;
3134     g_seamless_windows = sw;
3135     }
3136    
3137    
3138     void
3139     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3140     {
3141     seamless_window *sw;
3142 astrand 1107
3143 ossman_ 1149 if (!g_seamless_active)
3144     return;
3145    
3146 astrand 1089 sw = seamless_get_window_by_id(id);
3147     if (!sw)
3148     {
3149     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3150     return;
3151     }
3152    
3153     XDestroyWindow(g_display, sw->wnd);
3154     seamless_remove_window(sw);
3155     }
3156    
3157    
3158     void
3159     ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3160     {
3161     seamless_window *sw;
3162    
3163 ossman_ 1149 if (!g_seamless_active)
3164     return;
3165    
3166 astrand 1089 sw = seamless_get_window_by_id(id);
3167     if (!sw)
3168     {
3169     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3170     return;
3171     }
3172    
3173     if (!width || !height)
3174     /* X11 windows must be at least 1x1 */
3175     return;
3176    
3177     /* About MAX and MIN: Windows allows moving a window outside
3178     the desktop. This happens, for example, when maximizing an
3179     application. In this case, the position is set to something
3180     like -4,-4,1288,1032. Many WMs does not allow windows
3181     outside the desktop, however. Therefore, clip the window
3182     ourselves. */
3183     sw->xoffset = MAX(0, x);
3184     sw->yoffset = MAX(0, y);
3185     sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3186     sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3187    
3188 astrand 1118 /* If we move the window in a maximized state, then KDE won't
3189     accept restoration */
3190 astrand 1132 switch (sw->state)
3191     {
3192     case SEAMLESSRDP_MINIMIZED:
3193     case SEAMLESSRDP_MAXIMIZED:
3194     return;
3195     }
3196 astrand 1118
3197 astrand 1089 /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3198     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3199     }
3200    
3201    
3202     void
3203 astrand 1094 ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3204 astrand 1089 {
3205     seamless_window *sw;
3206    
3207 ossman_ 1149 if (!g_seamless_active)
3208     return;
3209    
3210 astrand 1089 sw = seamless_get_window_by_id(id);
3211 astrand 1107 if (!sw)
3212     {
3213     warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3214     return;
3215     }
3216 astrand 1089
3217 astrand 1139 /* FIXME: Might want to convert the name for non-EWMH WMs */
3218 astrand 1089 XStoreName(g_display, sw->wnd, title);
3219 astrand 1139 ewmh_set_wm_name(sw->wnd, title);
3220 astrand 1089 }
3221    
3222    
3223     void
3224     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3225     {
3226     seamless_window *sw;
3227    
3228 ossman_ 1149 if (!g_seamless_active)
3229     return;
3230    
3231 astrand 1089 sw = seamless_get_window_by_id(id);
3232 astrand 1107 if (!sw)
3233     {
3234     warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3235     return;
3236     }
3237 astrand 1089
3238     switch (state)
3239     {
3240     case SEAMLESSRDP_NORMAL:
3241     case SEAMLESSRDP_MAXIMIZED:
3242 astrand 1118 ewmh_change_state(sw->wnd, state);
3243 ossman_ 1142 XMapWindow(g_display, sw->wnd);
3244 astrand 1089 break;
3245     case SEAMLESSRDP_MINIMIZED:
3246 astrand 1118 /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3247     the Window Manager should probably just ignore the request, since
3248     _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3249     such as minimization, rather than an independent state." Besides,
3250     XIconifyWindow is easier. */
3251 ossman_ 1142 if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3252     {
3253 ossman_ 1144 XWMHints *hints;
3254     hints = XAllocWMHints();
3255     hints->flags = StateHint;
3256     hints->initial_state = IconicState;
3257     XSetWMHints(g_display, sw->wnd, hints);
3258     XFree(hints);
3259 ossman_ 1142 XMapWindow(g_display, sw->wnd);
3260     }
3261     else
3262     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3263 astrand 1089 break;
3264     default:
3265     warning("SeamlessRDP: Invalid state %d\n", state);
3266     break;
3267     }
3268 ossman_ 1142
3269 ossman_ 1143 /* Handle popups without parents through some ewm hints */
3270     if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3271     ewmh_set_window_popup(sw->wnd);
3272    
3273 ossman_ 1142 sw->state = state;
3274 astrand 1089 }
3275 astrand 1123
3276    
3277     void
3278     ui_seamless_syncbegin(unsigned long flags)
3279     {
3280 ossman_ 1149 if (!g_seamless_active)
3281     return;
3282    
3283 astrand 1123 /* Destroy all seamless windows */
3284     while (g_seamless_windows)
3285     {
3286     XDestroyWindow(g_display, g_seamless_windows->wnd);
3287     seamless_remove_window(g_seamless_windows);
3288     }
3289     }

  ViewVC Help
Powered by ViewVC 1.1.26