/[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 1155 - (hide annotations)
Fri Mar 17 10:48:11 2006 UTC (18 years, 3 months ago) by ossman_
File MIME type: text/plain
File size: 79096 byte(s)
Add some client side book keeping of window ordering and focus in order to
not send unnecessary updates. This is done to avoid side effects for commands
that would seem to be no-ops.

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

  ViewVC Help
Powered by ViewVC 1.1.26