/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/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/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1057 - (hide annotations)
Tue Mar 7 08:17:40 2006 UTC (18 years, 2 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 62674 byte(s)
* If fullscreen mode, set g_using_full_workarea = True;

* When using -g workarea, if workarea fetch fails, do not set
  g_using_full_workarea. Fall back to size of entire screen, instead
  of 800x600.

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

  ViewVC Help
Powered by ViewVC 1.1.26