/[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 821 - (hide annotations)
Mon Feb 28 01:15:45 2005 UTC (19 years, 2 months ago) by jdmeijer
File MIME type: text/plain
File size: 51755 byte(s)
More optimisations

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

  ViewVC Help
Powered by ViewVC 1.1.26