/[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 1118 - (hide annotations)
Tue Mar 14 13:56:50 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 74377 byte(s)
Implemented support for changing state normal/minimized/maximized via EWMH. Also, sending notifications to server when local state changes.

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

  ViewVC Help
Powered by ViewVC 1.1.26