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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1223 - (hide annotations)
Sun Apr 9 20:11:42 2006 UTC (18 years, 1 month ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 83712 byte(s)
Compile fixes for GCC 2.96. Fixes 1444824.

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

  ViewVC Help
Powered by ViewVC 1.1.26