/[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 1154 - (hide annotations)
Fri Mar 17 09:56:20 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 78140 byte(s)
Detect focus changes and send FOCUS to the server.

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 ossman_ 1151 static void
1748     ui_seamless_handle_restack(seamless_window * sw)
1749     {
1750     Status status;
1751     Window root, parent, *children;
1752     unsigned int nchildren, i;
1753     seamless_window *sw_below;
1754    
1755     status = XQueryTree(g_display, RootWindowOfScreen(g_screen),
1756     &root, &parent, &children, &nchildren);
1757     if (!status || !nchildren)
1758     return;
1759    
1760     sw_below = NULL;
1761    
1762     i = 0;
1763     while (children[i] != sw->wnd)
1764     {
1765     i++;
1766     if (i >= nchildren)
1767     return;
1768     }
1769    
1770     for (i++; i < nchildren; i++)
1771     {
1772     sw_below = seamless_get_window_by_wnd(children[i]);
1773     if (sw_below)
1774     break;
1775     }
1776    
1777     if (sw_below)
1778     seamless_send_zchange(sw->id, sw_below->id, 0);
1779     else
1780     seamless_send_zchange(sw->id, 0, 0);
1781     }
1782    
1783 stargo 887 /* Process events in Xlib queue
1784 astrand 275 Returns 0 after user quit, 1 otherwise */
1785     static int
1786 matthewc 192 xwin_process_events(void)
1787 matty 9 {
1788 n-ki 54 XEvent xevent;
1789 matthewc 38 KeySym keysym;
1790 matty 10 uint32 ev_time;
1791 astrand 66 char str[256];
1792     Status status;
1793 stargo 887 int events = 0;
1794 astrand 1094 seamless_window *sw;
1795 matty 9
1796 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
1797 matty 9 {
1798 jsorg71 450 XNextEvent(g_display, &xevent);
1799 matthewc 123
1800 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1801 astrand 66 {
1802 astrand 84 DEBUG_KBD(("Filtering event\n"));
1803 astrand 66 continue;
1804     }
1805    
1806 n-ki 54 switch (xevent.type)
1807 matty 9 {
1808 jsorg71 688 case VisibilityNotify:
1809 astrand 1089 if (xevent.xvisibility.window == g_wnd)
1810     g_Unobscured =
1811     xevent.xvisibility.state == VisibilityUnobscured;
1812    
1813 jsorg71 688 break;
1814 astrand 275 case ClientMessage:
1815     /* the window manager told us to quit */
1816 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
1817     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1818 astrand 275 /* Quit */
1819     return 0;
1820     break;
1821    
1822 matty 9 case KeyPress:
1823 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1824     if (g_IC != NULL)
1825 astrand 66 /* Multi_key compatible version */
1826     {
1827 jsorg71 450 XmbLookupString(g_IC,
1828 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
1829     &status);
1830 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1831 astrand 66 {
1832 astrand 82 error("XmbLookupString failed with status 0x%x\n",
1833     status);
1834 astrand 66 break;
1835     }
1836     }
1837     else
1838     {
1839     /* Plain old XLookupString */
1840 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1841 astrand 66 XLookupString((XKeyEvent *) & xevent,
1842 astrand 82 str, sizeof(str), &keysym, NULL);
1843 astrand 66 }
1844    
1845 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1846 astrand 261 get_ksname(keysym)));
1847 astrand 66
1848 matthewc 203 ev_time = time(NULL);
1849     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1850 astrand 118 break;
1851    
1852 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1853 astrand 976 ev_time, True, 0);
1854 astrand 66 break;
1855 matthewc 203
1856 astrand 66 case KeyRelease:
1857 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1858 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
1859     sizeof(str), &keysym, NULL);
1860 n-ki 52
1861 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1862 matthewc 203 get_ksname(keysym)));
1863 n-ki 52
1864 matthewc 203 ev_time = time(NULL);
1865     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1866 astrand 118 break;
1867    
1868 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1869 astrand 976 ev_time, False, 0);
1870 matty 9 break;
1871    
1872     case ButtonPress:
1873 astrand 988 handle_button_event(xevent, True);
1874     break;
1875 matty 9
1876     case ButtonRelease:
1877 astrand 988 handle_button_event(xevent, False);
1878 matty 10 break;
1879    
1880     case MotionNotify:
1881 jsorg71 450 if (g_moving_wnd)
1882 astrand 342 {
1883 jsorg71 450 XMoveWindow(g_display, g_wnd,
1884     xevent.xmotion.x_root - g_move_x_offset,
1885     xevent.xmotion.y_root - g_move_y_offset);
1886 astrand 342 break;
1887     }
1888    
1889 jsorg71 447 if (g_fullscreen && !g_focused)
1890 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1891 jsorg71 288 CurrentTime);
1892 astrand 1089
1893     if (xevent.xmotion.window == g_wnd)
1894     {
1895     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1896     xevent.xmotion.x, xevent.xmotion.y);
1897     }
1898     else
1899     {
1900     /* SeamlessRDP */
1901     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
1902     xevent.xmotion.x_root,
1903     xevent.xmotion.y_root);
1904     }
1905 matty 28 break;
1906    
1907 matthewc 194 case FocusIn:
1908 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
1909     break;
1910 jsorg71 447 g_focused = True;
1911 astrand 543 reset_modifier_keys();
1912 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
1913     XGrabKeyboard(g_display, g_wnd, True,
1914 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
1915 ossman_ 1154
1916     sw = seamless_get_window_by_wnd(xevent.xfocus.window);
1917     if (!sw)
1918     break;
1919    
1920     seamless_send_focus(sw->id, 0);
1921 matty 28 break;
1922    
1923 matthewc 194 case FocusOut:
1924 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
1925     break;
1926 jsorg71 447 g_focused = False;
1927 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1928 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
1929 matty 28 break;
1930 matty 31
1931 matthewc 250 case EnterNotify:
1932     /* we only register for this event when in fullscreen mode */
1933 jsorg71 257 /* or grab_keyboard */
1934 jsorg71 447 g_mouse_in_wnd = True;
1935     if (g_fullscreen)
1936 jsorg71 257 {
1937 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1938 astrand 261 CurrentTime);
1939 jsorg71 257 break;
1940     }
1941 jsorg71 447 if (g_focused)
1942 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
1943 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
1944 matthewc 250 break;
1945    
1946 matthewc 253 case LeaveNotify:
1947 jsorg71 257 /* we only register for this event when grab_keyboard */
1948 jsorg71 447 g_mouse_in_wnd = False;
1949 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
1950 matthewc 253 break;
1951    
1952 matty 31 case Expose:
1953 astrand 1089 if (xevent.xexpose.window == g_wnd)
1954     {
1955     XCopyArea(g_display, g_backstore, xevent.xexpose.window,
1956     g_gc,
1957     xevent.xexpose.x, xevent.xexpose.y,
1958     xevent.xexpose.width, xevent.xexpose.height,
1959     xevent.xexpose.x, xevent.xexpose.y);
1960     }
1961     else
1962     {
1963     sw = seamless_get_window_by_wnd(xevent.xexpose.window);
1964     if (sw)
1965     XCopyArea(g_display, g_backstore,
1966     xevent.xexpose.window, g_gc,
1967     xevent.xexpose.x + sw->xoffset,
1968     xevent.xexpose.y + sw->yoffset,
1969     xevent.xexpose.width,
1970     xevent.xexpose.height, xevent.xexpose.x,
1971     xevent.xexpose.y);
1972 astrand 1107 else
1973     {
1974     error("Expose for unknown window 0x%lx\n",
1975     xevent.xexpose.window);
1976     }
1977 astrand 1089 }
1978    
1979 matty 31 break;
1980 astrand 119
1981     case MappingNotify:
1982     /* Refresh keyboard mapping if it has changed. This is important for
1983     Xvnc, since it allocates keycodes dynamically */
1984     if (xevent.xmapping.request == MappingKeyboard
1985     || xevent.xmapping.request == MappingModifier)
1986     XRefreshKeyboardMapping(&xevent.xmapping);
1987 matthewc 203
1988     if (xevent.xmapping.request == MappingModifier)
1989     {
1990 jsorg71 450 XFreeModifiermap(g_mod_map);
1991     g_mod_map = XGetModifierMapping(g_display);
1992 matthewc 203 }
1993 astrand 119 break;
1994 matthewc 432
1995 astrand 435 /* clipboard stuff */
1996 forsberg 415 case SelectionNotify:
1997 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
1998 forsberg 415 break;
1999     case SelectionRequest:
2000 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2001 forsberg 415 break;
2002 matthewc 432 case SelectionClear:
2003     xclip_handle_SelectionClear();
2004     break;
2005 forsberg 415 case PropertyNotify:
2006 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
2007 astrand 1118 if (xevent.xproperty.window == g_wnd)
2008     break;
2009     if (xevent.xproperty.window == DefaultRootWindow(g_display))
2010     break;
2011    
2012     /* seamless */
2013     sw = seamless_get_window_by_wnd(xevent.xproperty.window);
2014     if (!sw)
2015     break;
2016    
2017     if ((xevent.xproperty.atom == g_net_wm_state_atom)
2018     && (xevent.xproperty.state == PropertyNewValue))
2019     {
2020     sw->state = ewmh_get_window_state(sw->wnd);
2021     seamless_send_state(sw->id, sw->state, 0);
2022     }
2023 astrand 1119
2024     if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2025     && (xevent.xproperty.state == PropertyNewValue))
2026     {
2027     sw->desktop = ewmh_get_window_desktop(sw->wnd);
2028     seamless_all_to_desktop(sw->wnd, sw->desktop);
2029     }
2030    
2031 forsberg 415 break;
2032 jdmeijer 905 case MapNotify:
2033 ossman_ 1149 if (!g_seamless_active)
2034 astrand 1089 rdp_send_client_window_status(1);
2035 jdmeijer 905 break;
2036     case UnmapNotify:
2037 ossman_ 1149 if (!g_seamless_active)
2038 astrand 1089 rdp_send_client_window_status(0);
2039 jdmeijer 905 break;
2040 ossman_ 1151 case ConfigureNotify:
2041     /* seamless */
2042     sw = seamless_get_window_by_wnd(xevent.xconfigure.window);
2043     if (!sw)
2044     break;
2045    
2046     ui_seamless_handle_restack(sw);
2047 matty 9 }
2048     }
2049 astrand 275 /* Keep going */
2050     return 1;
2051 matty 9 }
2052    
2053 astrand 275 /* Returns 0 after user quit, 1 otherwise */
2054     int
2055 matty 33 ui_select(int rdp_socket)
2056     {
2057 stargo 606 int n;
2058 matthewc 474 fd_set rfds, wfds;
2059 n-ki 592 struct timeval tv;
2060     BOOL s_timeout = False;
2061 matty 33
2062     while (True)
2063     {
2064 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2065 matthewc 121 /* Process any events already waiting */
2066 astrand 275 if (!xwin_process_events())
2067     /* User quit */
2068     return 0;
2069 astrand 119
2070 matty 33 FD_ZERO(&rfds);
2071 matthewc 474 FD_ZERO(&wfds);
2072 matty 33 FD_SET(rdp_socket, &rfds);
2073 jsorg71 450 FD_SET(g_x_socket, &rfds);
2074 matty 33
2075 matthewc 474 #ifdef WITH_RDPSND
2076     /* FIXME: there should be an API for registering fds */
2077 stargo 504 if (g_dsp_busy)
2078 matty 33 {
2079 matthewc 474 FD_SET(g_dsp_fd, &wfds);
2080 n-ki 592 n = (g_dsp_fd > n) ? g_dsp_fd : n;
2081 astrand 499 }
2082 matthewc 474 #endif
2083 n-ki 592 /* default timeout */
2084     tv.tv_sec = 60;
2085     tv.tv_usec = 0;
2086 matthewc 474
2087 n-ki 592 /* add redirection handles */
2088     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2089    
2090     n++;
2091    
2092     switch (select(n, &rfds, &wfds, NULL, &tv))
2093 matthewc 474 {
2094 matty 33 case -1:
2095     error("select: %s\n", strerror(errno));
2096    
2097     case 0:
2098 stargo 795 /* Abort serial read calls */
2099     if (s_timeout)
2100     rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2101 matty 33 continue;
2102     }
2103    
2104 n-ki 592 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2105    
2106 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2107     return 1;
2108    
2109 matthewc 474 #ifdef WITH_RDPSND
2110 stargo 504 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2111 matthewc 474 wave_out_play();
2112     #endif
2113 matty 33 }
2114     }
2115    
2116     void
2117 matty 25 ui_move_pointer(int x, int y)
2118 matty 9 {
2119 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2120 matty 9 }
2121    
2122 matty 25 HBITMAP
2123 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2124 matty 6 {
2125     XImage *image;
2126 matty 9 Pixmap bitmap;
2127 matty 28 uint8 *tdata;
2128 stargo 521 int bitmap_pad;
2129 matty 29
2130 astrand 1042 if (g_server_depth == 8)
2131 stargo 521 {
2132     bitmap_pad = 8;
2133     }
2134     else
2135     {
2136     bitmap_pad = g_bpp;
2137    
2138     if (g_bpp == 24)
2139     bitmap_pad = 32;
2140     }
2141    
2142 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2143     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2144     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2145 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2146 matty 6
2147 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2148 matty 9
2149     XFree(image);
2150 jsorg71 644 if (tdata != data)
2151 n-ki 279 xfree(tdata);
2152 matty 24 return (HBITMAP) bitmap;
2153 matty 6 }
2154    
2155 matty 25 void
2156 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2157 matty 6 {
2158 matty 10 XImage *image;
2159 matty 29 uint8 *tdata;
2160 stargo 521 int bitmap_pad;
2161    
2162 astrand 1042 if (g_server_depth == 8)
2163 stargo 521 {
2164     bitmap_pad = 8;
2165     }
2166     else
2167     {
2168     bitmap_pad = g_bpp;
2169    
2170     if (g_bpp == 24)
2171     bitmap_pad = 32;
2172     }
2173    
2174 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2175     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2176 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2177 matty 28
2178 jsorg71 450 if (g_ownbackstore)
2179 matty 31 {
2180 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2181     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2182 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2183     (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2184     x - sw->xoffset, y - sw->yoffset));
2185 matty 31 }
2186     else
2187     {
2188 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2189 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2190     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2191     x - sw->xoffset, y - sw->yoffset));
2192 matty 31 }
2193 matty 29
2194 matty 24 XFree(image);
2195 jsorg71 644 if (tdata != data)
2196 n-ki 279 xfree(tdata);
2197 matty 6 }
2198    
2199 matty 25 void
2200     ui_destroy_bitmap(HBITMAP bmp)
2201 matty 6 {
2202 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2203 matty 10 }
2204    
2205 matty 25 HGLYPH
2206 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2207 matty 10 {
2208 matty 9 XImage *image;
2209     Pixmap bitmap;
2210     int scanline;
2211 matty 6
2212 matty 9 scanline = (width + 7) / 8;
2213 matty 6
2214 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2215 jsorg71 725 if (g_create_glyph_gc == 0)
2216     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2217 matty 9
2218 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2219 astrand 73 width, height, 8, scanline);
2220 matty 23 image->byte_order = MSBFirst;
2221     image->bitmap_bit_order = MSBFirst;
2222     XInitImage(image);
2223    
2224 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2225 matty 29
2226 matty 9 XFree(image);
2227 astrand 64 return (HGLYPH) bitmap;
2228 matty 6 }
2229 matty 7
2230 matty 25 void
2231     ui_destroy_glyph(HGLYPH glyph)
2232 matty 7 {
2233 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2234 matty 9 }
2235    
2236 matty 29 HCURSOR
2237 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2238     uint8 * andmask, uint8 * xormask)
2239 matty 9 {
2240 matty 29 HGLYPH maskglyph, cursorglyph;
2241     XColor bg, fg;
2242     Cursor xcursor;
2243     uint8 *cursor, *pcursor;
2244     uint8 *mask, *pmask;
2245     uint8 nextbit;
2246     int scanline, offset;
2247     int i, j;
2248    
2249     scanline = (width + 7) / 8;
2250     offset = scanline * height;
2251    
2252 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2253 matty 29 memset(cursor, 0, offset);
2254    
2255 forsberg 415 mask = (uint8 *) xmalloc(offset);
2256 matty 29 memset(mask, 0, offset);
2257    
2258     /* approximate AND and XOR masks with a monochrome X pointer */
2259     for (i = 0; i < height; i++)
2260 matty 7 {
2261 matty 29 offset -= scanline;
2262     pcursor = &cursor[offset];
2263     pmask = &mask[offset];
2264    
2265     for (j = 0; j < scanline; j++)
2266 matty 28 {
2267 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2268     {
2269     if (xormask[0] || xormask[1] || xormask[2])
2270     {
2271     *pcursor |= (~(*andmask) & nextbit);
2272     *pmask |= nextbit;
2273     }
2274     else
2275     {
2276     *pcursor |= ((*andmask) & nextbit);
2277     *pmask |= (~(*andmask) & nextbit);
2278     }
2279    
2280     xormask += 3;
2281     }
2282    
2283     andmask++;
2284     pcursor++;
2285     pmask++;
2286 matty 28 }
2287 matty 7 }
2288 matty 29
2289     fg.red = fg.blue = fg.green = 0xffff;
2290     bg.red = bg.blue = bg.green = 0x0000;
2291     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2292    
2293     cursorglyph = ui_create_glyph(width, height, cursor);
2294     maskglyph = ui_create_glyph(width, height, mask);
2295    
2296 astrand 66 xcursor =
2297 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2298 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2299 astrand 64
2300 matty 29 ui_destroy_glyph(maskglyph);
2301     ui_destroy_glyph(cursorglyph);
2302     xfree(mask);
2303     xfree(cursor);
2304 astrand 64 return (HCURSOR) xcursor;
2305 matty 29 }
2306    
2307     void
2308     ui_set_cursor(HCURSOR cursor)
2309     {
2310 jsorg71 450 g_current_cursor = (Cursor) cursor;
2311     XDefineCursor(g_display, g_wnd, g_current_cursor);
2312 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2313 matty 29 }
2314    
2315     void
2316     ui_destroy_cursor(HCURSOR cursor)
2317     {
2318 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2319 matty 29 }
2320    
2321 astrand 508 void
2322     ui_set_null_cursor(void)
2323     {
2324     ui_set_cursor(g_null_cursor);
2325     }
2326    
2327 matty 29 #define MAKE_XCOLOR(xc,c) \
2328     (xc)->red = ((c)->red << 8) | (c)->red; \
2329     (xc)->green = ((c)->green << 8) | (c)->green; \
2330     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2331     (xc)->flags = DoRed | DoGreen | DoBlue;
2332    
2333 n-ki 279
2334 matty 29 HCOLOURMAP
2335 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2336 matty 29 {
2337     COLOURENTRY *entry;
2338     int i, ncolours = colours->ncolours;
2339 jsorg71 450 if (!g_owncolmap)
2340 matty 28 {
2341 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2342 n-ki 279 XColor xentry;
2343     XColor xc_cache[256];
2344     uint32 colour;
2345     int colLookup = 256;
2346     for (i = 0; i < ncolours; i++)
2347 matty 28 {
2348 n-ki 279 entry = &colours->colours[i];
2349     MAKE_XCOLOR(&xentry, entry);
2350 matty 7
2351 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2352 astrand 196 {
2353 n-ki 279 /* Allocation failed, find closest match. */
2354     int j = 256;
2355     int nMinDist = 3 * 256 * 256;
2356     long nDist = nMinDist;
2357 matty 28
2358 n-ki 279 /* only get the colors once */
2359     while (colLookup--)
2360 astrand 196 {
2361 n-ki 279 xc_cache[colLookup].pixel = colLookup;
2362     xc_cache[colLookup].red = xc_cache[colLookup].green =
2363     xc_cache[colLookup].blue = 0;
2364     xc_cache[colLookup].flags = 0;
2365 jsorg71 450 XQueryColor(g_display,
2366     DefaultColormap(g_display,
2367     DefaultScreen(g_display)),
2368 n-ki 279 &xc_cache[colLookup]);
2369 n-ki 185 }
2370 n-ki 279 colLookup = 0;
2371    
2372     /* approximate the pixel */
2373     while (j--)
2374 astrand 196 {
2375 n-ki 279 if (xc_cache[j].flags)
2376     {
2377     nDist = ((long) (xc_cache[j].red >> 8) -
2378     (long) (xentry.red >> 8)) *
2379     ((long) (xc_cache[j].red >> 8) -
2380     (long) (xentry.red >> 8)) +
2381     ((long) (xc_cache[j].green >> 8) -
2382     (long) (xentry.green >> 8)) *
2383     ((long) (xc_cache[j].green >> 8) -
2384     (long) (xentry.green >> 8)) +
2385     ((long) (xc_cache[j].blue >> 8) -
2386     (long) (xentry.blue >> 8)) *
2387     ((long) (xc_cache[j].blue >> 8) -
2388     (long) (xentry.blue >> 8));
2389     }
2390     if (nDist < nMinDist)
2391     {
2392     nMinDist = nDist;
2393     xentry.pixel = j;
2394     }
2395 n-ki 185 }
2396     }
2397 n-ki 279 colour = xentry.pixel;
2398    
2399     /* update our cache */
2400     if (xentry.pixel < 256)
2401     {
2402     xc_cache[xentry.pixel].red = xentry.red;
2403     xc_cache[xentry.pixel].green = xentry.green;
2404     xc_cache[xentry.pixel].blue = xentry.blue;
2405    
2406     }
2407    
2408 matthewc 527 map[i] = colour;
2409 n-ki 185 }
2410 n-ki 279 return map;
2411     }
2412     else
2413     {
2414     XColor *xcolours, *xentry;
2415     Colormap map;
2416 matty 29
2417 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2418 n-ki 279 for (i = 0; i < ncolours; i++)
2419 astrand 196 {
2420 n-ki 279 entry = &colours->colours[i];
2421     xentry = &xcolours[i];
2422     xentry->pixel = i;
2423     MAKE_XCOLOR(xentry, entry);
2424 matty 29 }
2425    
2426 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2427     XStoreColors(g_display, map, xcolours, ncolours);
2428 n-ki 185
2429 n-ki 279 xfree(xcolours);
2430     return (HCOLOURMAP) map;
2431 matty 29 }
2432 matty 7 }
2433    
2434 matty 25 void
2435     ui_destroy_colourmap(HCOLOURMAP map)
2436 matty 7 {
2437 jsorg71 450 if (!g_owncolmap)
2438 n-ki 279 xfree(map);
2439     else
2440 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2441 matty 7 }
2442    
2443 matty 25 void
2444     ui_set_colourmap(HCOLOURMAP map)
2445 matty 7 {
2446 jsorg71 450 if (!g_owncolmap)
2447 astrand 448 {
2448 jsorg71 450 if (g_colmap)
2449     xfree(g_colmap);
2450 astrand 448
2451 jsorg71 450 g_colmap = (uint32 *) map;
2452 astrand 448 }
2453 n-ki 279 else
2454 astrand 1089 {
2455 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2456 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2457     }
2458 matty 7 }
2459    
2460 matty 25 void
2461     ui_set_clip(int x, int y, int cx, int cy)
2462 matty 7 {
2463 astrand 1089 g_clip_rectangle.x = x;
2464     g_clip_rectangle.y = y;
2465     g_clip_rectangle.width = cx;
2466     g_clip_rectangle.height = cy;
2467     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2468 matty 9 }
2469 matty 7
2470 matty 25 void
2471 matthewc 192 ui_reset_clip(void)
2472 matty 9 {
2473 astrand 1089 g_clip_rectangle.x = 0;
2474     g_clip_rectangle.y = 0;
2475     g_clip_rectangle.width = g_width;
2476     g_clip_rectangle.height = g_height;
2477     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2478 matty 7 }
2479    
2480 matty 25 void
2481 matthewc 192 ui_bell(void)
2482 matty 10 {
2483 jsorg71 450 XBell(g_display, 0);
2484 matty 10 }
2485    
2486 matty 25 void
2487     ui_destblt(uint8 opcode,
2488     /* dest */ int x, int y, int cx, int cy)
2489 matty 9 {
2490 matty 29 SET_FUNCTION(opcode);
2491 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2492 matty 29 RESET_FUNCTION(opcode);
2493 matty 9 }
2494    
2495 jsorg71 373 static uint8 hatch_patterns[] = {
2496 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2497     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2498     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2499     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2500     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2501     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2502 jsorg71 373 };
2503    
2504 matty 25 void
2505     ui_patblt(uint8 opcode,
2506     /* dest */ int x, int y, int cx, int cy,
2507 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2508 matty 9 {
2509     Pixmap fill;
2510 jsorg71 59 uint8 i, ipattern[8];
2511 matty 9
2512 matty 29 SET_FUNCTION(opcode);
2513 matty 9
2514     switch (brush->style)
2515     {
2516 matty 24 case 0: /* Solid */
2517 matty 29 SET_FOREGROUND(fgcolour);
2518 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2519 matty 9 break;
2520    
2521 jsorg71 373 case 2: /* Hatch */
2522 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2523     hatch_patterns + brush->pattern[0] * 8);
2524 astrand 487 SET_FOREGROUND(fgcolour);
2525     SET_BACKGROUND(bgcolour);
2526 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2527     XSetStipple(g_display, g_gc, fill);
2528     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2529 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2530 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2531     XSetTSOrigin(g_display, g_gc, 0, 0);
2532 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
2533     break;
2534    
2535 matty 24 case 3: /* Pattern */
2536 jsorg71 59 for (i = 0; i != 8; i++)
2537     ipattern[7 - i] = brush->pattern[i];
2538     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2539 matty 29 SET_FOREGROUND(bgcolour);
2540     SET_BACKGROUND(fgcolour);
2541 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2542     XSetStipple(g_display, g_gc, fill);
2543     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2544 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2545 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2546     XSetTSOrigin(g_display, g_gc, 0, 0);
2547 astrand 64 ui_destroy_glyph((HGLYPH) fill);
2548 matty 9 break;
2549    
2550     default:
2551 matty 30 unimpl("brush %d\n", brush->style);
2552 matty 9 }
2553 matty 29
2554     RESET_FUNCTION(opcode);
2555 jsorg71 680
2556     if (g_ownbackstore)
2557     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2558 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2559     (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2560     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2561 matty 9 }
2562    
2563 matty 25 void
2564     ui_screenblt(uint8 opcode,
2565     /* dest */ int x, int y, int cx, int cy,
2566     /* src */ int srcx, int srcy)
2567 matty 9 {
2568 matty 29 SET_FUNCTION(opcode);
2569 jsorg71 450 if (g_ownbackstore)
2570 stargo 609 {
2571 astrand 1089 XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2572     g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2573     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2574 stargo 609 }
2575     else
2576     {
2577     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2578     }
2579 astrand 1089
2580     ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2581     (g_display, g_ownbackstore ? g_backstore : g_wnd,
2582     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2583    
2584 matty 29 RESET_FUNCTION(opcode);
2585 matty 9 }
2586    
2587 matty 25 void
2588     ui_memblt(uint8 opcode,
2589     /* dest */ int x, int y, int cx, int cy,
2590     /* src */ HBITMAP src, int srcx, int srcy)
2591 matty 9 {
2592 matty 29 SET_FUNCTION(opcode);
2593 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2594 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2595     (g_display, (Pixmap) src, sw->wnd, g_gc,
2596     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2597 jsorg71 450 if (g_ownbackstore)
2598     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2599 matty 29 RESET_FUNCTION(opcode);
2600 matty 9 }
2601    
2602 matty 25 void
2603     ui_triblt(uint8 opcode,
2604     /* dest */ int x, int y, int cx, int cy,
2605     /* src */ HBITMAP src, int srcx, int srcy,
2606 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2607 matty 9 {
2608     /* This is potentially difficult to do in general. Until someone
2609 matty 10 comes up with a more efficient way of doing it I am using cases. */
2610 matty 9
2611     switch (opcode)
2612     {
2613 matty 24 case 0x69: /* PDSxxn */
2614 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2615 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2616 matty 16 break;
2617    
2618 matty 24 case 0xb8: /* PSDPxax */
2619 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2620 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2621 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2622 matty 9 break;
2623    
2624 matty 29 case 0xc0: /* PSa */
2625 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2626 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2627 matty 28 break;
2628    
2629 matty 9 default:
2630 matty 30 unimpl("triblt 0x%x\n", opcode);
2631 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2632 matty 9 }
2633     }
2634    
2635 matty 25 void
2636     ui_line(uint8 opcode,
2637     /* dest */ int startx, int starty, int endx, int endy,
2638 astrand 64 /* pen */ PEN * pen)
2639 matty 9 {
2640 matty 29 SET_FUNCTION(opcode);
2641     SET_FOREGROUND(pen->colour);
2642 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2643 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2644     startx - sw->xoffset, starty - sw->yoffset,
2645     endx - sw->xoffset, endy - sw->yoffset));
2646 jsorg71 450 if (g_ownbackstore)
2647     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2648 matty 29 RESET_FUNCTION(opcode);
2649 matty 9 }
2650    
2651 matty 25 void
2652     ui_rect(
2653     /* dest */ int x, int y, int cx, int cy,
2654     /* brush */ int colour)
2655 matty 9 {
2656 matty 29 SET_FOREGROUND(colour);
2657 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2658 matty 9 }
2659    
2660 jdmeijer 831 void
2661     ui_polygon(uint8 opcode,
2662     /* mode */ uint8 fillmode,
2663     /* dest */ POINT * point, int npoints,
2664     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2665     {
2666     uint8 style, i, ipattern[8];
2667     Pixmap fill;
2668    
2669     SET_FUNCTION(opcode);
2670    
2671     switch (fillmode)
2672     {
2673     case ALTERNATE:
2674     XSetFillRule(g_display, g_gc, EvenOddRule);
2675     break;
2676     case WINDING:
2677     XSetFillRule(g_display, g_gc, WindingRule);
2678     break;
2679     default:
2680     unimpl("fill mode %d\n", fillmode);
2681     }
2682    
2683     if (brush)
2684     style = brush->style;
2685     else
2686     style = 0;
2687    
2688     switch (style)
2689     {
2690     case 0: /* Solid */
2691     SET_FOREGROUND(fgcolour);
2692     FILL_POLYGON((XPoint *) point, npoints);
2693     break;
2694    
2695     case 2: /* Hatch */
2696     fill = (Pixmap) ui_create_glyph(8, 8,
2697     hatch_patterns + brush->pattern[0] * 8);
2698     SET_FOREGROUND(fgcolour);
2699     SET_BACKGROUND(bgcolour);
2700     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2701     XSetStipple(g_display, g_gc, fill);
2702     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2703     FILL_POLYGON((XPoint *) point, npoints);
2704     XSetFillStyle(g_display, g_gc, FillSolid);
2705     XSetTSOrigin(g_display, g_gc, 0, 0);
2706     ui_destroy_glyph((HGLYPH) fill);
2707     break;
2708    
2709     case 3: /* Pattern */
2710     for (i = 0; i != 8; i++)
2711     ipattern[7 - i] = brush->pattern[i];
2712     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2713     SET_FOREGROUND(bgcolour);
2714     SET_BACKGROUND(fgcolour);
2715     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2716     XSetStipple(g_display, g_gc, fill);
2717     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2718     FILL_POLYGON((XPoint *) point, npoints);
2719     XSetFillStyle(g_display, g_gc, FillSolid);
2720     XSetTSOrigin(g_display, g_gc, 0, 0);
2721     ui_destroy_glyph((HGLYPH) fill);
2722     break;
2723    
2724     default:
2725     unimpl("brush %d\n", brush->style);
2726     }
2727    
2728     RESET_FUNCTION(opcode);
2729     }
2730    
2731     void
2732 jdmeijer 844 ui_polyline(uint8 opcode,
2733     /* dest */ POINT * points, int npoints,
2734     /* pen */ PEN * pen)
2735     {
2736     /* TODO: set join style */
2737     SET_FUNCTION(opcode);
2738     SET_FOREGROUND(pen->colour);
2739     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2740     if (g_ownbackstore)
2741     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2742     CoordModePrevious);
2743 astrand 1089
2744     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2745     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2746    
2747 jdmeijer 844 RESET_FUNCTION(opcode);
2748     }
2749    
2750     void
2751 jdmeijer 831 ui_ellipse(uint8 opcode,
2752     /* mode */ uint8 fillmode,
2753     /* dest */ int x, int y, int cx, int cy,
2754     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2755     {
2756     uint8 style, i, ipattern[8];
2757     Pixmap fill;
2758    
2759     SET_FUNCTION(opcode);
2760    
2761     if (brush)
2762     style = brush->style;
2763     else
2764     style = 0;
2765    
2766     switch (style)
2767     {
2768     case 0: /* Solid */
2769     SET_FOREGROUND(fgcolour);
2770     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2771     break;
2772    
2773     case 2: /* Hatch */
2774     fill = (Pixmap) ui_create_glyph(8, 8,
2775     hatch_patterns + brush->pattern[0] * 8);
2776     SET_FOREGROUND(fgcolour);
2777     SET_BACKGROUND(bgcolour);
2778     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2779     XSetStipple(g_display, g_gc, fill);
2780     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2781     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2782     XSetFillStyle(g_display, g_gc, FillSolid);
2783     XSetTSOrigin(g_display, g_gc, 0, 0);
2784     ui_destroy_glyph((HGLYPH) fill);
2785     break;
2786    
2787     case 3: /* Pattern */
2788     for (i = 0; i != 8; i++)
2789     ipattern[7 - i] = brush->pattern[i];
2790     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2791     SET_FOREGROUND(bgcolour);
2792     SET_BACKGROUND(fgcolour);
2793     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2794     XSetStipple(g_display, g_gc, fill);
2795     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2796     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2797     XSetFillStyle(g_display, g_gc, FillSolid);
2798     XSetTSOrigin(g_display, g_gc, 0, 0);
2799     ui_destroy_glyph((HGLYPH) fill);
2800     break;
2801    
2802     default:
2803     unimpl("brush %d\n", brush->style);
2804     }
2805    
2806     RESET_FUNCTION(opcode);
2807     }
2808    
2809 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
2810 matty 25 void
2811     ui_draw_glyph(int mixmode,
2812     /* dest */ int x, int y, int cx, int cy,
2813 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
2814     int bgcolour, int fgcolour)
2815 matty 9 {
2816 matty 29 SET_FOREGROUND(fgcolour);
2817     SET_BACKGROUND(bgcolour);
2818 matty 9
2819 jsorg71 450 XSetFillStyle(g_display, g_gc,
2820 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2821 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2822     XSetTSOrigin(g_display, g_gc, x, y);
2823 matty 9
2824 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2825 matty 9
2826 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2827 matty 9 }
2828    
2829 mmihalik 49 #define DO_GLYPH(ttext,idx) \
2830     {\
2831     glyph = cache_get_font (font, ttext[idx]);\
2832     if (!(flags & TEXT2_IMPLICIT_X))\
2833 jsorg71 564 {\
2834     xyoffset = ttext[++idx];\
2835     if ((xyoffset & 0x80))\
2836 mmihalik 49 {\
2837 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2838     y += ttext[idx+1] | (ttext[idx+2] << 8);\
2839 mmihalik 49 else\
2840 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2841     idx += 2;\
2842 mmihalik 49 }\
2843 jsorg71 564 else\
2844 mmihalik 49 {\
2845 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2846     y += xyoffset;\
2847     else\
2848     x += xyoffset;\
2849 mmihalik 49 }\
2850 jsorg71 564 }\
2851     if (glyph != NULL)\
2852     {\
2853     x1 = x + glyph->offset;\
2854     y1 = y + glyph->baseline;\
2855     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2856     XSetTSOrigin(g_display, g_gc, x1, y1);\
2857     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2858     if (flags & TEXT2_IMPLICIT_X)\
2859     x += glyph->width;\
2860     }\
2861 mmihalik 49 }
2862    
2863 matty 25 void
2864 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2865 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
2866 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2867     int bgcolour, int fgcolour, uint8 * text, uint8 length)
2868 matty 9 {
2869 jdmeijer 843 /* TODO: use brush appropriately */
2870    
2871 matty 10 FONTGLYPH *glyph;
2872 jsorg71 564 int i, j, xyoffset, x1, y1;
2873 mmihalik 49 DATABLOB *entry;
2874 matty 9
2875 matty 29 SET_FOREGROUND(bgcolour);
2876 matty 28
2877 astrand 620 /* Sometimes, the boxcx value is something really large, like
2878     32691. This makes XCopyArea fail with Xvnc. The code below
2879     is a quick fix. */
2880     if (boxx + boxcx > g_width)
2881     boxcx = g_width - boxx;
2882    
2883 matty 9 if (boxcx > 1)
2884 matty 31 {
2885 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2886 matty 31 }
2887 matty 17 else if (mixmode == MIX_OPAQUE)
2888 matty 31 {
2889 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2890 matty 31 }
2891 matty 9
2892 jsorg71 564 SET_FOREGROUND(fgcolour);
2893     SET_BACKGROUND(bgcolour);
2894     XSetFillStyle(g_display, g_gc, FillStippled);
2895    
2896 matty 9 /* Paint text, character by character */
2897 astrand 64 for (i = 0; i < length;)
2898     {
2899     switch (text[i])
2900     {
2901     case 0xff:
2902 astrand 1031 /* At least two bytes needs to follow */
2903 astrand 1029 if (i + 3 > length)
2904 astrand 64 {
2905 astrand 1031 warning("Skipping short 0xff command:");
2906     for (j = 0; j < length; j++)
2907     fprintf(stderr, "%02x ", text[j]);
2908     fprintf(stderr, "\n");
2909 astrand 1029 i = length = 0;
2910     break;
2911 astrand 64 }
2912 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
2913     i += 3;
2914     length -= i;
2915 astrand 64 /* this will move pointer from start to first character after FF command */
2916 astrand 1029 text = &(text[i]);
2917 astrand 64 i = 0;
2918 mmihalik 49 break;
2919 matty 9
2920 astrand 64 case 0xfe:
2921 astrand 1031 /* At least one byte needs to follow */
2922     if (i + 2 > length)
2923 astrand 1029 {
2924 astrand 1031 warning("Skipping short 0xfe command:");
2925     for (j = 0; j < length; j++)
2926     fprintf(stderr, "%02x ", text[j]);
2927     fprintf(stderr, "\n");
2928 astrand 1029 i = length = 0;
2929     break;
2930     }
2931 astrand 64 entry = cache_get_text(text[i + 1]);
2932 astrand 1030 if (entry->data != NULL)
2933 astrand 64 {
2934 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
2935     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2936 astrand 64 {
2937     if (flags & TEXT2_VERTICAL)
2938     y += text[i + 2];
2939     else
2940     x += text[i + 2];
2941     }
2942     for (j = 0; j < entry->size; j++)
2943 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
2944 matthewc 44 }
2945 astrand 1031 if (i + 2 < length)
2946     i += 3;
2947     else
2948     i += 2;
2949 jsorg71 286 length -= i;
2950     /* this will move pointer from start to first character after FE command */
2951     text = &(text[i]);
2952     i = 0;
2953 astrand 64 break;
2954 matty 17
2955 astrand 64 default:
2956     DO_GLYPH(text, i);
2957     i++;
2958     break;
2959 matty 29 }
2960 mmihalik 49 }
2961 jsorg71 564
2962     XSetFillStyle(g_display, g_gc, FillSolid);
2963    
2964 jsorg71 450 if (g_ownbackstore)
2965 jsorg71 278 {
2966     if (boxcx > 1)
2967 astrand 1089 {
2968 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2969 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
2970 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2971     (g_display, g_backstore, sw->wnd, g_gc,
2972     boxx, boxy,
2973     boxcx, boxcy,
2974     boxx - sw->xoffset, boxy - sw->yoffset));
2975     }
2976 jsorg71 278 else
2977 astrand 1089 {
2978 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2979 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
2980 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2981     (g_display, g_backstore, sw->wnd, g_gc,
2982     clipx, clipy,
2983     clipcx, clipcy, clipx - sw->xoffset,
2984     clipy - sw->yoffset));
2985     }
2986 jsorg71 278 }
2987 matty 9 }
2988    
2989 matty 25 void
2990     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2991 matty 9 {
2992 matty 28 Pixmap pix;
2993 matty 9 XImage *image;
2994    
2995 jsorg71 450 if (g_ownbackstore)
2996 matty 31 {
2997 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2998 matty 31 }
2999     else
3000     {
3001 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3002     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3003     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3004     XFreePixmap(g_display, pix);
3005 matty 31 }
3006 matty 28
3007 jsorg71 450 offset *= g_bpp / 8;
3008     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
3009 matty 28
3010     XDestroyImage(image);
3011 matty 9 }
3012    
3013 matty 25 void
3014     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
3015 matty 9 {
3016     XImage *image;
3017 matty 10 uint8 *data;
3018 matty 9
3019 jsorg71 450 offset *= g_bpp / 8;
3020     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3021 matty 10 if (data == NULL)
3022     return;
3023 matty 29
3024 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3025     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
3026 matty 29
3027 jsorg71 450 if (g_ownbackstore)
3028 matty 31 {
3029 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3030     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3031 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3032     (g_display, g_backstore, sw->wnd, g_gc,
3033     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3034 matty 31 }
3035     else
3036     {
3037 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3038 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3039     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3040     x - sw->xoffset, y - sw->yoffset));
3041 matty 31 }
3042    
3043 matty 9 XFree(image);
3044     }
3045 jsorg71 713
3046     /* these do nothing here but are used in uiports */
3047     void
3048     ui_begin_update(void)
3049     {
3050     }
3051    
3052     void
3053     ui_end_update(void)
3054     {
3055     }
3056 astrand 1089
3057     void
3058 ossman_ 1149 ui_seamless_begin()
3059     {
3060     if (!g_seamless_rdp)
3061     return;
3062    
3063     if (g_seamless_started)
3064     return;
3065    
3066     g_seamless_started = True;
3067    
3068     ui_seamless_toggle();
3069     }
3070    
3071     void
3072 astrand 1089 ui_seamless_toggle()
3073     {
3074 ossman_ 1149 if (!g_seamless_rdp)
3075     return;
3076    
3077     if (!g_seamless_started)
3078     return;
3079    
3080     if (g_seamless_active)
3081 astrand 1089 {
3082     /* Deactivate */
3083     while (g_seamless_windows)
3084     {
3085     XDestroyWindow(g_display, g_seamless_windows->wnd);
3086     seamless_remove_window(g_seamless_windows);
3087     }
3088     XMapWindow(g_display, g_wnd);
3089     }
3090     else
3091     {
3092     /* Activate */
3093     XUnmapWindow(g_display, g_wnd);
3094     seamless_send_sync();
3095     }
3096    
3097 ossman_ 1149 g_seamless_active = !g_seamless_active;
3098 astrand 1089 }
3099    
3100     void
3101 astrand 1098 ui_seamless_create_window(unsigned long id, unsigned long parent, unsigned long flags)
3102 astrand 1089 {
3103     Window wnd;
3104     XSetWindowAttributes attribs;
3105     XClassHint *classhints;
3106 astrand 1132 XSizeHints *sizehints;
3107 astrand 1089 long input_mask;
3108 astrand 1101 seamless_window *sw, *sw_parent;
3109 astrand 1089
3110 ossman_ 1149 if (!g_seamless_active)
3111     return;
3112    
3113 astrand 1122 /* Ignore CREATEs for existing windows */
3114     sw = seamless_get_window_by_id(id);
3115     if (sw)
3116     return;
3117    
3118 astrand 1089 get_window_attribs(&attribs);
3119     attribs.override_redirect = False;
3120    
3121 astrand 1132 wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3122 astrand 1089 InputOutput, g_visual,
3123     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3124     CWBorderPixel, &attribs);
3125    
3126 astrand 1133 XStoreName(g_display, wnd, "SeamlessRDP");
3127 astrand 1139 ewmh_set_wm_name(wnd, "SeamlessRDP");
3128 astrand 1089
3129     mwm_hide_decorations(wnd);
3130    
3131     classhints = XAllocClassHint();
3132     if (classhints != NULL)
3133     {
3134 astrand 1133 classhints->res_name = "rdesktop";
3135     classhints->res_class = "SeamlessRDP";
3136 astrand 1089 XSetClassHint(g_display, wnd, classhints);
3137     XFree(classhints);
3138     }
3139    
3140 astrand 1132 /* WM_NORMAL_HINTS */
3141     sizehints = XAllocSizeHints();
3142     if (sizehints != NULL)
3143     {
3144     sizehints->flags = USPosition;
3145     XSetWMNormalHints(g_display, wnd, sizehints);
3146     XFree(sizehints);
3147     }
3148    
3149 astrand 1101 /* Set WM_TRANSIENT_FOR, if necessary */
3150 ossman_ 1143 if ((parent != 0x00000000) && (parent != 0xFFFFFFFF))
3151 astrand 1103 {
3152     sw_parent = seamless_get_window_by_id(parent);
3153     if (sw_parent)
3154     XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3155     else
3156     warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3157     }
3158 astrand 1101
3159 ossman_ 1137
3160 astrand 1089 /* FIXME: Support for Input Context:s */
3161    
3162     get_input_mask(&input_mask);
3163 astrand 1118 input_mask |= PropertyChangeMask;
3164 astrand 1089
3165     XSelectInput(g_display, wnd, input_mask);
3166    
3167     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3168     seamless window, we could try to close the window on the
3169     serverside, instead of terminating rdesktop */
3170     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3171    
3172     sw = malloc(sizeof(seamless_window));
3173     sw->wnd = wnd;
3174     sw->id = id;
3175 ossman_ 1143 sw->parent = parent;
3176 astrand 1089 sw->xoffset = 0;
3177     sw->yoffset = 0;
3178     sw->width = 0;
3179     sw->height = 0;
3180 astrand 1132 sw->state = SEAMLESSRDP_NOTYETMAPPED;
3181     sw->desktop = 0;
3182 astrand 1089 sw->next = g_seamless_windows;
3183     g_seamless_windows = sw;
3184     }
3185    
3186    
3187     void
3188     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3189     {
3190     seamless_window *sw;
3191 astrand 1107
3192 ossman_ 1149 if (!g_seamless_active)
3193     return;
3194    
3195 astrand 1089 sw = seamless_get_window_by_id(id);
3196     if (!sw)
3197     {
3198     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3199     return;
3200     }
3201    
3202     XDestroyWindow(g_display, sw->wnd);
3203     seamless_remove_window(sw);
3204     }
3205    
3206    
3207     void
3208     ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3209     {
3210     seamless_window *sw;
3211    
3212 ossman_ 1149 if (!g_seamless_active)
3213     return;
3214    
3215 astrand 1089 sw = seamless_get_window_by_id(id);
3216     if (!sw)
3217     {
3218     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3219     return;
3220     }
3221    
3222     if (!width || !height)
3223     /* X11 windows must be at least 1x1 */
3224     return;
3225    
3226     /* About MAX and MIN: Windows allows moving a window outside
3227     the desktop. This happens, for example, when maximizing an
3228     application. In this case, the position is set to something
3229     like -4,-4,1288,1032. Many WMs does not allow windows
3230     outside the desktop, however. Therefore, clip the window
3231     ourselves. */
3232     sw->xoffset = MAX(0, x);
3233     sw->yoffset = MAX(0, y);
3234     sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3235     sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3236    
3237 astrand 1118 /* If we move the window in a maximized state, then KDE won't
3238     accept restoration */
3239 astrand 1132 switch (sw->state)
3240     {
3241     case SEAMLESSRDP_MINIMIZED:
3242     case SEAMLESSRDP_MAXIMIZED:
3243     return;
3244     }
3245 astrand 1118
3246 astrand 1089 /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3247     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3248     }
3249    
3250 ossman_ 1151 void
3251     ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3252     {
3253     seamless_window *sw;
3254 astrand 1089
3255 ossman_ 1151 if (!g_seamless_active)
3256     return;
3257    
3258     sw = seamless_get_window_by_id(id);
3259     if (!sw)
3260     {
3261     warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3262     return;
3263     }
3264    
3265     if (behind)
3266     {
3267     seamless_window *sw_behind;
3268     Window wnds[2];
3269    
3270     sw_behind = seamless_get_window_by_id(behind);
3271     if (!sw_behind)
3272     {
3273     warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3274     behind);
3275     return;
3276     }
3277    
3278     wnds[1] = sw_behind->wnd;
3279     wnds[0] = sw->wnd;
3280    
3281     XRestackWindows(g_display, wnds, 2);
3282     }
3283     else
3284     {
3285     XRaiseWindow(g_display, sw->wnd);
3286     }
3287     }
3288    
3289 astrand 1089 void
3290 astrand 1094 ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3291 astrand 1089 {
3292     seamless_window *sw;
3293    
3294 ossman_ 1149 if (!g_seamless_active)
3295     return;
3296    
3297 astrand 1089 sw = seamless_get_window_by_id(id);
3298 astrand 1107 if (!sw)
3299     {
3300     warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3301     return;
3302     }
3303 astrand 1089
3304 astrand 1139 /* FIXME: Might want to convert the name for non-EWMH WMs */
3305 astrand 1089 XStoreName(g_display, sw->wnd, title);
3306 astrand 1139 ewmh_set_wm_name(sw->wnd, title);
3307 astrand 1089 }
3308    
3309    
3310     void
3311     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3312     {
3313     seamless_window *sw;
3314    
3315 ossman_ 1149 if (!g_seamless_active)
3316     return;
3317    
3318 astrand 1089 sw = seamless_get_window_by_id(id);
3319 astrand 1107 if (!sw)
3320     {
3321     warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3322     return;
3323     }
3324 astrand 1089
3325     switch (state)
3326     {
3327     case SEAMLESSRDP_NORMAL:
3328     case SEAMLESSRDP_MAXIMIZED:
3329 astrand 1118 ewmh_change_state(sw->wnd, state);
3330 ossman_ 1142 XMapWindow(g_display, sw->wnd);
3331 astrand 1089 break;
3332     case SEAMLESSRDP_MINIMIZED:
3333 astrand 1118 /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3334     the Window Manager should probably just ignore the request, since
3335     _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3336     such as minimization, rather than an independent state." Besides,
3337     XIconifyWindow is easier. */
3338 ossman_ 1142 if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3339     {
3340 ossman_ 1144 XWMHints *hints;
3341     hints = XAllocWMHints();
3342     hints->flags = StateHint;
3343     hints->initial_state = IconicState;
3344     XSetWMHints(g_display, sw->wnd, hints);
3345     XFree(hints);
3346 ossman_ 1142 XMapWindow(g_display, sw->wnd);
3347     }
3348     else
3349     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3350 astrand 1089 break;
3351     default:
3352     warning("SeamlessRDP: Invalid state %d\n", state);
3353     break;
3354     }
3355 ossman_ 1142
3356 ossman_ 1143 /* Handle popups without parents through some ewm hints */
3357     if ((sw->state == SEAMLESSRDP_NOTYETMAPPED) && (sw->parent == 0xFFFFFFFF))
3358     ewmh_set_window_popup(sw->wnd);
3359    
3360 ossman_ 1142 sw->state = state;
3361 astrand 1089 }
3362 astrand 1123
3363    
3364     void
3365     ui_seamless_syncbegin(unsigned long flags)
3366     {
3367 ossman_ 1149 if (!g_seamless_active)
3368     return;
3369    
3370 astrand 1123 /* Destroy all seamless windows */
3371     while (g_seamless_windows)
3372     {
3373     XDestroyWindow(g_display, g_seamless_windows->wnd);
3374     seamless_remove_window(g_seamless_windows);
3375     }
3376     }

  ViewVC Help
Powered by ViewVC 1.1.26