/[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 1250 - (hide annotations)
Mon Aug 7 11:46:28 2006 UTC (17 years, 10 months ago) by astrand
File MIME type: text/plain
File size: 84157 byte(s)
Indent fixes

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