/[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 1249 - (hide annotations)
Mon Aug 7 11:45:06 2006 UTC (17 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 84145 byte(s)
Fixed a minor seamless bug in DRAW_ELLIPSE: Was copying from
backingstore before updated.

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

  ViewVC Help
Powered by ViewVC 1.1.26