/[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 1226 - (hide annotations)
Wed Apr 12 06:47:24 2006 UTC (18 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 83817 byte(s)
The default color depth is now the depth of the root window.

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     select_visual()
1318     {
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 astrand 1042 vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &visuals_count);
1344     g_visual = NULL;
1345     g_no_translate_image = False;
1346 astrand 1049 g_compatible_arch = False;
1347 astrand 1042 if (vmatches != NULL)
1348 matthewc 527 {
1349 astrand 1042 for (i = 0; i < visuals_count; ++i)
1350 stargo 565 {
1351 astrand 1042 XVisualInfo *visual_info = &vmatches[i];
1352 astrand 1223 BOOL can_translate_to_bpp = False;
1353     int j;
1354 stargo 565
1355 astrand 1042 /* Try to find a no-translation visual that'll
1356     allow us to use RDP bitmaps directly as ZPixmaps. */
1357     if (!g_xserver_be && (((visual_info->depth == 15) &&
1358     /* R5G5B5 */
1359     (visual_info->red_mask == 0x7c00) &&
1360     (visual_info->green_mask == 0x3e0) &&
1361     (visual_info->blue_mask == 0x1f)) ||
1362     ((visual_info->depth == 16) &&
1363     /* R5G6B5 */
1364     (visual_info->red_mask == 0xf800) &&
1365     (visual_info->green_mask == 0x7e0) &&
1366     (visual_info->blue_mask == 0x1f)) ||
1367     ((visual_info->depth == 24) &&
1368     /* R8G8B8 */
1369     (visual_info->red_mask == 0xff0000) &&
1370     (visual_info->green_mask == 0xff00) &&
1371     (visual_info->blue_mask == 0xff))))
1372     {
1373     g_visual = visual_info->visual;
1374     g_depth = visual_info->depth;
1375 astrand 1049 g_compatible_arch = !g_host_be;
1376 astrand 1042 g_no_translate_image = (visual_info->depth == g_server_depth);
1377     if (g_no_translate_image)
1378     /* We found the best visual */
1379     break;
1380     }
1381     else
1382     {
1383 astrand 1049 g_compatible_arch = False;
1384 astrand 1042 }
1385 jsorg71 644
1386 astrand 1042 if (visual_info->depth > 24)
1387     {
1388     /* Avoid 32-bit visuals and likes like the plague.
1389     They're either untested or proven to work bad
1390     (e.g. nvidia's Composite 32-bit visual).
1391     Most implementation offer a 24-bit visual anyway. */
1392     continue;
1393     }
1394 stargo 565
1395 astrand 1042 /* Only care for visuals, for whose BPPs (not depths!)
1396     we have a translateXtoY function. */
1397     for (j = 0; j < pixmap_formats_count; ++j)
1398     {
1399     if (pfm[j].depth == visual_info->depth)
1400     {
1401     if ((pfm[j].bits_per_pixel == 16) ||
1402     (pfm[j].bits_per_pixel == 24) ||
1403     (pfm[j].bits_per_pixel == 32))
1404     {
1405     can_translate_to_bpp = True;
1406     }
1407     break;
1408     }
1409     }
1410    
1411     /* Prefer formats which have the most colour depth.
1412     We're being truly aristocratic here, minding each
1413     weight on its own. */
1414     if (can_translate_to_bpp)
1415     {
1416     unsigned vis_red_weight =
1417     calculate_mask_weight(visual_info->red_mask);
1418     unsigned vis_green_weight =
1419     calculate_mask_weight(visual_info->green_mask);
1420     unsigned vis_blue_weight =
1421     calculate_mask_weight(visual_info->blue_mask);
1422     if ((vis_red_weight >= red_weight)
1423     && (vis_green_weight >= green_weight)
1424     && (vis_blue_weight >= blue_weight))
1425     {
1426     red_weight = vis_red_weight;
1427     green_weight = vis_green_weight;
1428     blue_weight = vis_blue_weight;
1429     g_visual = visual_info->visual;
1430     g_depth = visual_info->depth;
1431     }
1432     }
1433 stargo 565 }
1434 astrand 1042 XFree(vmatches);
1435 matthewc 527 }
1436 astrand 1042
1437     if (g_visual != NULL)
1438     {
1439     g_owncolmap = False;
1440     calculate_shifts(g_visual->red_mask, &g_red_shift_r, &g_red_shift_l);
1441     calculate_shifts(g_visual->green_mask, &g_green_shift_r, &g_green_shift_l);
1442     calculate_shifts(g_visual->blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1443     }
1444 matthewc 527 else
1445     {
1446 astrand 1042 template.class = PseudoColor;
1447     template.depth = 8;
1448     template.colormap_size = 256;
1449     vmatches =
1450     XGetVisualInfo(g_display,
1451     VisualClassMask | VisualDepthMask | VisualColormapSizeMask,
1452     &template, &visuals_count);
1453     if (vmatches == NULL)
1454 matthewc 527 {
1455 astrand 1042 error("No usable TrueColor or PseudoColor visuals on this display.\n");
1456     XCloseDisplay(g_display);
1457     XFree(pfm);
1458 matthewc 527 return False;
1459     }
1460    
1461 astrand 1042 /* we use a colourmap, so the default visual should do */
1462     g_owncolmap = True;
1463     g_visual = vmatches[0].visual;
1464     g_depth = vmatches[0].depth;
1465     }
1466 jsorg71 644
1467 astrand 1042 g_bpp = 0;
1468     for (i = 0; i < pixmap_formats_count; ++i)
1469     {
1470     XPixmapFormatValues *pf = &pfm[i];
1471     if (pf->depth == g_depth)
1472 jdmeijer 821 {
1473 astrand 1042 g_bpp = pf->bits_per_pixel;
1474    
1475     if (g_no_translate_image)
1476 jdmeijer 821 {
1477 astrand 1042 switch (g_server_depth)
1478     {
1479     case 15:
1480     case 16:
1481     if (g_bpp != 16)
1482     g_no_translate_image = False;
1483     break;
1484     case 24:
1485     /* Yes, this will force image translation
1486     on most modern servers which use 32 bits
1487     for R8G8B8. */
1488     if (g_bpp != 24)
1489     g_no_translate_image = False;
1490     break;
1491     default:
1492     g_no_translate_image = False;
1493     break;
1494     }
1495 jdmeijer 821 }
1496    
1497 astrand 1042 /* Pixmap formats list is a depth-to-bpp mapping --
1498     there's just a single entry for every depth,
1499     so we can safely break here */
1500     break;
1501 jdmeijer 821 }
1502 matthewc 527 }
1503 astrand 1042 XFree(pfm);
1504     pfm = NULL;
1505     return True;
1506     }
1507 matthewc 527
1508 astrand 1199 static XErrorHandler g_old_error_handler;
1509    
1510     static int
1511     error_handler(Display * dpy, XErrorEvent * eev)
1512     {
1513     if ((eev->error_code == BadMatch) && (eev->request_code == X_ConfigureWindow))
1514     {
1515     fprintf(stderr, "Got \"BadMatch\" when trying to restack windows.\n");
1516     fprintf(stderr,
1517     "This is most likely caused by a broken window manager (commonly KWin).\n");
1518     return 0;
1519     }
1520    
1521     return g_old_error_handler(dpy, eev);
1522     }
1523    
1524 astrand 1042 BOOL
1525     ui_init(void)
1526     {
1527     int screen_num;
1528    
1529     g_display = XOpenDisplay(NULL);
1530     if (g_display == NULL)
1531 matthewc 121 {
1532 astrand 1042 error("Failed to open display: %s\n", XDisplayName(NULL));
1533     return False;
1534 matthewc 121 }
1535    
1536     {
1537 astrand 1042 uint16 endianess_test = 1;
1538     g_host_be = !(BOOL) (*(uint8 *) (&endianess_test));
1539     }
1540    
1541 astrand 1199 g_old_error_handler = XSetErrorHandler(error_handler);
1542 astrand 1042 g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1543     screen_num = DefaultScreen(g_display);
1544     g_x_socket = ConnectionNumber(g_display);
1545     g_screen = ScreenOfDisplay(g_display, screen_num);
1546     g_depth = DefaultDepthOfScreen(g_screen);
1547    
1548     if (!select_visual())
1549 matthewc 121 return False;
1550 astrand 1042
1551     if (g_no_translate_image)
1552     {
1553     DEBUG(("Performance optimization possible: avoiding image translation (colour depth conversion).\n"));
1554 matthewc 121 }
1555    
1556 astrand 1042 if (g_server_depth > g_bpp)
1557     {
1558     warning("Remote desktop colour depth %d higher than display colour depth %d.\n",
1559     g_server_depth, g_bpp);
1560     }
1561    
1562     DEBUG(("RDP depth: %d, display depth: %d, display bpp: %d, X server BE: %d, host BE: %d\n",
1563     g_server_depth, g_depth, g_bpp, g_xserver_be, g_host_be));
1564    
1565 matthewc 517 if (!g_owncolmap)
1566 n-ki 279 {
1567 astrand 580 g_xcolmap =
1568     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1569     AllocNone);
1570 jsorg71 450 if (g_depth <= 8)
1571 astrand 1042 warning("Display colour depth is %d bit: you may want to use -C for a private colourmap.\n", g_depth);
1572 n-ki 279 }
1573    
1574 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1575     {
1576 astrand 1042 warning("External BackingStore not available. Using internal.\n");
1577 jsorg71 450 g_ownbackstore = True;
1578 stargo 609 }
1579 matthewc 121
1580 astrand 500 /*
1581     * Determine desktop size
1582     */
1583 astrand 547 if (g_fullscreen)
1584 astrand 263 {
1585 astrand 547 g_width = WidthOfScreen(g_screen);
1586     g_height = HeightOfScreen(g_screen);
1587 astrand 1057 g_using_full_workarea = True;
1588 astrand 547 }
1589     else if (g_width < 0)
1590     {
1591 astrand 500 /* Percent of screen */
1592 astrand 991 if (-g_width >= 100)
1593     g_using_full_workarea = True;
1594 astrand 500 g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1595     g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1596     }
1597     else if (g_width == 0)
1598     {
1599 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1600 matthewc 300 uint32 x, y, cx, cy;
1601     if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1602 astrand 263 {
1603 jsorg71 447 g_width = cx;
1604     g_height = cy;
1605 astrand 1057 g_using_full_workarea = True;
1606 matthewc 300 }
1607     else
1608     {
1609 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1610 astrand 1057 g_width = WidthOfScreen(g_screen);
1611     g_height = HeightOfScreen(g_screen);
1612 astrand 263 }
1613     }
1614 matthewc 121
1615 matthewc 160 /* make sure width is a multiple of 4 */
1616 jsorg71 447 g_width = (g_width + 3) & ~3;
1617 matthewc 160
1618 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1619 matthewc 203
1620 astrand 498 xkeymap_init();
1621    
1622 jsorg71 447 if (g_enable_compose)
1623 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1624 matthewc 188
1625 matthewc 432 xclip_init();
1626 astrand 1199 ewmh_init();
1627     if (g_seamless_rdp)
1628     seamless_init();
1629 jsorg71 316
1630 astrand 1042 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_depth, g_bpp, g_depth));
1631 jsorg71 316
1632 jsorg71 81 return True;
1633     }
1634 astrand 66
1635 matthewc 188 void
1636 matthewc 192 ui_deinit(void)
1637 matthewc 188 {
1638 astrand 1199 while (g_seamless_windows)
1639     {
1640     XDestroyWindow(g_display, g_seamless_windows->wnd);
1641     sw_remove_window(g_seamless_windows);
1642     }
1643    
1644 ossman_ 1214 xclip_deinit();
1645    
1646 jsorg71 450 if (g_IM != NULL)
1647     XCloseIM(g_IM);
1648 astrand 580
1649 stargo 576 if (g_null_cursor != NULL)
1650     ui_destroy_cursor(g_null_cursor);
1651 matthewc 188
1652 jsorg71 450 XFreeModifiermap(g_mod_map);
1653 matthewc 203
1654 jsorg71 450 if (g_ownbackstore)
1655     XFreePixmap(g_display, g_backstore);
1656 matthewc 188
1657 jsorg71 450 XFreeGC(g_display, g_gc);
1658     XCloseDisplay(g_display);
1659     g_display = NULL;
1660 matthewc 188 }
1661    
1662 astrand 1199
1663     static void
1664     get_window_attribs(XSetWindowAttributes * attribs)
1665     {
1666     attribs->background_pixel = BlackPixelOfScreen(g_screen);
1667     attribs->background_pixel = WhitePixelOfScreen(g_screen);
1668     attribs->border_pixel = WhitePixelOfScreen(g_screen);
1669     attribs->backing_store = g_ownbackstore ? NotUseful : Always;
1670     attribs->override_redirect = g_fullscreen;
1671     attribs->colormap = g_xcolmap;
1672     }
1673    
1674     static void
1675     get_input_mask(long *input_mask)
1676     {
1677     *input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1678     VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1679    
1680     if (g_sendmotion)
1681     *input_mask |= PointerMotionMask;
1682     if (g_ownbackstore)
1683     *input_mask |= ExposureMask;
1684     if (g_fullscreen || g_grab_keyboard)
1685     *input_mask |= EnterWindowMask;
1686     if (g_grab_keyboard)
1687     *input_mask |= LeaveWindowMask;
1688     }
1689    
1690 matthewc 121 BOOL
1691 matthewc 192 ui_create_window(void)
1692 matty 6 {
1693 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1694 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1695    
1696 matthewc 121 XSetWindowAttributes attribs;
1697 matty 28 XClassHint *classhints;
1698     XSizeHints *sizehints;
1699 matthewc 188 int wndwidth, wndheight;
1700 matthewc 432 long input_mask, ic_input_mask;
1701 jsorg71 100 XEvent xevent;
1702    
1703 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1704     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1705 matthewc 188
1706 stargo 867 /* Handle -x-y portion of geometry string */
1707     if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1708     g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1709     if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1710     g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1711    
1712 astrand 1199 get_window_attribs(&attribs);
1713 matthewc 188
1714 astrand 801 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1715     wndheight, 0, g_depth, InputOutput, g_visual,
1716     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1717     CWBorderPixel, &attribs);
1718 jsorg71 100
1719 stargo 576 if (g_gc == NULL)
1720 astrand 1199 {
1721 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1722 astrand 1199 ui_reset_clip();
1723     }
1724 stargo 565
1725 jsorg71 725 if (g_create_bitmap_gc == NULL)
1726     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1727    
1728 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
1729 stargo 565 {
1730 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1731 stargo 565
1732     /* clear to prevent rubbish being exposed at startup */
1733     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1734     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1735     }
1736    
1737 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
1738 jsorg71 100
1739 jsorg71 450 if (g_hide_decorations)
1740 astrand 1199 mwm_hide_decorations(g_wnd);
1741 astrand 262
1742 jsorg71 100 classhints = XAllocClassHint();
1743     if (classhints != NULL)
1744     {
1745     classhints->res_name = classhints->res_class = "rdesktop";
1746 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
1747 jsorg71 100 XFree(classhints);
1748     }
1749    
1750     sizehints = XAllocSizeHints();
1751     if (sizehints)
1752     {
1753     sizehints->flags = PMinSize | PMaxSize;
1754 stargo 867 if (g_pos)
1755     sizehints->flags |= PPosition;
1756 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
1757     sizehints->min_height = sizehints->max_height = g_height;
1758 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
1759 jsorg71 100 XFree(sizehints);
1760     }
1761    
1762 astrand 651 if (g_embed_wnd)
1763     {
1764     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1765     }
1766 stargo 636
1767 astrand 1199 get_input_mask(&input_mask);
1768 matthewc 121
1769 jsorg71 450 if (g_IM != NULL)
1770 matthewc 188 {
1771 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1772 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1773 matthewc 188
1774 jsorg71 450 if ((g_IC != NULL)
1775     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1776 matthewc 188 input_mask |= ic_input_mask;
1777     }
1778    
1779 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
1780     XMapWindow(g_display, g_wnd);
1781 jsorg71 100
1782 matthewc 208 /* wait for VisibilityNotify */
1783 astrand 196 do
1784     {
1785 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1786 astrand 196 }
1787 matthewc 208 while (xevent.type != VisibilityNotify);
1788 jsorg71 688 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1789 matthewc 123
1790 jsorg71 447 g_focused = False;
1791     g_mouse_in_wnd = False;
1792 jsorg71 257
1793 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
1794 jsorg71 450 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1795     g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1796     XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1797 astrand 275
1798 astrand 508 /* create invisible 1x1 cursor to be used as null cursor */
1799 stargo 576 if (g_null_cursor == NULL)
1800     g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1801 astrand 508
1802 matty 10 return True;
1803 matty 6 }
1804    
1805 matty 25 void
1806 n-ki 677 ui_resize_window()
1807     {
1808     XSizeHints *sizehints;
1809 jsorg71 708 Pixmap bs;
1810 n-ki 677
1811     sizehints = XAllocSizeHints();
1812     if (sizehints)
1813     {
1814     sizehints->flags = PMinSize | PMaxSize;
1815     sizehints->min_width = sizehints->max_width = g_width;
1816     sizehints->min_height = sizehints->max_height = g_height;
1817     XSetWMNormalHints(g_display, g_wnd, sizehints);
1818     XFree(sizehints);
1819     }
1820    
1821     if (!(g_fullscreen || g_embed_wnd))
1822     {
1823     XResizeWindow(g_display, g_wnd, g_width, g_height);
1824     }
1825 jsorg71 708
1826     /* create new backstore pixmap */
1827     if (g_backstore != 0)
1828     {
1829     bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1830     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1831     XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1832     XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1833     XFreePixmap(g_display, g_backstore);
1834     g_backstore = bs;
1835     }
1836 n-ki 677 }
1837    
1838     void
1839 matthewc 192 ui_destroy_window(void)
1840 matty 6 {
1841 jsorg71 450 if (g_IC != NULL)
1842     XDestroyIC(g_IC);
1843 matty 31
1844 jsorg71 450 XDestroyWindow(g_display, g_wnd);
1845 matty 6 }
1846    
1847 jsorg71 100 void
1848 matthewc 192 xwin_toggle_fullscreen(void)
1849 jsorg71 100 {
1850 matthewc 188 Pixmap contents = 0;
1851 matthewc 123
1852 astrand 1199 if (g_seamless_active)
1853     /* Turn off SeamlessRDP mode */
1854     ui_seamless_toggle();
1855    
1856 jsorg71 450 if (!g_ownbackstore)
1857 matthewc 188 {
1858     /* need to save contents of window */
1859 jsorg71 450 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1860     XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1861 matthewc 188 }
1862    
1863     ui_destroy_window();
1864 jsorg71 447 g_fullscreen = !g_fullscreen;
1865 matthewc 188 ui_create_window();
1866 matthewc 123
1867 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
1868 matthewc 188
1869 jsorg71 450 if (!g_ownbackstore)
1870 matthewc 188 {
1871 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1872     XFreePixmap(g_display, contents);
1873 matthewc 188 }
1874 jsorg71 100 }
1875    
1876 astrand 988 static void
1877     handle_button_event(XEvent xevent, BOOL down)
1878     {
1879     uint16 button, flags = 0;
1880     g_last_gesturetime = xevent.xbutton.time;
1881     button = xkeymap_translate_button(xevent.xbutton.button);
1882     if (button == 0)
1883     return;
1884    
1885     if (down)
1886     flags = MOUSE_FLAG_DOWN;
1887    
1888     /* Stop moving window when button is released, regardless of cursor position */
1889     if (g_moving_wnd && (xevent.type == ButtonRelease))
1890     g_moving_wnd = False;
1891    
1892     /* If win_button_size is nonzero, enable single app mode */
1893     if (xevent.xbutton.y < g_win_button_size)
1894     {
1895     /* Check from right to left: */
1896     if (xevent.xbutton.x >= g_width - g_win_button_size)
1897     {
1898     /* The close button, continue */
1899     ;
1900     }
1901     else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1902     {
1903     /* The maximize/restore button. Do not send to
1904     server. It might be a good idea to change the
1905     cursor or give some other visible indication
1906     that rdesktop inhibited this click */
1907     if (xevent.type == ButtonPress)
1908     return;
1909     }
1910     else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1911     {
1912     /* The minimize button. Iconify window. */
1913     if (xevent.type == ButtonRelease)
1914     {
1915     /* Release the mouse button outside the minimize button, to prevent the
1916     actual minimazation to happen */
1917     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1918     XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1919     return;
1920     }
1921     }
1922     else if (xevent.xbutton.x <= g_win_button_size)
1923     {
1924     /* The system menu. Ignore. */
1925     if (xevent.type == ButtonPress)
1926     return;
1927     }
1928     else
1929     {
1930     /* The title bar. */
1931     if (xevent.type == ButtonPress)
1932     {
1933 astrand 991 if (!g_fullscreen && g_hide_decorations && !g_using_full_workarea)
1934 astrand 988 {
1935     g_moving_wnd = True;
1936     g_move_x_offset = xevent.xbutton.x;
1937     g_move_y_offset = xevent.xbutton.y;
1938     }
1939     return;
1940     }
1941     }
1942     }
1943    
1944 astrand 1199 if (xevent.xmotion.window == g_wnd)
1945     {
1946     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1947     flags | button, xevent.xbutton.x, xevent.xbutton.y);
1948     }
1949     else
1950     {
1951     /* SeamlessRDP */
1952     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1953     flags | button, xevent.xbutton.x_root, xevent.xbutton.y_root);
1954     }
1955 astrand 988 }
1956    
1957 astrand 1199
1958 stargo 887 /* Process events in Xlib queue
1959 astrand 275 Returns 0 after user quit, 1 otherwise */
1960     static int
1961 matthewc 192 xwin_process_events(void)
1962 matty 9 {
1963 n-ki 54 XEvent xevent;
1964 matthewc 38 KeySym keysym;
1965 matty 10 uint32 ev_time;
1966 astrand 66 char str[256];
1967     Status status;
1968 stargo 887 int events = 0;
1969 astrand 1199 seamless_window *sw;
1970 matty 9
1971 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
1972 matty 9 {
1973 jsorg71 450 XNextEvent(g_display, &xevent);
1974 matthewc 123
1975 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1976 astrand 66 {
1977 astrand 84 DEBUG_KBD(("Filtering event\n"));
1978 astrand 66 continue;
1979     }
1980    
1981 n-ki 54 switch (xevent.type)
1982 matty 9 {
1983 jsorg71 688 case VisibilityNotify:
1984 astrand 1199 if (xevent.xvisibility.window == g_wnd)
1985     g_Unobscured =
1986     xevent.xvisibility.state == VisibilityUnobscured;
1987    
1988 jsorg71 688 break;
1989 astrand 275 case ClientMessage:
1990     /* the window manager told us to quit */
1991 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
1992     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1993 astrand 275 /* Quit */
1994     return 0;
1995     break;
1996    
1997 matty 9 case KeyPress:
1998 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1999     if (g_IC != NULL)
2000 astrand 66 /* Multi_key compatible version */
2001     {
2002 jsorg71 450 XmbLookupString(g_IC,
2003 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
2004     &status);
2005 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
2006 astrand 66 {
2007 astrand 82 error("XmbLookupString failed with status 0x%x\n",
2008     status);
2009 astrand 66 break;
2010     }
2011     }
2012     else
2013     {
2014     /* Plain old XLookupString */
2015 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
2016 astrand 66 XLookupString((XKeyEvent *) & xevent,
2017 astrand 82 str, sizeof(str), &keysym, NULL);
2018 astrand 66 }
2019    
2020 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
2021 astrand 261 get_ksname(keysym)));
2022 astrand 66
2023 matthewc 203 ev_time = time(NULL);
2024     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
2025 astrand 118 break;
2026    
2027 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2028 astrand 976 ev_time, True, 0);
2029 astrand 66 break;
2030 matthewc 203
2031 astrand 66 case KeyRelease:
2032 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
2033 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
2034     sizeof(str), &keysym, NULL);
2035 n-ki 52
2036 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
2037 matthewc 203 get_ksname(keysym)));
2038 n-ki 52
2039 matthewc 203 ev_time = time(NULL);
2040     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
2041 astrand 118 break;
2042    
2043 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
2044 astrand 976 ev_time, False, 0);
2045 matty 9 break;
2046    
2047     case ButtonPress:
2048 astrand 988 handle_button_event(xevent, True);
2049     break;
2050 matty 9
2051     case ButtonRelease:
2052 astrand 988 handle_button_event(xevent, False);
2053 matty 10 break;
2054    
2055     case MotionNotify:
2056 jsorg71 450 if (g_moving_wnd)
2057 astrand 342 {
2058 jsorg71 450 XMoveWindow(g_display, g_wnd,
2059     xevent.xmotion.x_root - g_move_x_offset,
2060     xevent.xmotion.y_root - g_move_y_offset);
2061 astrand 342 break;
2062     }
2063    
2064 jsorg71 447 if (g_fullscreen && !g_focused)
2065 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2066 jsorg71 288 CurrentTime);
2067 astrand 1199
2068     if (xevent.xmotion.window == g_wnd)
2069     {
2070     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2071     xevent.xmotion.x, xevent.xmotion.y);
2072     }
2073     else
2074     {
2075     /* SeamlessRDP */
2076     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE,
2077     xevent.xmotion.x_root,
2078     xevent.xmotion.y_root);
2079     }
2080 matty 28 break;
2081    
2082 matthewc 194 case FocusIn:
2083 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
2084     break;
2085 jsorg71 447 g_focused = True;
2086 astrand 543 reset_modifier_keys();
2087 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
2088     XGrabKeyboard(g_display, g_wnd, True,
2089 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
2090 astrand 1199
2091     sw = sw_get_window_by_wnd(xevent.xfocus.window);
2092     if (!sw)
2093     break;
2094    
2095     if (sw->id != g_seamless_focused)
2096     {
2097     seamless_send_focus(sw->id, 0);
2098     g_seamless_focused = sw->id;
2099     }
2100 matty 28 break;
2101    
2102 matthewc 194 case FocusOut:
2103 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
2104     break;
2105 jsorg71 447 g_focused = False;
2106 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
2107 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2108 matty 28 break;
2109 matty 31
2110 matthewc 250 case EnterNotify:
2111     /* we only register for this event when in fullscreen mode */
2112 jsorg71 257 /* or grab_keyboard */
2113 jsorg71 447 g_mouse_in_wnd = True;
2114     if (g_fullscreen)
2115 jsorg71 257 {
2116 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
2117 astrand 261 CurrentTime);
2118 jsorg71 257 break;
2119     }
2120 jsorg71 447 if (g_focused)
2121 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
2122 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
2123 matthewc 250 break;
2124    
2125 matthewc 253 case LeaveNotify:
2126 jsorg71 257 /* we only register for this event when grab_keyboard */
2127 jsorg71 447 g_mouse_in_wnd = False;
2128 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
2129 matthewc 253 break;
2130    
2131 matty 31 case Expose:
2132 astrand 1199 if (xevent.xexpose.window == g_wnd)
2133     {
2134     XCopyArea(g_display, g_backstore, xevent.xexpose.window,
2135     g_gc,
2136     xevent.xexpose.x, xevent.xexpose.y,
2137     xevent.xexpose.width, xevent.xexpose.height,
2138     xevent.xexpose.x, xevent.xexpose.y);
2139     }
2140     else
2141     {
2142     sw = sw_get_window_by_wnd(xevent.xexpose.window);
2143     if (!sw)
2144     break;
2145     XCopyArea(g_display, g_backstore,
2146     xevent.xexpose.window, g_gc,
2147     xevent.xexpose.x + sw->xoffset,
2148     xevent.xexpose.y + sw->yoffset,
2149     xevent.xexpose.width,
2150     xevent.xexpose.height, xevent.xexpose.x,
2151     xevent.xexpose.y);
2152     }
2153    
2154 matty 31 break;
2155 astrand 119
2156     case MappingNotify:
2157     /* Refresh keyboard mapping if it has changed. This is important for
2158     Xvnc, since it allocates keycodes dynamically */
2159     if (xevent.xmapping.request == MappingKeyboard
2160     || xevent.xmapping.request == MappingModifier)
2161     XRefreshKeyboardMapping(&xevent.xmapping);
2162 matthewc 203
2163     if (xevent.xmapping.request == MappingModifier)
2164     {
2165 jsorg71 450 XFreeModifiermap(g_mod_map);
2166     g_mod_map = XGetModifierMapping(g_display);
2167 matthewc 203 }
2168 astrand 119 break;
2169 matthewc 432
2170 astrand 435 /* clipboard stuff */
2171 forsberg 415 case SelectionNotify:
2172 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
2173 forsberg 415 break;
2174     case SelectionRequest:
2175 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
2176 forsberg 415 break;
2177 matthewc 432 case SelectionClear:
2178     xclip_handle_SelectionClear();
2179     break;
2180 forsberg 415 case PropertyNotify:
2181 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
2182 astrand 1199 if (xevent.xproperty.window == g_wnd)
2183     break;
2184     if (xevent.xproperty.window == DefaultRootWindow(g_display))
2185     break;
2186    
2187     /* seamless */
2188     sw = sw_get_window_by_wnd(xevent.xproperty.window);
2189     if (!sw)
2190     break;
2191    
2192     if ((xevent.xproperty.atom == g_net_wm_state_atom)
2193     && (xevent.xproperty.state == PropertyNewValue))
2194     {
2195     sw->state = ewmh_get_window_state(sw->wnd);
2196     seamless_send_state(sw->id, sw->state, 0);
2197     }
2198    
2199     if ((xevent.xproperty.atom == g_net_wm_desktop_atom)
2200     && (xevent.xproperty.state == PropertyNewValue))
2201     {
2202     sw->desktop = ewmh_get_window_desktop(sw->wnd);
2203     sw_all_to_desktop(sw->wnd, sw->desktop);
2204     }
2205    
2206 forsberg 415 break;
2207 jdmeijer 905 case MapNotify:
2208 astrand 1199 if (!g_seamless_active)
2209     rdp_send_client_window_status(1);
2210 jdmeijer 905 break;
2211     case UnmapNotify:
2212 astrand 1199 if (!g_seamless_active)
2213     rdp_send_client_window_status(0);
2214 jdmeijer 905 break;
2215 astrand 1199 case ConfigureNotify:
2216     if (!g_seamless_active)
2217     break;
2218    
2219     sw = sw_get_window_by_wnd(xevent.xconfigure.window);
2220     if (!sw)
2221     break;
2222    
2223     gettimeofday(sw->position_timer, NULL);
2224     if (sw->position_timer->tv_usec + SEAMLESSRDP_POSITION_TIMER >=
2225     1000000)
2226     {
2227     sw->position_timer->tv_usec +=
2228     SEAMLESSRDP_POSITION_TIMER - 1000000;
2229     sw->position_timer->tv_sec += 1;
2230     }
2231     else
2232     {
2233     sw->position_timer->tv_usec += SEAMLESSRDP_POSITION_TIMER;
2234     }
2235    
2236     sw_handle_restack(sw);
2237     break;
2238 matty 9 }
2239     }
2240 astrand 275 /* Keep going */
2241     return 1;
2242 matty 9 }
2243    
2244 astrand 275 /* Returns 0 after user quit, 1 otherwise */
2245     int
2246 matty 33 ui_select(int rdp_socket)
2247     {
2248 stargo 606 int n;
2249 matthewc 474 fd_set rfds, wfds;
2250 n-ki 592 struct timeval tv;
2251     BOOL s_timeout = False;
2252 matty 33
2253     while (True)
2254     {
2255 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
2256 matthewc 121 /* Process any events already waiting */
2257 astrand 275 if (!xwin_process_events())
2258     /* User quit */
2259     return 0;
2260 astrand 119
2261 astrand 1199 if (g_seamless_active)
2262     sw_check_timers();
2263    
2264 matty 33 FD_ZERO(&rfds);
2265 matthewc 474 FD_ZERO(&wfds);
2266 matty 33 FD_SET(rdp_socket, &rfds);
2267 jsorg71 450 FD_SET(g_x_socket, &rfds);
2268 matty 33
2269 matthewc 474 #ifdef WITH_RDPSND
2270     /* FIXME: there should be an API for registering fds */
2271 stargo 504 if (g_dsp_busy)
2272 matty 33 {
2273 matthewc 474 FD_SET(g_dsp_fd, &wfds);
2274 n-ki 592 n = (g_dsp_fd > n) ? g_dsp_fd : n;
2275 astrand 499 }
2276 matthewc 474 #endif
2277 n-ki 592 /* default timeout */
2278     tv.tv_sec = 60;
2279     tv.tv_usec = 0;
2280 matthewc 474
2281 n-ki 592 /* add redirection handles */
2282     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
2283 astrand 1199 seamless_select_timeout(&tv);
2284 n-ki 592
2285     n++;
2286    
2287     switch (select(n, &rfds, &wfds, NULL, &tv))
2288 matthewc 474 {
2289 matty 33 case -1:
2290     error("select: %s\n", strerror(errno));
2291    
2292     case 0:
2293 stargo 795 /* Abort serial read calls */
2294     if (s_timeout)
2295     rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
2296 matty 33 continue;
2297     }
2298    
2299 n-ki 592 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
2300    
2301 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
2302     return 1;
2303    
2304 matthewc 474 #ifdef WITH_RDPSND
2305 stargo 504 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
2306 matthewc 474 wave_out_play();
2307     #endif
2308 matty 33 }
2309     }
2310    
2311     void
2312 matty 25 ui_move_pointer(int x, int y)
2313 matty 9 {
2314 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
2315 matty 9 }
2316    
2317 matty 25 HBITMAP
2318 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
2319 matty 6 {
2320     XImage *image;
2321 matty 9 Pixmap bitmap;
2322 matty 28 uint8 *tdata;
2323 stargo 521 int bitmap_pad;
2324 matty 29
2325 astrand 1042 if (g_server_depth == 8)
2326 stargo 521 {
2327     bitmap_pad = 8;
2328     }
2329     else
2330     {
2331     bitmap_pad = g_bpp;
2332    
2333     if (g_bpp == 24)
2334     bitmap_pad = 32;
2335     }
2336    
2337 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2338     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
2339     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2340 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2341 matty 6
2342 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
2343 matty 9
2344     XFree(image);
2345 jsorg71 644 if (tdata != data)
2346 n-ki 279 xfree(tdata);
2347 matty 24 return (HBITMAP) bitmap;
2348 matty 6 }
2349    
2350 matty 25 void
2351 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
2352 matty 6 {
2353 matty 10 XImage *image;
2354 matty 29 uint8 *tdata;
2355 stargo 521 int bitmap_pad;
2356    
2357 astrand 1042 if (g_server_depth == 8)
2358 stargo 521 {
2359     bitmap_pad = 8;
2360     }
2361     else
2362     {
2363     bitmap_pad = g_bpp;
2364    
2365     if (g_bpp == 24)
2366     bitmap_pad = 32;
2367     }
2368    
2369 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
2370     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2371 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
2372 matty 28
2373 jsorg71 450 if (g_ownbackstore)
2374 matty 31 {
2375 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2376     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2377 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2378     (g_display, g_backstore, sw->wnd, g_gc, x, y, cx, cy,
2379     x - sw->xoffset, y - sw->yoffset));
2380 matty 31 }
2381     else
2382     {
2383 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2384 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2385     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
2386     x - sw->xoffset, y - sw->yoffset));
2387 matty 31 }
2388 matty 29
2389 matty 24 XFree(image);
2390 jsorg71 644 if (tdata != data)
2391 n-ki 279 xfree(tdata);
2392 matty 6 }
2393    
2394 matty 25 void
2395     ui_destroy_bitmap(HBITMAP bmp)
2396 matty 6 {
2397 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
2398 matty 10 }
2399    
2400 matty 25 HGLYPH
2401 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
2402 matty 10 {
2403 matty 9 XImage *image;
2404     Pixmap bitmap;
2405     int scanline;
2406 matty 6
2407 matty 9 scanline = (width + 7) / 8;
2408 matty 6
2409 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
2410 jsorg71 725 if (g_create_glyph_gc == 0)
2411     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
2412 matty 9
2413 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
2414 astrand 73 width, height, 8, scanline);
2415 matty 23 image->byte_order = MSBFirst;
2416     image->bitmap_bit_order = MSBFirst;
2417     XInitImage(image);
2418    
2419 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
2420 matty 29
2421 matty 9 XFree(image);
2422 astrand 64 return (HGLYPH) bitmap;
2423 matty 6 }
2424 matty 7
2425 matty 25 void
2426     ui_destroy_glyph(HGLYPH glyph)
2427 matty 7 {
2428 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
2429 matty 9 }
2430    
2431 matty 29 HCURSOR
2432 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
2433     uint8 * andmask, uint8 * xormask)
2434 matty 9 {
2435 matty 29 HGLYPH maskglyph, cursorglyph;
2436     XColor bg, fg;
2437     Cursor xcursor;
2438     uint8 *cursor, *pcursor;
2439     uint8 *mask, *pmask;
2440     uint8 nextbit;
2441     int scanline, offset;
2442     int i, j;
2443    
2444     scanline = (width + 7) / 8;
2445     offset = scanline * height;
2446    
2447 forsberg 415 cursor = (uint8 *) xmalloc(offset);
2448 matty 29 memset(cursor, 0, offset);
2449    
2450 forsberg 415 mask = (uint8 *) xmalloc(offset);
2451 matty 29 memset(mask, 0, offset);
2452    
2453     /* approximate AND and XOR masks with a monochrome X pointer */
2454     for (i = 0; i < height; i++)
2455 matty 7 {
2456 matty 29 offset -= scanline;
2457     pcursor = &cursor[offset];
2458     pmask = &mask[offset];
2459    
2460     for (j = 0; j < scanline; j++)
2461 matty 28 {
2462 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
2463     {
2464     if (xormask[0] || xormask[1] || xormask[2])
2465     {
2466     *pcursor |= (~(*andmask) & nextbit);
2467     *pmask |= nextbit;
2468     }
2469     else
2470     {
2471     *pcursor |= ((*andmask) & nextbit);
2472     *pmask |= (~(*andmask) & nextbit);
2473     }
2474    
2475     xormask += 3;
2476     }
2477    
2478     andmask++;
2479     pcursor++;
2480     pmask++;
2481 matty 28 }
2482 matty 7 }
2483 matty 29
2484     fg.red = fg.blue = fg.green = 0xffff;
2485     bg.red = bg.blue = bg.green = 0x0000;
2486     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
2487    
2488     cursorglyph = ui_create_glyph(width, height, cursor);
2489     maskglyph = ui_create_glyph(width, height, mask);
2490    
2491 astrand 66 xcursor =
2492 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
2493 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
2494 astrand 64
2495 matty 29 ui_destroy_glyph(maskglyph);
2496     ui_destroy_glyph(cursorglyph);
2497     xfree(mask);
2498     xfree(cursor);
2499 astrand 64 return (HCURSOR) xcursor;
2500 matty 29 }
2501    
2502     void
2503     ui_set_cursor(HCURSOR cursor)
2504     {
2505 jsorg71 450 g_current_cursor = (Cursor) cursor;
2506     XDefineCursor(g_display, g_wnd, g_current_cursor);
2507 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDefineCursor, (g_display, sw->wnd, g_current_cursor));
2508 matty 29 }
2509    
2510     void
2511     ui_destroy_cursor(HCURSOR cursor)
2512     {
2513 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
2514 matty 29 }
2515    
2516 astrand 508 void
2517     ui_set_null_cursor(void)
2518     {
2519     ui_set_cursor(g_null_cursor);
2520     }
2521    
2522 matty 29 #define MAKE_XCOLOR(xc,c) \
2523     (xc)->red = ((c)->red << 8) | (c)->red; \
2524     (xc)->green = ((c)->green << 8) | (c)->green; \
2525     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
2526     (xc)->flags = DoRed | DoGreen | DoBlue;
2527    
2528 n-ki 279
2529 matty 29 HCOLOURMAP
2530 astrand 64 ui_create_colourmap(COLOURMAP * colours)
2531 matty 29 {
2532     COLOURENTRY *entry;
2533     int i, ncolours = colours->ncolours;
2534 jsorg71 450 if (!g_owncolmap)
2535 matty 28 {
2536 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
2537 n-ki 279 XColor xentry;
2538     XColor xc_cache[256];
2539     uint32 colour;
2540     int colLookup = 256;
2541     for (i = 0; i < ncolours; i++)
2542 matty 28 {
2543 n-ki 279 entry = &colours->colours[i];
2544     MAKE_XCOLOR(&xentry, entry);
2545 matty 7
2546 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
2547 astrand 196 {
2548 n-ki 279 /* Allocation failed, find closest match. */
2549     int j = 256;
2550     int nMinDist = 3 * 256 * 256;
2551     long nDist = nMinDist;
2552 matty 28
2553 n-ki 279 /* only get the colors once */
2554     while (colLookup--)
2555 astrand 196 {
2556 n-ki 279 xc_cache[colLookup].pixel = colLookup;
2557     xc_cache[colLookup].red = xc_cache[colLookup].green =
2558     xc_cache[colLookup].blue = 0;
2559     xc_cache[colLookup].flags = 0;
2560 jsorg71 450 XQueryColor(g_display,
2561     DefaultColormap(g_display,
2562     DefaultScreen(g_display)),
2563 n-ki 279 &xc_cache[colLookup]);
2564 n-ki 185 }
2565 n-ki 279 colLookup = 0;
2566    
2567     /* approximate the pixel */
2568     while (j--)
2569 astrand 196 {
2570 n-ki 279 if (xc_cache[j].flags)
2571     {
2572     nDist = ((long) (xc_cache[j].red >> 8) -
2573     (long) (xentry.red >> 8)) *
2574     ((long) (xc_cache[j].red >> 8) -
2575     (long) (xentry.red >> 8)) +
2576     ((long) (xc_cache[j].green >> 8) -
2577     (long) (xentry.green >> 8)) *
2578     ((long) (xc_cache[j].green >> 8) -
2579     (long) (xentry.green >> 8)) +
2580     ((long) (xc_cache[j].blue >> 8) -
2581     (long) (xentry.blue >> 8)) *
2582     ((long) (xc_cache[j].blue >> 8) -
2583     (long) (xentry.blue >> 8));
2584     }
2585     if (nDist < nMinDist)
2586     {
2587     nMinDist = nDist;
2588     xentry.pixel = j;
2589     }
2590 n-ki 185 }
2591     }
2592 n-ki 279 colour = xentry.pixel;
2593    
2594     /* update our cache */
2595     if (xentry.pixel < 256)
2596     {
2597     xc_cache[xentry.pixel].red = xentry.red;
2598     xc_cache[xentry.pixel].green = xentry.green;
2599     xc_cache[xentry.pixel].blue = xentry.blue;
2600    
2601     }
2602    
2603 matthewc 527 map[i] = colour;
2604 n-ki 185 }
2605 n-ki 279 return map;
2606     }
2607     else
2608     {
2609     XColor *xcolours, *xentry;
2610     Colormap map;
2611 matty 29
2612 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
2613 n-ki 279 for (i = 0; i < ncolours; i++)
2614 astrand 196 {
2615 n-ki 279 entry = &colours->colours[i];
2616     xentry = &xcolours[i];
2617     xentry->pixel = i;
2618     MAKE_XCOLOR(xentry, entry);
2619 matty 29 }
2620    
2621 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
2622     XStoreColors(g_display, map, xcolours, ncolours);
2623 n-ki 185
2624 n-ki 279 xfree(xcolours);
2625     return (HCOLOURMAP) map;
2626 matty 29 }
2627 matty 7 }
2628    
2629 matty 25 void
2630     ui_destroy_colourmap(HCOLOURMAP map)
2631 matty 7 {
2632 jsorg71 450 if (!g_owncolmap)
2633 n-ki 279 xfree(map);
2634     else
2635 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
2636 matty 7 }
2637    
2638 matty 25 void
2639     ui_set_colourmap(HCOLOURMAP map)
2640 matty 7 {
2641 jsorg71 450 if (!g_owncolmap)
2642 astrand 448 {
2643 jsorg71 450 if (g_colmap)
2644     xfree(g_colmap);
2645 astrand 448
2646 jsorg71 450 g_colmap = (uint32 *) map;
2647 astrand 448 }
2648 n-ki 279 else
2649 astrand 1199 {
2650 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2651 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XSetWindowColormap, (g_display, sw->wnd, (Colormap) map));
2652     }
2653 matty 7 }
2654    
2655 matty 25 void
2656     ui_set_clip(int x, int y, int cx, int cy)
2657 matty 7 {
2658 astrand 1199 g_clip_rectangle.x = x;
2659     g_clip_rectangle.y = y;
2660     g_clip_rectangle.width = cx;
2661     g_clip_rectangle.height = cy;
2662     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2663 matty 9 }
2664 matty 7
2665 matty 25 void
2666 matthewc 192 ui_reset_clip(void)
2667 matty 9 {
2668 astrand 1199 g_clip_rectangle.x = 0;
2669     g_clip_rectangle.y = 0;
2670     g_clip_rectangle.width = g_width;
2671     g_clip_rectangle.height = g_height;
2672     XSetClipRectangles(g_display, g_gc, 0, 0, &g_clip_rectangle, 1, YXBanded);
2673 matty 7 }
2674    
2675 matty 25 void
2676 matthewc 192 ui_bell(void)
2677 matty 10 {
2678 jsorg71 450 XBell(g_display, 0);
2679 matty 10 }
2680    
2681 matty 25 void
2682     ui_destblt(uint8 opcode,
2683     /* dest */ int x, int y, int cx, int cy)
2684 matty 9 {
2685 matty 29 SET_FUNCTION(opcode);
2686 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2687 matty 29 RESET_FUNCTION(opcode);
2688 matty 9 }
2689    
2690 jsorg71 373 static uint8 hatch_patterns[] = {
2691 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2692     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2693     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2694     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2695     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2696     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2697 jsorg71 373 };
2698    
2699 matty 25 void
2700     ui_patblt(uint8 opcode,
2701     /* dest */ int x, int y, int cx, int cy,
2702 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2703 matty 9 {
2704     Pixmap fill;
2705 jsorg71 59 uint8 i, ipattern[8];
2706 matty 9
2707 matty 29 SET_FUNCTION(opcode);
2708 matty 9
2709     switch (brush->style)
2710     {
2711 matty 24 case 0: /* Solid */
2712 matty 29 SET_FOREGROUND(fgcolour);
2713 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2714 matty 9 break;
2715    
2716 jsorg71 373 case 2: /* Hatch */
2717 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2718     hatch_patterns + brush->pattern[0] * 8);
2719 astrand 487 SET_FOREGROUND(fgcolour);
2720     SET_BACKGROUND(bgcolour);
2721 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2722     XSetStipple(g_display, g_gc, fill);
2723     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2724 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2725 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2726     XSetTSOrigin(g_display, g_gc, 0, 0);
2727 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
2728     break;
2729    
2730 matty 24 case 3: /* Pattern */
2731 jsorg71 59 for (i = 0; i != 8; i++)
2732     ipattern[7 - i] = brush->pattern[i];
2733     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2734 matty 29 SET_FOREGROUND(bgcolour);
2735     SET_BACKGROUND(fgcolour);
2736 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2737     XSetStipple(g_display, g_gc, fill);
2738     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2739 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2740 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2741     XSetTSOrigin(g_display, g_gc, 0, 0);
2742 astrand 64 ui_destroy_glyph((HGLYPH) fill);
2743 matty 9 break;
2744    
2745     default:
2746 matty 30 unimpl("brush %d\n", brush->style);
2747 matty 9 }
2748 matty 29
2749     RESET_FUNCTION(opcode);
2750 jsorg71 680
2751     if (g_ownbackstore)
2752     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2753 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2754     (g_display, g_ownbackstore ? g_backstore : g_wnd, sw->wnd, g_gc,
2755     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2756 matty 9 }
2757    
2758 matty 25 void
2759     ui_screenblt(uint8 opcode,
2760     /* dest */ int x, int y, int cx, int cy,
2761     /* src */ int srcx, int srcy)
2762 matty 9 {
2763 matty 29 SET_FUNCTION(opcode);
2764 jsorg71 450 if (g_ownbackstore)
2765 stargo 609 {
2766 astrand 1199 XCopyArea(g_display, g_Unobscured ? g_wnd : g_backstore,
2767     g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2768     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2769 stargo 609 }
2770     else
2771     {
2772     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2773     }
2774 astrand 1199
2775     ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2776     (g_display, g_ownbackstore ? g_backstore : g_wnd,
2777     sw->wnd, g_gc, x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
2778    
2779 matty 29 RESET_FUNCTION(opcode);
2780 matty 9 }
2781    
2782 matty 25 void
2783     ui_memblt(uint8 opcode,
2784     /* dest */ int x, int y, int cx, int cy,
2785     /* src */ HBITMAP src, int srcx, int srcy)
2786 matty 9 {
2787 matty 29 SET_FUNCTION(opcode);
2788 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2789 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
2790     (g_display, (Pixmap) src, sw->wnd, g_gc,
2791     srcx, srcy, cx, cy, x - sw->xoffset, y - sw->yoffset));
2792 jsorg71 450 if (g_ownbackstore)
2793     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2794 matty 29 RESET_FUNCTION(opcode);
2795 matty 9 }
2796    
2797 matty 25 void
2798     ui_triblt(uint8 opcode,
2799     /* dest */ int x, int y, int cx, int cy,
2800     /* src */ HBITMAP src, int srcx, int srcy,
2801 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2802 matty 9 {
2803     /* This is potentially difficult to do in general. Until someone
2804 matty 10 comes up with a more efficient way of doing it I am using cases. */
2805 matty 9
2806     switch (opcode)
2807     {
2808 matty 24 case 0x69: /* PDSxxn */
2809 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2810 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2811 matty 16 break;
2812    
2813 matty 24 case 0xb8: /* PSDPxax */
2814 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2815 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2816 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2817 matty 9 break;
2818    
2819 matty 29 case 0xc0: /* PSa */
2820 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2821 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2822 matty 28 break;
2823    
2824 matty 9 default:
2825 matty 30 unimpl("triblt 0x%x\n", opcode);
2826 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2827 matty 9 }
2828     }
2829    
2830 matty 25 void
2831     ui_line(uint8 opcode,
2832     /* dest */ int startx, int starty, int endx, int endy,
2833 astrand 64 /* pen */ PEN * pen)
2834 matty 9 {
2835 matty 29 SET_FUNCTION(opcode);
2836     SET_FOREGROUND(pen->colour);
2837 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2838 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XDrawLine, (g_display, sw->wnd, g_gc,
2839     startx - sw->xoffset, starty - sw->yoffset,
2840     endx - sw->xoffset, endy - sw->yoffset));
2841 jsorg71 450 if (g_ownbackstore)
2842     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2843 matty 29 RESET_FUNCTION(opcode);
2844 matty 9 }
2845    
2846 matty 25 void
2847     ui_rect(
2848     /* dest */ int x, int y, int cx, int cy,
2849     /* brush */ int colour)
2850 matty 9 {
2851 matty 29 SET_FOREGROUND(colour);
2852 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2853 matty 9 }
2854    
2855 jdmeijer 831 void
2856     ui_polygon(uint8 opcode,
2857     /* mode */ uint8 fillmode,
2858     /* dest */ POINT * point, int npoints,
2859     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2860     {
2861     uint8 style, i, ipattern[8];
2862     Pixmap fill;
2863    
2864     SET_FUNCTION(opcode);
2865    
2866     switch (fillmode)
2867     {
2868     case ALTERNATE:
2869     XSetFillRule(g_display, g_gc, EvenOddRule);
2870     break;
2871     case WINDING:
2872     XSetFillRule(g_display, g_gc, WindingRule);
2873     break;
2874     default:
2875     unimpl("fill mode %d\n", fillmode);
2876     }
2877    
2878     if (brush)
2879     style = brush->style;
2880     else
2881     style = 0;
2882    
2883     switch (style)
2884     {
2885     case 0: /* Solid */
2886     SET_FOREGROUND(fgcolour);
2887     FILL_POLYGON((XPoint *) point, npoints);
2888     break;
2889    
2890     case 2: /* Hatch */
2891     fill = (Pixmap) ui_create_glyph(8, 8,
2892     hatch_patterns + brush->pattern[0] * 8);
2893     SET_FOREGROUND(fgcolour);
2894     SET_BACKGROUND(bgcolour);
2895     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2896     XSetStipple(g_display, g_gc, fill);
2897     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2898     FILL_POLYGON((XPoint *) point, npoints);
2899     XSetFillStyle(g_display, g_gc, FillSolid);
2900     XSetTSOrigin(g_display, g_gc, 0, 0);
2901     ui_destroy_glyph((HGLYPH) fill);
2902     break;
2903    
2904     case 3: /* Pattern */
2905     for (i = 0; i != 8; i++)
2906     ipattern[7 - i] = brush->pattern[i];
2907     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2908     SET_FOREGROUND(bgcolour);
2909     SET_BACKGROUND(fgcolour);
2910     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2911     XSetStipple(g_display, g_gc, fill);
2912     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2913     FILL_POLYGON((XPoint *) point, npoints);
2914     XSetFillStyle(g_display, g_gc, FillSolid);
2915     XSetTSOrigin(g_display, g_gc, 0, 0);
2916     ui_destroy_glyph((HGLYPH) fill);
2917     break;
2918    
2919     default:
2920     unimpl("brush %d\n", brush->style);
2921     }
2922    
2923     RESET_FUNCTION(opcode);
2924     }
2925    
2926     void
2927 jdmeijer 844 ui_polyline(uint8 opcode,
2928     /* dest */ POINT * points, int npoints,
2929     /* pen */ PEN * pen)
2930     {
2931     /* TODO: set join style */
2932     SET_FUNCTION(opcode);
2933     SET_FOREGROUND(pen->colour);
2934     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2935     if (g_ownbackstore)
2936     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2937     CoordModePrevious);
2938 astrand 1199
2939     ON_ALL_SEAMLESS_WINDOWS(seamless_XDrawLines,
2940     (sw->wnd, (XPoint *) points, npoints, sw->xoffset, sw->yoffset));
2941    
2942 jdmeijer 844 RESET_FUNCTION(opcode);
2943     }
2944    
2945     void
2946 jdmeijer 831 ui_ellipse(uint8 opcode,
2947     /* mode */ uint8 fillmode,
2948     /* dest */ int x, int y, int cx, int cy,
2949     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2950     {
2951     uint8 style, i, ipattern[8];
2952     Pixmap fill;
2953    
2954     SET_FUNCTION(opcode);
2955    
2956     if (brush)
2957     style = brush->style;
2958     else
2959     style = 0;
2960    
2961     switch (style)
2962     {
2963     case 0: /* Solid */
2964     SET_FOREGROUND(fgcolour);
2965     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2966     break;
2967    
2968     case 2: /* Hatch */
2969     fill = (Pixmap) ui_create_glyph(8, 8,
2970     hatch_patterns + brush->pattern[0] * 8);
2971     SET_FOREGROUND(fgcolour);
2972     SET_BACKGROUND(bgcolour);
2973     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2974     XSetStipple(g_display, g_gc, fill);
2975     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2976     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2977     XSetFillStyle(g_display, g_gc, FillSolid);
2978     XSetTSOrigin(g_display, g_gc, 0, 0);
2979     ui_destroy_glyph((HGLYPH) fill);
2980     break;
2981    
2982     case 3: /* Pattern */
2983     for (i = 0; i != 8; i++)
2984     ipattern[7 - i] = brush->pattern[i];
2985     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2986     SET_FOREGROUND(bgcolour);
2987     SET_BACKGROUND(fgcolour);
2988     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2989     XSetStipple(g_display, g_gc, fill);
2990     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2991     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2992     XSetFillStyle(g_display, g_gc, FillSolid);
2993     XSetTSOrigin(g_display, g_gc, 0, 0);
2994     ui_destroy_glyph((HGLYPH) fill);
2995     break;
2996    
2997     default:
2998     unimpl("brush %d\n", brush->style);
2999     }
3000    
3001     RESET_FUNCTION(opcode);
3002     }
3003    
3004 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
3005 matty 25 void
3006     ui_draw_glyph(int mixmode,
3007     /* dest */ int x, int y, int cx, int cy,
3008 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
3009     int bgcolour, int fgcolour)
3010 matty 9 {
3011 matty 29 SET_FOREGROUND(fgcolour);
3012     SET_BACKGROUND(bgcolour);
3013 matty 9
3014 jsorg71 450 XSetFillStyle(g_display, g_gc,
3015 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
3016 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
3017     XSetTSOrigin(g_display, g_gc, x, y);
3018 matty 9
3019 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
3020 matty 9
3021 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
3022 matty 9 }
3023    
3024 mmihalik 49 #define DO_GLYPH(ttext,idx) \
3025     {\
3026     glyph = cache_get_font (font, ttext[idx]);\
3027     if (!(flags & TEXT2_IMPLICIT_X))\
3028 jsorg71 564 {\
3029     xyoffset = ttext[++idx];\
3030     if ((xyoffset & 0x80))\
3031 mmihalik 49 {\
3032 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3033     y += ttext[idx+1] | (ttext[idx+2] << 8);\
3034 mmihalik 49 else\
3035 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
3036     idx += 2;\
3037 mmihalik 49 }\
3038 jsorg71 564 else\
3039 mmihalik 49 {\
3040 jsorg71 564 if (flags & TEXT2_VERTICAL)\
3041     y += xyoffset;\
3042     else\
3043     x += xyoffset;\
3044 mmihalik 49 }\
3045 jsorg71 564 }\
3046     if (glyph != NULL)\
3047     {\
3048     x1 = x + glyph->offset;\
3049     y1 = y + glyph->baseline;\
3050     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
3051     XSetTSOrigin(g_display, g_gc, x1, y1);\
3052     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
3053     if (flags & TEXT2_IMPLICIT_X)\
3054     x += glyph->width;\
3055     }\
3056 mmihalik 49 }
3057    
3058 matty 25 void
3059 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
3060 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
3061 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
3062     int bgcolour, int fgcolour, uint8 * text, uint8 length)
3063 matty 9 {
3064 jdmeijer 843 /* TODO: use brush appropriately */
3065    
3066 matty 10 FONTGLYPH *glyph;
3067 jsorg71 564 int i, j, xyoffset, x1, y1;
3068 mmihalik 49 DATABLOB *entry;
3069 matty 9
3070 matty 29 SET_FOREGROUND(bgcolour);
3071 matty 28
3072 astrand 620 /* Sometimes, the boxcx value is something really large, like
3073     32691. This makes XCopyArea fail with Xvnc. The code below
3074     is a quick fix. */
3075     if (boxx + boxcx > g_width)
3076     boxcx = g_width - boxx;
3077    
3078 matty 9 if (boxcx > 1)
3079 matty 31 {
3080 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
3081 matty 31 }
3082 matty 17 else if (mixmode == MIX_OPAQUE)
3083 matty 31 {
3084 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
3085 matty 31 }
3086 matty 9
3087 jsorg71 564 SET_FOREGROUND(fgcolour);
3088     SET_BACKGROUND(bgcolour);
3089     XSetFillStyle(g_display, g_gc, FillStippled);
3090    
3091 matty 9 /* Paint text, character by character */
3092 astrand 64 for (i = 0; i < length;)
3093     {
3094     switch (text[i])
3095     {
3096     case 0xff:
3097 astrand 1031 /* At least two bytes needs to follow */
3098 astrand 1029 if (i + 3 > length)
3099 astrand 64 {
3100 astrand 1031 warning("Skipping short 0xff command:");
3101     for (j = 0; j < length; j++)
3102     fprintf(stderr, "%02x ", text[j]);
3103     fprintf(stderr, "\n");
3104 astrand 1029 i = length = 0;
3105     break;
3106 astrand 64 }
3107 astrand 1029 cache_put_text(text[i + 1], text, text[i + 2]);
3108     i += 3;
3109     length -= i;
3110 astrand 64 /* this will move pointer from start to first character after FF command */
3111 astrand 1029 text = &(text[i]);
3112 astrand 64 i = 0;
3113 mmihalik 49 break;
3114 matty 9
3115 astrand 64 case 0xfe:
3116 astrand 1031 /* At least one byte needs to follow */
3117     if (i + 2 > length)
3118 astrand 1029 {
3119 astrand 1031 warning("Skipping short 0xfe command:");
3120     for (j = 0; j < length; j++)
3121     fprintf(stderr, "%02x ", text[j]);
3122     fprintf(stderr, "\n");
3123 astrand 1029 i = length = 0;
3124     break;
3125     }
3126 astrand 64 entry = cache_get_text(text[i + 1]);
3127 astrand 1030 if (entry->data != NULL)
3128 astrand 64 {
3129 astrand 1031 if ((((uint8 *) (entry->data))[1] == 0)
3130     && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
3131 astrand 64 {
3132     if (flags & TEXT2_VERTICAL)
3133     y += text[i + 2];
3134     else
3135     x += text[i + 2];
3136     }
3137     for (j = 0; j < entry->size; j++)
3138 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
3139 matthewc 44 }
3140 astrand 1031 if (i + 2 < length)
3141     i += 3;
3142     else
3143     i += 2;
3144 jsorg71 286 length -= i;
3145     /* this will move pointer from start to first character after FE command */
3146     text = &(text[i]);
3147     i = 0;
3148 astrand 64 break;
3149 matty 17
3150 astrand 64 default:
3151     DO_GLYPH(text, i);
3152     i++;
3153     break;
3154 matty 29 }
3155 mmihalik 49 }
3156 jsorg71 564
3157     XSetFillStyle(g_display, g_gc, FillSolid);
3158    
3159 jsorg71 450 if (g_ownbackstore)
3160 jsorg71 278 {
3161     if (boxcx > 1)
3162 astrand 1199 {
3163 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
3164 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
3165 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3166     (g_display, g_backstore, sw->wnd, g_gc,
3167     boxx, boxy,
3168     boxcx, boxcy,
3169     boxx - sw->xoffset, boxy - sw->yoffset));
3170     }
3171 jsorg71 278 else
3172 astrand 1199 {
3173 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
3174 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
3175 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3176     (g_display, g_backstore, sw->wnd, g_gc,
3177     clipx, clipy,
3178     clipcx, clipcy, clipx - sw->xoffset,
3179     clipy - sw->yoffset));
3180     }
3181 jsorg71 278 }
3182 matty 9 }
3183    
3184 matty 25 void
3185     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
3186 matty 9 {
3187 matty 28 Pixmap pix;
3188 matty 9 XImage *image;
3189    
3190 jsorg71 450 if (g_ownbackstore)
3191 matty 31 {
3192 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
3193 matty 31 }
3194     else
3195     {
3196 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
3197     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
3198     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
3199     XFreePixmap(g_display, pix);
3200 matty 31 }
3201 matty 28
3202 jsorg71 450 offset *= g_bpp / 8;
3203     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
3204 matty 28
3205     XDestroyImage(image);
3206 matty 9 }
3207    
3208 matty 25 void
3209     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
3210 matty 9 {
3211     XImage *image;
3212 matty 10 uint8 *data;
3213 matty 9
3214 jsorg71 450 offset *= g_bpp / 8;
3215     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
3216 matty 10 if (data == NULL)
3217     return;
3218 matty 29
3219 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
3220     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
3221 matty 29
3222 jsorg71 450 if (g_ownbackstore)
3223 matty 31 {
3224 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
3225     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
3226 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3227     (g_display, g_backstore, sw->wnd, g_gc,
3228     x, y, cx, cy, x - sw->xoffset, y - sw->yoffset));
3229 matty 31 }
3230     else
3231     {
3232 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
3233 astrand 1199 ON_ALL_SEAMLESS_WINDOWS(XCopyArea,
3234     (g_display, g_wnd, sw->wnd, g_gc, x, y, cx, cy,
3235     x - sw->xoffset, y - sw->yoffset));
3236 matty 31 }
3237    
3238 matty 9 XFree(image);
3239     }
3240 jsorg71 713
3241     /* these do nothing here but are used in uiports */
3242     void
3243     ui_begin_update(void)
3244     {
3245     }
3246    
3247     void
3248     ui_end_update(void)
3249     {
3250     }
3251 astrand 1199
3252    
3253     void
3254     ui_seamless_begin(BOOL hidden)
3255     {
3256     if (!g_seamless_rdp)
3257     return;
3258    
3259     if (g_seamless_started)
3260     return;
3261    
3262     g_seamless_started = True;
3263     g_seamless_hidden = hidden;
3264    
3265     if (!hidden)
3266     ui_seamless_toggle();
3267     }
3268    
3269    
3270     void
3271     ui_seamless_hide_desktop()
3272     {
3273     if (!g_seamless_rdp)
3274     return;
3275    
3276     if (!g_seamless_started)
3277     return;
3278    
3279     if (g_seamless_active)
3280     ui_seamless_toggle();
3281    
3282     g_seamless_hidden = True;
3283     }
3284    
3285    
3286     void
3287     ui_seamless_unhide_desktop()
3288     {
3289     if (!g_seamless_rdp)
3290     return;
3291    
3292     if (!g_seamless_started)
3293     return;
3294    
3295     g_seamless_hidden = False;
3296    
3297     ui_seamless_toggle();
3298     }
3299    
3300    
3301     void
3302     ui_seamless_toggle()
3303     {
3304     if (!g_seamless_rdp)
3305     return;
3306    
3307     if (!g_seamless_started)
3308     return;
3309    
3310     if (g_seamless_hidden)
3311     return;
3312    
3313     if (g_seamless_active)
3314     {
3315     /* Deactivate */
3316     while (g_seamless_windows)
3317     {
3318     XDestroyWindow(g_display, g_seamless_windows->wnd);
3319     sw_remove_window(g_seamless_windows);
3320     }
3321     XMapWindow(g_display, g_wnd);
3322     }
3323     else
3324     {
3325     /* Activate */
3326     XUnmapWindow(g_display, g_wnd);
3327     seamless_send_sync();
3328     }
3329    
3330     g_seamless_active = !g_seamless_active;
3331     }
3332    
3333    
3334     void
3335     ui_seamless_create_window(unsigned long id, unsigned long group, unsigned long parent,
3336     unsigned long flags)
3337     {
3338     Window wnd;
3339     XSetWindowAttributes attribs;
3340     XClassHint *classhints;
3341     XSizeHints *sizehints;
3342     XWMHints *wmhints;
3343     long input_mask;
3344     seamless_window *sw, *sw_parent;
3345    
3346     if (!g_seamless_active)
3347     return;
3348    
3349     /* Ignore CREATEs for existing windows */
3350     sw = sw_get_window_by_id(id);
3351     if (sw)
3352     return;
3353    
3354     get_window_attribs(&attribs);
3355     wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), -1, -1, 1, 1, 0, g_depth,
3356     InputOutput, g_visual,
3357     CWBackPixel | CWBackingStore | CWColormap | CWBorderPixel, &attribs);
3358    
3359     XStoreName(g_display, wnd, "SeamlessRDP");
3360     ewmh_set_wm_name(wnd, "SeamlessRDP");
3361    
3362     mwm_hide_decorations(wnd);
3363    
3364     classhints = XAllocClassHint();
3365     if (classhints != NULL)
3366     {
3367     classhints->res_name = "rdesktop";
3368     classhints->res_class = "SeamlessRDP";
3369     XSetClassHint(g_display, wnd, classhints);
3370     XFree(classhints);
3371     }
3372    
3373     /* WM_NORMAL_HINTS */
3374     sizehints = XAllocSizeHints();
3375     if (sizehints != NULL)
3376     {
3377     sizehints->flags = USPosition;
3378     XSetWMNormalHints(g_display, wnd, sizehints);
3379     XFree(sizehints);
3380     }
3381    
3382     /* Parent-less transient windows */
3383     if (parent == 0xFFFFFFFF)
3384     {
3385     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3386     /* Some buggy wm:s (kwin) do not handle the above, so fake it
3387     using some other hints. */
3388     ewmh_set_window_popup(wnd);
3389     }
3390     /* Normal transient windows */
3391     else if (parent != 0x00000000)
3392     {
3393     sw_parent = sw_get_window_by_id(parent);
3394     if (sw_parent)
3395     XSetTransientForHint(g_display, wnd, sw_parent->wnd);
3396     else
3397     warning("ui_seamless_create_window: No parent window 0x%lx\n", parent);
3398     }
3399    
3400     if (flags & SEAMLESSRDP_CREATE_MODAL)
3401     {
3402     /* We do this to support buggy wm:s (*cough* metacity *cough*)
3403     somewhat at least */
3404     if (parent == 0x00000000)
3405     XSetTransientForHint(g_display, wnd, RootWindowOfScreen(g_screen));
3406     ewmh_set_window_modal(wnd);
3407     }
3408    
3409     /* FIXME: Support for Input Context:s */
3410    
3411     get_input_mask(&input_mask);
3412     input_mask |= PropertyChangeMask;
3413    
3414     XSelectInput(g_display, wnd, input_mask);
3415    
3416     /* handle the WM_DELETE_WINDOW protocol. FIXME: When killing a
3417     seamless window, we could try to close the window on the
3418     serverside, instead of terminating rdesktop */
3419     XSetWMProtocols(g_display, wnd, &g_kill_atom, 1);
3420    
3421     sw = xmalloc(sizeof(seamless_window));
3422     sw->wnd = wnd;
3423     sw->id = id;
3424     sw->behind = 0;
3425     sw->group = sw_find_group(group, False);
3426     sw->group->refcnt++;
3427     sw->xoffset = 0;
3428     sw->yoffset = 0;
3429     sw->width = 0;
3430     sw->height = 0;
3431     sw->state = SEAMLESSRDP_NOTYETMAPPED;
3432     sw->desktop = 0;
3433     sw->position_timer = xmalloc(sizeof(struct timeval));
3434     timerclear(sw->position_timer);
3435    
3436     sw->outstanding_position = False;
3437     sw->outpos_serial = 0;
3438     sw->outpos_xoffset = sw->outpos_yoffset = 0;
3439     sw->outpos_width = sw->outpos_height = 0;
3440    
3441     sw->next = g_seamless_windows;
3442     g_seamless_windows = sw;
3443    
3444     /* WM_HINTS */
3445     wmhints = XAllocWMHints();
3446     if (wmhints)
3447     {
3448     wmhints->flags = WindowGroupHint;
3449     wmhints->window_group = sw->group->wnd;
3450     XSetWMHints(g_display, sw->wnd, wmhints);
3451     XFree(wmhints);
3452     }
3453     }
3454    
3455    
3456     void
3457     ui_seamless_destroy_window(unsigned long id, unsigned long flags)
3458     {
3459     seamless_window *sw;
3460    
3461     if (!g_seamless_active)
3462     return;
3463    
3464     sw = sw_get_window_by_id(id);
3465     if (!sw)
3466     {
3467     warning("ui_seamless_destroy_window: No information for window 0x%lx\n", id);
3468     return;
3469     }
3470    
3471     XDestroyWindow(g_display, sw->wnd);
3472     sw_remove_window(sw);
3473     }
3474    
3475    
3476     void
3477     ui_seamless_move_window(unsigned long id, int x, int y, int width, int height, unsigned long flags)
3478     {
3479     seamless_window *sw;
3480    
3481     if (!g_seamless_active)
3482     return;
3483    
3484     sw = sw_get_window_by_id(id);
3485     if (!sw)
3486     {
3487     warning("ui_seamless_move_window: No information for window 0x%lx\n", id);
3488     return;
3489     }
3490    
3491     /* We ignore server updates until it has handled our request. */
3492     if (sw->outstanding_position)
3493     return;
3494    
3495     if (!width || !height)
3496     /* X11 windows must be at least 1x1 */
3497     return;
3498    
3499     sw->xoffset = x;
3500     sw->yoffset = y;
3501     sw->width = width;
3502     sw->height = height;
3503    
3504     /* If we move the window in a maximized state, then KDE won't
3505     accept restoration */
3506     switch (sw->state)
3507     {
3508     case SEAMLESSRDP_MINIMIZED:
3509     case SEAMLESSRDP_MAXIMIZED:
3510     return;
3511     }
3512    
3513     /* FIXME: Perhaps use ewmh_net_moveresize_window instead */
3514     XMoveResizeWindow(g_display, sw->wnd, sw->xoffset, sw->yoffset, sw->width, sw->height);
3515     }
3516    
3517    
3518     void
3519     ui_seamless_restack_window(unsigned long id, unsigned long behind, unsigned long flags)
3520     {
3521     seamless_window *sw;
3522    
3523     if (!g_seamless_active)
3524     return;
3525    
3526     sw = sw_get_window_by_id(id);
3527     if (!sw)
3528     {
3529     warning("ui_seamless_restack_window: No information for window 0x%lx\n", id);
3530     return;
3531     }
3532    
3533     if (behind)
3534     {
3535     seamless_window *sw_behind;
3536     Window wnds[2];
3537    
3538     sw_behind = sw_get_window_by_id(behind);
3539     if (!sw_behind)
3540     {
3541     warning("ui_seamless_restack_window: No information for window 0x%lx\n",
3542     behind);
3543     return;
3544     }
3545    
3546     wnds[1] = sw_behind->wnd;
3547     wnds[0] = sw->wnd;
3548    
3549     XRestackWindows(g_display, wnds, 2);
3550     }
3551     else
3552     {
3553     XRaiseWindow(g_display, sw->wnd);
3554     }
3555    
3556     sw_restack_window(sw, behind);
3557     }
3558    
3559    
3560     void
3561     ui_seamless_settitle(unsigned long id, const char *title, unsigned long flags)
3562     {
3563     seamless_window *sw;
3564    
3565     if (!g_seamless_active)
3566     return;
3567    
3568     sw = sw_get_window_by_id(id);
3569     if (!sw)
3570     {
3571     warning("ui_seamless_settitle: No information for window 0x%lx\n", id);
3572     return;
3573     }
3574    
3575     /* FIXME: Might want to convert the name for non-EWMH WMs */
3576     XStoreName(g_display, sw->wnd, title);
3577     ewmh_set_wm_name(sw->wnd, title);
3578     }
3579    
3580    
3581     void
3582     ui_seamless_setstate(unsigned long id, unsigned int state, unsigned long flags)
3583     {
3584     seamless_window *sw;
3585    
3586     if (!g_seamless_active)
3587     return;
3588    
3589     sw = sw_get_window_by_id(id);
3590     if (!sw)
3591     {
3592     warning("ui_seamless_setstate: No information for window 0x%lx\n", id);
3593     return;
3594     }
3595    
3596     switch (state)
3597     {
3598     case SEAMLESSRDP_NORMAL:
3599     case SEAMLESSRDP_MAXIMIZED:
3600     ewmh_change_state(sw->wnd, state);
3601     XMapWindow(g_display, sw->wnd);
3602     break;
3603     case SEAMLESSRDP_MINIMIZED:
3604     /* EWMH says: "if an Application asks to toggle _NET_WM_STATE_HIDDEN
3605     the Window Manager should probably just ignore the request, since
3606     _NET_WM_STATE_HIDDEN is a function of some other aspect of the window
3607     such as minimization, rather than an independent state." Besides,
3608     XIconifyWindow is easier. */
3609     if (sw->state == SEAMLESSRDP_NOTYETMAPPED)
3610     {
3611     XWMHints *hints;
3612     hints = XGetWMHints(g_display, sw->wnd);
3613     if (hints)
3614     {
3615     hints->flags |= StateHint;
3616     hints->initial_state = IconicState;
3617     XSetWMHints(g_display, sw->wnd, hints);
3618     XFree(hints);
3619     }
3620     XMapWindow(g_display, sw->wnd);
3621     }
3622     else
3623     XIconifyWindow(g_display, sw->wnd, DefaultScreen(g_display));
3624     break;
3625     default:
3626     warning("SeamlessRDP: Invalid state %d\n", state);
3627     break;
3628     }
3629    
3630     sw->state = state;
3631     }
3632    
3633    
3634     void
3635     ui_seamless_syncbegin(unsigned long flags)
3636     {
3637     if (!g_seamless_active)
3638     return;
3639    
3640     /* Destroy all seamless windows */
3641     while (g_seamless_windows)
3642     {
3643     XDestroyWindow(g_display, g_seamless_windows->wnd);
3644     sw_remove_window(g_seamless_windows);
3645     }
3646     }
3647    
3648    
3649     void
3650     ui_seamless_ack(unsigned int serial)
3651     {
3652     seamless_window *sw;
3653     for (sw = g_seamless_windows; sw; sw = sw->next)
3654     {
3655     if (sw->outstanding_position && (sw->outpos_serial == serial))
3656     {
3657     sw->xoffset = sw->outpos_xoffset;
3658     sw->yoffset = sw->outpos_yoffset;
3659     sw->width = sw->outpos_width;
3660     sw->height = sw->outpos_height;
3661     sw->outstanding_position = False;
3662    
3663     /* Do a complete redraw of the window as part of the
3664     completion of the move. This is to remove any
3665     artifacts caused by our lack of synchronization. */
3666     XCopyArea(g_display, g_backstore,
3667     sw->wnd, g_gc,
3668     sw->xoffset, sw->yoffset, sw->width, sw->height, 0, 0);
3669    
3670     break;
3671     }
3672     }
3673     }

  ViewVC Help
Powered by ViewVC 1.1.26