/[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 1041 - (hide annotations)
Tue Jan 24 12:25:49 2006 UTC (18 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 57432 byte(s)
Corrected spelling error.

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

  ViewVC Help
Powered by ViewVC 1.1.26