/[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 1168 - (hide annotations)
Mon Mar 20 14:39:00 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 80822 byte(s)
Make sure we do not update seamless windows' offsets until we get an ACK
back (i.e. when the request has been executed).

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

  ViewVC Help
Powered by ViewVC 1.1.26