/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1246 - (hide annotations)
Tue Jul 11 17:22:24 2006 UTC (17 years, 10 months ago) by stargo
File MIME type: text/plain
File size: 84213 byte(s)
set screen-number in XGetVisualInfo (patch 1417414 by Jeremy Smith)

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

  ViewVC Help
Powered by ViewVC 1.1.26