/[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 1157 - (hide annotations)
Fri Mar 17 12:39:09 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 80178 byte(s)
Send back our local positions upon changes, but only after a small timeout.

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

  ViewVC Help
Powered by ViewVC 1.1.26