/[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 1159 - (hide annotations)
Fri Mar 17 15:16:52 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 80056 byte(s)
Set _NET_WM_STATE property manually for withdrawn windows.

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

  ViewVC Help
Powered by ViewVC 1.1.26