/[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 1042 - (hide annotations)
Tue Jan 24 12:40:24 2006 UTC (18 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 62212 byte(s)
Applied patch #1390148 from Ilya Konstantinov: Refactoring of color depth code.

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

  ViewVC Help
Powered by ViewVC 1.1.26