/[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 1107 - (hide annotations)
Fri Mar 10 14:09:16 2006 UTC (18 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 73292 byte(s)
Checking return value from seamless_get_window_* everywhere

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

  ViewVC Help
Powered by ViewVC 1.1.26