/[rdesktop]/sourceforge.net/trunk/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1364 - (hide annotations)
Thu Jan 4 04:55:56 2007 UTC (17 years, 4 months ago) by jsorg71
File MIME type: text/plain
File size: 84162 byte(s)
RD_ prefix and win32 compatibility for core files

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

  ViewVC Help
Powered by ViewVC 1.1.26