/[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 1094 - (hide annotations)
Fri Mar 10 10:40:50 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 72663 byte(s)
SETSTATE is not two ops: TITLE and STATE

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     }
1907    
1908 matty 31 break;
1909 astrand 119
1910     case MappingNotify:
1911     /* Refresh keyboard mapping if it has changed. This is important for
1912     Xvnc, since it allocates keycodes dynamically */
1913     if (xevent.xmapping.request == MappingKeyboard
1914     || xevent.xmapping.request == MappingModifier)
1915     XRefreshKeyboardMapping(&xevent.xmapping);
1916 matthewc 203
1917     if (xevent.xmapping.request == MappingModifier)
1918     {
1919 jsorg71 450 XFreeModifiermap(g_mod_map);
1920     g_mod_map = XGetModifierMapping(g_display);
1921 matthewc 203 }
1922 astrand 119 break;
1923 matthewc 432
1924 astrand 435 /* clipboard stuff */
1925 forsberg 415 case SelectionNotify:
1926 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
1927 forsberg 415 break;
1928     case SelectionRequest:
1929 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1930 forsberg 415 break;
1931 matthewc 432 case SelectionClear:
1932     xclip_handle_SelectionClear();
1933     break;
1934 forsberg 415 case PropertyNotify:
1935 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
1936 forsberg 415 break;
1937 jdmeijer 905 case MapNotify:
1938 astrand 1089 if (!g_seamless_rdp)
1939     rdp_send_client_window_status(1);
1940 jdmeijer 905 break;
1941     case UnmapNotify:
1942 astrand 1089 if (!g_seamless_rdp)
1943     rdp_send_client_window_status(0);
1944 jdmeijer 905 break;
1945 matty 9 }
1946     }
1947 astrand 275 /* Keep going */
1948     return 1;
1949 matty 9 }
1950    
1951 astrand 275 /* Returns 0 after user quit, 1 otherwise */
1952     int
1953 matty 33 ui_select(int rdp_socket)
1954     {
1955 stargo 606 int n;
1956 matthewc 474 fd_set rfds, wfds;
1957 n-ki 592 struct timeval tv;
1958     BOOL s_timeout = False;
1959 matty 33
1960     while (True)
1961     {
1962 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1963 matthewc 121 /* Process any events already waiting */
1964 astrand 275 if (!xwin_process_events())
1965     /* User quit */
1966     return 0;
1967 astrand 119
1968 matty 33 FD_ZERO(&rfds);
1969 matthewc 474 FD_ZERO(&wfds);
1970 matty 33 FD_SET(rdp_socket, &rfds);
1971 jsorg71 450 FD_SET(g_x_socket, &rfds);
1972 matty 33
1973 matthewc 474 #ifdef WITH_RDPSND
1974     /* FIXME: there should be an API for registering fds */
1975 stargo 504 if (g_dsp_busy)
1976 matty 33 {
1977 matthewc 474 FD_SET(g_dsp_fd, &wfds);
1978 n-ki 592 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1979 astrand 499 }
1980 matthewc 474 #endif
1981 n-ki 592 /* default timeout */
1982     tv.tv_sec = 60;
1983     tv.tv_usec = 0;
1984 matthewc 474
1985 n-ki 592 /* add redirection handles */
1986     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1987    
1988     n++;
1989    
1990     switch (select(n, &rfds, &wfds, NULL, &tv))
1991 matthewc 474 {
1992 matty 33 case -1:
1993     error("select: %s\n", strerror(errno));
1994    
1995     case 0:
1996 stargo 795 /* Abort serial read calls */
1997     if (s_timeout)
1998     rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1999 matty 33 continue;
2000     }
2001    
2002 n-ki 592 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2003    
2004 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2005     return 1;
2006    
2007 matthewc 474 #ifdef WITH_RDPSND
2008 stargo 504 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2009 matthewc 474 wave_out_play();
2010     #endif
2011 matty 33 }
2012     }
2013    
2014     void
2015 matty 25 ui_move_pointer(int x, int y)
2016 matty 9 {
2017 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2018 matty 9 }
2019    
2020 matty 25 HBITMAP
2021 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2022 matty 6 {
2023     XImage *image;
2024 matty 9 Pixmap bitmap;
2025 matty 28 uint8 *tdata;
2026 stargo 521 int bitmap_pad;
2027 matty 29
2028 astrand 1042 if (g_server_depth == 8)
2029 stargo 521 {
2030     bitmap_pad = 8;
2031     }
2032     else
2033     {
2034     bitmap_pad = g_bpp;
2035    
2036     if (g_bpp == 24)
2037     bitmap_pad = 32;
2038     }
2039    
2040 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2041     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2042     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2043 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2044 matty 6
2045 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2046 matty 9
2047     XFree(image);
2048 jsorg71 644 if (tdata != data)
2049 n-ki 279 xfree(tdata);
2050 matty 24 return (HBITMAP) bitmap;
2051 matty 6 }
2052    
2053 matty 25 void
2054 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2055 matty 6 {
2056 matty 10 XImage *image;
2057 matty 29 uint8 *tdata;
2058 stargo 521 int bitmap_pad;
2059    
2060 astrand 1042 if (g_server_depth == 8)
2061 stargo 521 {
2062     bitmap_pad = 8;
2063     }
2064     else
2065     {
2066     bitmap_pad = g_bpp;
2067    
2068     if (g_bpp == 24)
2069     bitmap_pad = 32;
2070     }
2071    
2072 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2073     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2074 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2075 matty 28
2076 jsorg71 450 if (g_ownbackstore)
2077 matty 31 {
2078 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2079     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2080 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2081     (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2082     x - sw->xoffset, y - sw->yoffset));
2083 matty 31 }
2084     else
2085     {
2086 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2087 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2088     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2089     x - sw->xoffset, y - sw->yoffset));
2090 matty 31 }
2091 matty 29
2092 matty 24 XFree(image);
2093 jsorg71 644 if (tdata != data)
2094 n-ki 279 xfree(tdata);
2095 matty 6 }
2096    
2097 matty 25 void
2098     ui_destroy_bitmap(HBITMAP bmp)
2099 matty 6 {
2100 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2101 matty 10 }
2102    
2103 matty 25 HGLYPH
2104 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2105 matty 10 {
2106 matty 9 XImage *image;
2107     Pixmap bitmap;
2108     int scanline;
2109 matty 6
2110 matty 9 scanline = (width + 7) / 8;
2111 matty 6
2112 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2113 jsorg71 725 if (g_create_glyph_gc == 0)
2114     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2115 matty 9
2116 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2117 astrand 73 width, height, 8, scanline);
2118 matty 23 image->byte_order = MSBFirst;
2119     image->bitmap_bit_order = MSBFirst;
2120     XInitImage(image);
2121    
2122 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2123 matty 29
2124 matty 9 XFree(image);
2125 astrand 64 return (HGLYPH) bitmap;
2126 matty 6 }
2127 matty 7
2128 matty 25 void
2129     ui_destroy_glyph(HGLYPH glyph)
2130 matty 7 {
2131 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2132 matty 9 }
2133    
2134 matty 29 HCURSOR
2135 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2136     uint8 * andmask, uint8 * xormask)
2137 matty 9 {
2138 matty 29 HGLYPH maskglyph, cursorglyph;
2139     XColor bg, fg;
2140     Cursor xcursor;
2141     uint8 *cursor, *pcursor;
2142     uint8 *mask, *pmask;
2143     uint8 nextbit;
2144     int scanline, offset;
2145     int i, j;
2146    
2147     scanline = (width + 7) / 8;
2148     offset = scanline * height;
2149    
2150 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2151 matty 29 memset(cursor, 0, offset);
2152    
2153 forsberg 415 mask = (uint8 *) xmalloc(offset);
2154 matty 29 memset(mask, 0, offset);
2155    
2156     /* approximate AND and XOR masks with a monochrome X pointer */
2157     for (i = 0; i < height; i++)
2158 matty 7 {
2159 matty 29 offset -= scanline;
2160     pcursor = &cursor[offset];
2161     pmask = &mask[offset];
2162    
2163     for (j = 0; j < scanline; j++)
2164 matty 28 {
2165 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2166     {
2167     if (xormask[0] || xormask[1] || xormask[2])
2168     {
2169     *pcursor |= (~(*andmask) & nextbit);
2170     *pmask |= nextbit;
2171     }
2172     else
2173     {
2174     *pcursor |= ((*andmask) & nextbit);
2175     *pmask |= (~(*andmask) & nextbit);
2176     }
2177    
2178     xormask += 3;
2179     }
2180    
2181     andmask++;
2182     pcursor++;
2183     pmask++;
2184 matty 28 }
2185 matty 7 }
2186 matty 29
2187     fg.red = fg.blue = fg.green = 0xffff;
2188     bg.red = bg.blue = bg.green = 0x0000;
2189     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2190    
2191     cursorglyph = ui_create_glyph(width, height, cursor);
2192     maskglyph = ui_create_glyph(width, height, mask);
2193    
2194 astrand 66 xcursor =
2195 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2196 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2197 astrand 64
2198 matty 29 ui_destroy_glyph(maskglyph);
2199     ui_destroy_glyph(cursorglyph);
2200     xfree(mask);
2201     xfree(cursor);
2202 astrand 64 return (HCURSOR) xcursor;
2203 matty 29 }
2204    
2205     void
2206     ui_set_cursor(HCURSOR cursor)
2207     {
2208 jsorg71 450 g_current_cursor = (Cursor) cursor;
2209     XDefineCursor(g_display, g_wnd, g_current_cursor);
2210 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2211 matty 29 }
2212    
2213     void
2214     ui_destroy_cursor(HCURSOR cursor)
2215     {
2216 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2217 matty 29 }
2218    
2219 astrand 508 void
2220     ui_set_null_cursor(void)
2221     {
2222     ui_set_cursor(g_null_cursor);
2223     }
2224    
2225 matty 29 #define MAKE_XCOLOR(xc,c) \
2226     (xc)->red = ((c)->red << 8) | (c)->red; \
2227     (xc)->green = ((c)->green << 8) | (c)->green; \
2228     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2229     (xc)->flags = DoRed | DoGreen | DoBlue;
2230    
2231 n-ki 279
2232 matty 29 HCOLOURMAP
2233 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2234 matty 29 {
2235     COLOURENTRY *entry;
2236     int i, ncolours = colours->ncolours;
2237 jsorg71 450 if (!g_owncolmap)
2238 matty 28 {
2239 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2240 n-ki 279 XColor xentry;
2241     XColor xc_cache[256];
2242     uint32 colour;
2243     int colLookup = 256;
2244     for (i = 0; i < ncolours; i++)
2245 matty 28 {
2246 n-ki 279 entry = &colours->colours[i];
2247     MAKE_XCOLOR(&xentry, entry);
2248 matty 7
2249 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2250 astrand 196 {
2251 n-ki 279 /* Allocation failed, find closest match. */
2252     int j = 256;
2253     int nMinDist = 3 * 256 * 256;
2254     long nDist = nMinDist;
2255 matty 28
2256 n-ki 279 /* only get the colors once */
2257     while (colLookup--)
2258 astrand 196 {
2259 n-ki 279 xc_cache[colLookup].pixel = colLookup;
2260     xc_cache[colLookup].red = xc_cache[colLookup].green =
2261     xc_cache[colLookup].blue = 0;
2262     xc_cache[colLookup].flags = 0;
2263 jsorg71 450 XQueryColor(g_display,
2264     DefaultColormap(g_display,
2265     DefaultScreen(g_display)),
2266 n-ki 279 &xc_cache[colLookup]);
2267 n-ki 185 }
2268 n-ki 279 colLookup = 0;
2269    
2270     /* approximate the pixel */
2271     while (j--)
2272 astrand 196 {
2273 n-ki 279 if (xc_cache[j].flags)
2274     {
2275     nDist = ((long) (xc_cache[j].red >> 8) -
2276     (long) (xentry.red >> 8)) *
2277     ((long) (xc_cache[j].red >> 8) -
2278     (long) (xentry.red >> 8)) +
2279     ((long) (xc_cache[j].green >> 8) -
2280     (long) (xentry.green >> 8)) *
2281     ((long) (xc_cache[j].green >> 8) -
2282     (long) (xentry.green >> 8)) +
2283     ((long) (xc_cache[j].blue >> 8) -
2284     (long) (xentry.blue >> 8)) *
2285     ((long) (xc_cache[j].blue >> 8) -
2286     (long) (xentry.blue >> 8));
2287     }
2288     if (nDist < nMinDist)
2289     {
2290     nMinDist = nDist;
2291     xentry.pixel = j;
2292     }
2293 n-ki 185 }
2294     }
2295 n-ki 279 colour = xentry.pixel;
2296    
2297     /* update our cache */
2298     if (xentry.pixel < 256)
2299     {
2300     xc_cache[xentry.pixel].red = xentry.red;
2301     xc_cache[xentry.pixel].green = xentry.green;
2302     xc_cache[xentry.pixel].blue = xentry.blue;
2303    
2304     }
2305    
2306 matthewc 527 map[i] = colour;
2307 n-ki 185 }
2308 n-ki 279 return map;
2309     }
2310     else
2311     {
2312     XColor *xcolours, *xentry;
2313     Colormap map;
2314 matty 29
2315 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2316 n-ki 279 for (i = 0; i < ncolours; i++)
2317 astrand 196 {
2318 n-ki 279 entry = &colours->colours[i];
2319     xentry = &xcolours[i];
2320     xentry->pixel = i;
2321     MAKE_XCOLOR(xentry, entry);
2322 matty 29 }
2323    
2324 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2325     XStoreColors(g_display, map, xcolours, ncolours);
2326 n-ki 185
2327 n-ki 279 xfree(xcolours);
2328     return (HCOLOURMAP) map;
2329 matty 29 }
2330 matty 7 }
2331    
2332 matty 25 void
2333     ui_destroy_colourmap(HCOLOURMAP map)
2334 matty 7 {
2335 jsorg71 450 if (!g_owncolmap)
2336 n-ki 279 xfree(map);
2337     else
2338 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2339 matty 7 }
2340    
2341 matty 25 void
2342     ui_set_colourmap(HCOLOURMAP map)
2343 matty 7 {
2344 jsorg71 450 if (!g_owncolmap)
2345 astrand 448 {
2346 jsorg71 450 if (g_colmap)
2347     xfree(g_colmap);
2348 astrand 448
2349 jsorg71 450 g_colmap = (uint32 *) map;
2350 astrand 448 }
2351 n-ki 279 else
2352 astrand 1089 {
2353 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2354 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2355     }
2356 matty 7 }
2357    
2358 matty 25 void
2359     ui_set_clip(int x, int y, int cx, int cy)
2360 matty 7 {
2361 astrand 1089 g_clip_rectangle.x = x;
2362     g_clip_rectangle.y = y;
2363     g_clip_rectangle.width = cx;
2364     g_clip_rectangle.height = cy;
2365     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2366 matty 9 }
2367 matty 7
2368 matty 25 void
2369 matthewc 192 ui_reset_clip(void)
2370 matty 9 {
2371 astrand 1089 g_clip_rectangle.x = 0;
2372     g_clip_rectangle.y = 0;
2373     g_clip_rectangle.width = g_width;
2374     g_clip_rectangle.height = g_height;
2375     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2376 matty 7 }
2377    
2378 matty 25 void
2379 matthewc 192 ui_bell(void)
2380 matty 10 {
2381 jsorg71 450 XBell(g_display, 0);
2382 matty 10 }
2383    
2384 matty 25 void
2385     ui_destblt(uint8 opcode,
2386     /* dest */ int x, int y, int cx, int cy)
2387 matty 9 {
2388 matty 29 SET_FUNCTION(opcode);
2389 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2390 matty 29 RESET_FUNCTION(opcode);
2391 matty 9 }
2392    
2393 jsorg71 373 static uint8 hatch_patterns[] = {
2394 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2395     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2396     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2397     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2398     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2399     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2400 jsorg71 373 };
2401    
2402 matty 25 void
2403     ui_patblt(uint8 opcode,
2404     /* dest */ int x, int y, int cx, int cy,
2405 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2406 matty 9 {
2407     Pixmap fill;
2408 jsorg71 59 uint8 i, ipattern[8];
2409 matty 9
2410 matty 29 SET_FUNCTION(opcode);
2411 matty 9
2412     switch (brush->style)
2413     {
2414 matty 24 case 0: /* Solid */
2415 matty 29 SET_FOREGROUND(fgcolour);
2416 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2417 matty 9 break;
2418    
2419 jsorg71 373 case 2: /* Hatch */
2420 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2421     hatch_patterns + brush->pattern[0] * 8);
2422 astrand 487 SET_FOREGROUND(fgcolour);
2423     SET_BACKGROUND(bgcolour);
2424 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2425     XSetStipple(g_display, g_gc, fill);
2426     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2427 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2428 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2429     XSetTSOrigin(g_display, g_gc, 0, 0);
2430 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
2431     break;
2432    
2433 matty 24 case 3: /* Pattern */
2434 jsorg71 59 for (i = 0; i != 8; i++)
2435     ipattern[7 - i] = brush->pattern[i];
2436     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2437 matty 29 SET_FOREGROUND(bgcolour);
2438     SET_BACKGROUND(fgcolour);
2439 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2440     XSetStipple(g_display, g_gc, fill);
2441     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2442 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2443 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2444     XSetTSOrigin(g_display, g_gc, 0, 0);
2445 astrand 64 ui_destroy_glyph((HGLYPH) fill);
2446 matty 9 break;
2447    
2448     default:
2449 matty 30 unimpl("brush %d\n", brush->style);
2450 matty 9 }
2451 matty 29
2452     RESET_FUNCTION(opcode);
2453 jsorg71 680
2454     if (g_ownbackstore)
2455     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2456 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2457     (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2458     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2459 matty 9 }
2460    
2461 matty 25 void
2462     ui_screenblt(uint8 opcode,
2463     /* dest */ int x, int y, int cx, int cy,
2464     /* src */ int srcx, int srcy)
2465 matty 9 {
2466 matty 29 SET_FUNCTION(opcode);
2467 jsorg71 450 if (g_ownbackstore)
2468 stargo 609 {
2469 astrand 1089 XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2470     g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2471     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2472 stargo 609 }
2473     else
2474     {
2475     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2476     }
2477 astrand 1089
2478     ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2479     (g_display, g_ownbackstore ? g_backstore : g_wnd,
2480     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2481    
2482 matty 29 RESET_FUNCTION(opcode);
2483 matty 9 }
2484    
2485 matty 25 void
2486     ui_memblt(uint8 opcode,
2487     /* dest */ int x, int y, int cx, int cy,
2488     /* src */ HBITMAP src, int srcx, int srcy)
2489 matty 9 {
2490 matty 29 SET_FUNCTION(opcode);
2491 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2492 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2493     (g_display, (Pixmap) src, sw->wnd, g_gc,
2494     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2495 jsorg71 450 if (g_ownbackstore)
2496     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2497 matty 29 RESET_FUNCTION(opcode);
2498 matty 9 }
2499    
2500 matty 25 void
2501     ui_triblt(uint8 opcode,
2502     /* dest */ int x, int y, int cx, int cy,
2503     /* src */ HBITMAP src, int srcx, int srcy,
2504 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2505 matty 9 {
2506     /* This is potentially difficult to do in general. Until someone
2507 matty 10 comes up with a more efficient way of doing it I am using cases. */
2508 matty 9
2509     switch (opcode)
2510     {
2511 matty 24 case 0x69: /* PDSxxn */
2512 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2513 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2514 matty 16 break;
2515    
2516 matty 24 case 0xb8: /* PSDPxax */
2517 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2518 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2519 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2520 matty 9 break;
2521    
2522 matty 29 case 0xc0: /* PSa */
2523 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2524 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2525 matty 28 break;
2526    
2527 matty 9 default:
2528 matty 30 unimpl("triblt 0x%x\n", opcode);
2529 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2530 matty 9 }
2531     }
2532    
2533 matty 25 void
2534     ui_line(uint8 opcode,
2535     /* dest */ int startx, int starty, int endx, int endy,
2536 astrand 64 /* pen */ PEN * pen)
2537 matty 9 {
2538 matty 29 SET_FUNCTION(opcode);
2539     SET_FOREGROUND(pen->colour);
2540 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2541 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2542     startx - sw->xoffset, starty - sw->yoffset,
2543     endx - sw->xoffset, endy - sw->yoffset));
2544 jsorg71 450 if (g_ownbackstore)
2545     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2546 matty 29 RESET_FUNCTION(opcode);
2547 matty 9 }
2548    
2549 matty 25 void
2550     ui_rect(
2551     /* dest */ int x, int y, int cx, int cy,
2552     /* brush */ int colour)
2553 matty 9 {
2554 matty 29 SET_FOREGROUND(colour);
2555 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2556 matty 9 }
2557    
2558 jdmeijer 831 void
2559     ui_polygon(uint8 opcode,
2560     /* mode */ uint8 fillmode,
2561     /* dest */ POINT * point, int npoints,
2562     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2563     {
2564     uint8 style, i, ipattern[8];
2565     Pixmap fill;
2566    
2567     SET_FUNCTION(opcode);
2568    
2569     switch (fillmode)
2570     {
2571     case ALTERNATE:
2572     XSetFillRule(g_display, g_gc, EvenOddRule);
2573     break;
2574     case WINDING:
2575     XSetFillRule(g_display, g_gc, WindingRule);
2576     break;
2577     default:
2578     unimpl("fill mode %d\n", fillmode);
2579     }
2580    
2581     if (brush)
2582     style = brush->style;
2583     else
2584     style = 0;
2585    
2586     switch (style)
2587     {
2588     case 0: /* Solid */
2589     SET_FOREGROUND(fgcolour);
2590     FILL_POLYGON((XPoint *) point, npoints);
2591     break;
2592    
2593     case 2: /* Hatch */
2594     fill = (Pixmap) ui_create_glyph(8, 8,
2595     hatch_patterns + brush->pattern[0] * 8);
2596     SET_FOREGROUND(fgcolour);
2597     SET_BACKGROUND(bgcolour);
2598     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2599     XSetStipple(g_display, g_gc, fill);
2600     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2601     FILL_POLYGON((XPoint *) point, npoints);
2602     XSetFillStyle(g_display, g_gc, FillSolid);
2603     XSetTSOrigin(g_display, g_gc, 0, 0);
2604     ui_destroy_glyph((HGLYPH) fill);
2605     break;
2606    
2607     case 3: /* Pattern */
2608     for (i = 0; i != 8; i++)
2609     ipattern[7 - i] = brush->pattern[i];
2610     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2611     SET_FOREGROUND(bgcolour);
2612     SET_BACKGROUND(fgcolour);
2613     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2614     XSetStipple(g_display, g_gc, fill);
2615     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2616     FILL_POLYGON((XPoint *) point, npoints);
2617     XSetFillStyle(g_display, g_gc, FillSolid);
2618     XSetTSOrigin(g_display, g_gc, 0, 0);
2619     ui_destroy_glyph((HGLYPH) fill);
2620     break;
2621    
2622     default:
2623     unimpl("brush %d\n", brush->style);
2624     }
2625    
2626     RESET_FUNCTION(opcode);
2627     }
2628    
2629     void
2630 jdmeijer 844 ui_polyline(uint8 opcode,
2631     /* dest */ POINT * points, int npoints,
2632     /* pen */ PEN * pen)
2633     {
2634     /* TODO: set join style */
2635     SET_FUNCTION(opcode);
2636     SET_FOREGROUND(pen->colour);
2637     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2638     if (g_ownbackstore)
2639     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2640     CoordModePrevious);
2641 astrand 1089
2642     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2643     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2644    
2645 jdmeijer 844 RESET_FUNCTION(opcode);
2646     }
2647    
2648     void
2649 jdmeijer 831 ui_ellipse(uint8 opcode,
2650     /* mode */ uint8 fillmode,
2651     /* dest */ int x, int y, int cx, int cy,
2652     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2653     {
2654     uint8 style, i, ipattern[8];
2655     Pixmap fill;
2656    
2657     SET_FUNCTION(opcode);
2658    
2659     if (brush)
2660     style = brush->style;
2661     else
2662     style = 0;
2663    
2664     switch (style)
2665     {
2666     case 0: /* Solid */
2667     SET_FOREGROUND(fgcolour);
2668     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2669     break;
2670    
2671     case 2: /* Hatch */
2672     fill = (Pixmap) ui_create_glyph(8, 8,
2673     hatch_patterns + brush->pattern[0] * 8);
2674     SET_FOREGROUND(fgcolour);
2675     SET_BACKGROUND(bgcolour);
2676     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2677     XSetStipple(g_display, g_gc, fill);
2678     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2679     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2680     XSetFillStyle(g_display, g_gc, FillSolid);
2681     XSetTSOrigin(g_display, g_gc, 0, 0);
2682     ui_destroy_glyph((HGLYPH) fill);
2683     break;
2684    
2685     case 3: /* Pattern */
2686     for (i = 0; i != 8; i++)
2687     ipattern[7 - i] = brush->pattern[i];
2688     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2689     SET_FOREGROUND(bgcolour);
2690     SET_BACKGROUND(fgcolour);
2691     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2692     XSetStipple(g_display, g_gc, fill);
2693     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2694     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2695     XSetFillStyle(g_display, g_gc, FillSolid);
2696     XSetTSOrigin(g_display, g_gc, 0, 0);
2697     ui_destroy_glyph((HGLYPH) fill);
2698     break;
2699    
2700     default:
2701     unimpl("brush %d\n", brush->style);
2702     }
2703    
2704     RESET_FUNCTION(opcode);
2705     }
2706    
2707 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
2708 matty 25 void
2709     ui_draw_glyph(int mixmode,
2710     /* dest */ int x, int y, int cx, int cy,
2711 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
2712     int bgcolour, int fgcolour)
2713 matty 9 {
2714 matty 29 SET_FOREGROUND(fgcolour);
2715     SET_BACKGROUND(bgcolour);
2716 matty 9
2717 jsorg71 450 XSetFillStyle(g_display, g_gc,
2718 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2719 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2720     XSetTSOrigin(g_display, g_gc, x, y);
2721 matty 9
2722 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2723 matty 9
2724 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2725 matty 9 }
2726    
2727 mmihalik 49 #define DO_GLYPH(ttext,idx) \
2728     {\
2729     glyph = cache_get_font (font, ttext[idx]);\
2730     if (!(flags & TEXT2_IMPLICIT_X))\
2731 jsorg71 564 {\
2732     xyoffset = ttext[++idx];\
2733     if ((xyoffset & 0x80))\
2734 mmihalik 49 {\
2735 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2736     y += ttext[idx+1] | (ttext[idx+2] << 8);\
2737 mmihalik 49 else\
2738 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2739     idx += 2;\
2740 mmihalik 49 }\
2741 jsorg71 564 else\
2742 mmihalik 49 {\
2743 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2744     y += xyoffset;\
2745     else\
2746     x += xyoffset;\
2747 mmihalik 49 }\
2748 jsorg71 564 }\
2749     if (glyph != NULL)\
2750     {\
2751     x1 = x + glyph->offset;\
2752     y1 = y + glyph->baseline;\
2753     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2754     XSetTSOrigin(g_display, g_gc, x1, y1);\
2755     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2756     if (flags & TEXT2_IMPLICIT_X)\
2757     x += glyph->width;\
2758     }\
2759 mmihalik 49 }
2760    
2761 matty 25 void
2762 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2763 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
2764 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2765     int bgcolour, int fgcolour, uint8 * text, uint8 length)
2766 matty 9 {
2767 jdmeijer 843 /* TODO: use brush appropriately */
2768    
2769 matty 10 FONTGLYPH *glyph;
2770 jsorg71 564 int i, j, xyoffset, x1, y1;
2771 mmihalik 49 DATABLOB *entry;
2772 matty 9
2773 matty 29 SET_FOREGROUND(bgcolour);
2774 matty 28
2775 astrand 620 /* Sometimes, the boxcx value is something really large, like
2776     32691. This makes XCopyArea fail with Xvnc. The code below
2777     is a quick fix. */
2778     if (boxx + boxcx > g_width)
2779     boxcx = g_width - boxx;
2780    
2781 matty 9 if (boxcx > 1)
2782 matty 31 {
2783 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2784 matty 31 }
2785 matty 17 else if (mixmode == MIX_OPAQUE)
2786 matty 31 {
2787 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2788 matty 31 }
2789 matty 9
2790 jsorg71 564 SET_FOREGROUND(fgcolour);
2791     SET_BACKGROUND(bgcolour);
2792     XSetFillStyle(g_display, g_gc, FillStippled);
2793    
2794 matty 9 /* Paint text, character by character */
2795 astrand 64 for (i = 0; i < length;)
2796     {
2797     switch (text[i])
2798     {
2799     case 0xff:
2800 astrand 1031 /* At least two bytes needs to follow */
2801 astrand 1029 if (i + 3 > length)
2802 astrand 64 {
2803 astrand 1031 warning("Skipping short 0xff command:");
2804     for (j = 0; j < length; j++)
2805     fprintf(stderr, "%02x ", text[j]);
2806     fprintf(stderr, "\n");
2807 astrand 1029 i = length = 0;
2808     break;
2809 astrand 64 }
2810 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
2811     i += 3;
2812     length -= i;
2813 astrand 64 /* this will move pointer from start to first character after FF command */
2814 astrand 1029 text = &(text[i]);
2815 astrand 64 i = 0;
2816 mmihalik 49 break;
2817 matty 9
2818 astrand 64 case 0xfe:
2819 astrand 1031 /* At least one byte needs to follow */
2820     if (i + 2 > length)
2821 astrand 1029 {
2822 astrand 1031 warning("Skipping short 0xfe command:");
2823     for (j = 0; j < length; j++)
2824     fprintf(stderr, "%02x ", text[j]);
2825     fprintf(stderr, "\n");
2826 astrand 1029 i = length = 0;
2827     break;
2828     }
2829 astrand 64 entry = cache_get_text(text[i + 1]);
2830 astrand 1030 if (entry->data != NULL)
2831 astrand 64 {
2832 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
2833     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
2834 astrand 64 {
2835     if (flags & TEXT2_VERTICAL)
2836     y += text[i + 2];
2837     else
2838     x += text[i + 2];
2839     }
2840     for (j = 0; j < entry->size; j++)
2841 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
2842 matthewc 44 }
2843 astrand 1031 if (i + 2 < length)
2844     i += 3;
2845     else
2846     i += 2;
2847 jsorg71 286 length -= i;
2848     /* this will move pointer from start to first character after FE command */
2849     text = &(text[i]);
2850     i = 0;
2851 astrand 64 break;
2852 matty 17
2853 astrand 64 default:
2854     DO_GLYPH(text, i);
2855     i++;
2856     break;
2857 matty 29 }
2858 mmihalik 49 }
2859 jsorg71 564
2860     XSetFillStyle(g_display, g_gc, FillSolid);
2861    
2862 jsorg71 450 if (g_ownbackstore)
2863 jsorg71 278 {
2864     if (boxcx > 1)
2865 astrand 1089 {
2866 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2867 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
2868 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2869     (g_display, g_backstore, sw->wnd, g_gc,
2870     boxx, boxy,
2871     boxcx, boxcy,
2872     boxx - sw->xoffset, boxy - sw->yoffset));
2873     }
2874 jsorg71 278 else
2875 astrand 1089 {
2876 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2877 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
2878 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2879     (g_display, g_backstore, sw->wnd, g_gc,
2880     clipx, clipy,
2881     clipcx, clipcy, clipx - sw->xoffset,
2882     clipy - sw->yoffset));
2883     }
2884 jsorg71 278 }
2885 matty 9 }
2886    
2887 matty 25 void
2888     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2889 matty 9 {
2890 matty 28 Pixmap pix;
2891 matty 9 XImage *image;
2892    
2893 jsorg71 450 if (g_ownbackstore)
2894 matty 31 {
2895 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2896 matty 31 }
2897     else
2898     {
2899 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2900     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2901     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2902     XFreePixmap(g_display, pix);
2903 matty 31 }
2904 matty 28
2905 jsorg71 450 offset *= g_bpp / 8;
2906     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2907 matty 28
2908     XDestroyImage(image);
2909 matty 9 }
2910    
2911 matty 25 void
2912     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2913 matty 9 {
2914     XImage *image;
2915 matty 10 uint8 *data;
2916 matty 9
2917 jsorg71 450 offset *= g_bpp / 8;
2918     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2919 matty 10 if (data == NULL)
2920     return;
2921 matty 29
2922 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2923     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2924 matty 29
2925 jsorg71 450 if (g_ownbackstore)
2926 matty 31 {
2927 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2928     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2929 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2930     (g_display, g_backstore, sw->wnd, g_gc,
2931     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2932 matty 31 }
2933     else
2934     {
2935 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2936 astrand 1089 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2937     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2938     x - sw->xoffset, y - sw->yoffset));
2939 matty 31 }
2940    
2941 matty 9 XFree(image);
2942     }
2943 jsorg71 713
2944     /* these do nothing here but are used in uiports */
2945     void
2946     ui_begin_update(void)
2947     {
2948     }
2949    
2950     void
2951     ui_end_update(void)
2952     {
2953     }
2954 astrand 1089
2955     void
2956     ui_seamless_toggle()
2957     {
2958     if (g_seamless_rdp)
2959     {
2960     /* Deactivate */
2961     while (g_seamless_windows)
2962     {
2963     XDestroyWindow(g_display, g_seamless_windows->wnd);
2964     seamless_remove_window(g_seamless_windows);
2965     }
2966     XMapWindow(g_display, g_wnd);
2967     }
2968     else
2969     {
2970     /* Activate */
2971     if (g_win_button_size)
2972     {
2973     error("SeamlessRDP mode cannot be activated when using single application mode\n");
2974     return;
2975     }
2976     if (!g_using_full_workarea)
2977     {
2978     error("SeamlessRDP mode requires a session that covers the whole screen");
2979     return;
2980     }
2981    
2982     XUnmapWindow(g_display, g_wnd);
2983     seamless_send_sync();
2984     }
2985    
2986     g_seamless_rdp = !g_seamless_rdp;
2987     }
2988    
2989     void
2990     ui_seamless_create_window(unsigned long id, unsigned long flags)
2991     {
2992     Window wnd;
2993     XSetWindowAttributes attribs;
2994     XClassHint *classhints;
2995     long input_mask;
2996     seamless_window *sw;
2997    
2998     get_window_attribs(&attribs);
2999    
3000     attribs.override_redirect = False;
3001    
3002     /* FIXME: Do not assume that -1, -1 is outside screen Consider
3003     wait with showing the window until STATE and others have
3004     been recieved. */
3005     wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, 0,
3006     InputOutput, g_visual,
3007     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
3008     CWBorderPixel, &attribs);
3009    
3010     XStoreName(g_display, wnd, "rdesktop-seamless");
3011    
3012     mwm_hide_decorations(wnd);
3013    
3014     classhints = XAllocClassHint();
3015     if (classhints != NULL)
3016     {
3017     classhints->res_name = classhints->res_class = "rdesktop";
3018     XSetClassHint(g_display, wnd, classhints);
3019     XFree(classhints);
3020     }
3021    
3022     /* FIXME: Support for Input Context:s */
3023    
3024     get_input_mask(&input_mask);
3025    
3026     XSelectInput(g_display, wnd, input_mask);
3027    
3028     XMapWindow(g_display, wnd);
3029    
3030     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3031     seamless window, we could try to close the window on the
3032     serverside, instead of terminating rdesktop */
3033     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3034    
3035     sw = malloc(sizeof(seamless_window));
3036     sw->wnd = wnd;
3037     sw->id = id;
3038     sw->xoffset = 0;
3039     sw->yoffset = 0;
3040     sw->width = 0;
3041     sw->height = 0;
3042     sw->next = g_seamless_windows;
3043     g_seamless_windows = sw;
3044     }
3045    
3046    
3047     void
3048     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3049     {
3050     seamless_window *sw;
3051     sw = seamless_get_window_by_id(id);
3052    
3053     if (!sw)
3054     {
3055     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3056     return;
3057     }
3058    
3059     XDestroyWindow(g_display, sw->wnd);
3060     seamless_remove_window(sw);
3061     }
3062    
3063    
3064     void
3065     ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3066     {
3067     seamless_window *sw;
3068    
3069     sw = seamless_get_window_by_id(id);
3070    
3071     if (!sw)
3072     {
3073     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3074     return;
3075     }
3076    
3077     if (!width || !height)
3078     /* X11 windows must be at least 1x1 */
3079     return;
3080    
3081     /* About MAX and MIN: Windows allows moving a window outside
3082     the desktop. This happens, for example, when maximizing an
3083     application. In this case, the position is set to something
3084     like -4,-4,1288,1032. Many WMs does not allow windows
3085     outside the desktop, however. Therefore, clip the window
3086     ourselves. */
3087     sw->xoffset = MAX(0, x);
3088     sw->yoffset = MAX(0, y);
3089     sw->width = MIN(MIN(width, width + x), g_width - sw->xoffset);
3090     sw->height = MIN(MIN(height, height + y), g_height - sw->yoffset);
3091    
3092     /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3093     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3094     }
3095    
3096    
3097     void
3098 astrand 1094 ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3099 astrand 1089 {
3100     seamless_window *sw;
3101    
3102     sw = seamless_get_window_by_id(id);
3103    
3104     XStoreName(g_display, sw->wnd, title);
3105     }
3106    
3107    
3108     void
3109     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3110     {
3111     seamless_window *sw;
3112    
3113     sw = seamless_get_window_by_id(id);
3114    
3115     switch (state)
3116     {
3117     case SEAMLESSRDP_NORMAL:
3118     case SEAMLESSRDP_MAXIMIZED:
3119     /* FIXME */
3120     break;
3121     case SEAMLESSRDP_MINIMIZED:
3122     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3123     break;
3124     default:
3125     warning("SeamlessRDP: Invalid state %d\n", state);
3126     break;
3127     }
3128     }

  ViewVC Help
Powered by ViewVC 1.1.26