/[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 1170 - (hide annotations)
Mon Mar 20 15:43:15 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 80635 byte(s)
Cleaned up SeamlessRDP functions: All utility functions are prefixed with sw_.

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

  ViewVC Help
Powered by ViewVC 1.1.26