/[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 988 - (hide annotations)
Thu Aug 25 20:27:45 2005 UTC (18 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 56736 byte(s)
Moved mouse button handling to separate function, handle_button_event. The single app mode has been enhanced: The minimazation now works better.

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 342
83 matthewc 474 #ifdef WITH_RDPSND
84     extern int g_dsp_fd;
85     extern BOOL g_dsp_busy;
86 stargo 501 extern BOOL g_rdpsnd;
87 matthewc 474 #endif
88    
89 astrand 262 /* MWM decorations */
90     #define MWM_HINTS_DECORATIONS (1L << 1)
91     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
92     typedef struct
93     {
94 matthewc 301 uint32 flags;
95     uint32 functions;
96     uint32 decorations;
97     sint32 inputMode;
98     uint32 status;
99 astrand 262 }
100     PropMotifWmHints;
101    
102 jsorg71 316 typedef struct
103     {
104     uint32 red;
105     uint32 green;
106     uint32 blue;
107     }
108     PixelColour;
109 astrand 262
110 forsberg 415
111 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
112     { \
113 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
114     if (g_ownbackstore) \
115     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
116 matty 31 }
117    
118 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
119 jsorg71 281 { \
120 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
121 jsorg71 281 }
122    
123 jdmeijer 831 #define FILL_POLYGON(p,np)\
124     { \
125     XFillPolygon(g_display, g_wnd, g_gc, p, np, Complex, CoordModePrevious); \
126     if (g_ownbackstore) \
127     XFillPolygon(g_display, g_backstore, g_gc, p, np, Complex, CoordModePrevious); \
128     }
129    
130     #define DRAW_ELLIPSE(x,y,cx,cy,m)\
131     { \
132     switch (m) \
133     { \
134     case 0: /* Outline */ \
135     XDrawArc(g_display, g_wnd, g_gc, x, y, cx, cy, 0, 360*64); \
136     if (g_ownbackstore) \
137     XDrawArc(g_display, g_backstore, g_gc, x, y, cx, cy, 0, 360*64); \
138     break; \
139     case 1: /* Filled */ \
140     XFillArc(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, \
141     cx, cy, 0, 360*64); \
142     if (g_ownbackstore) \
143     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y); \
144     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 jdmeijer 821 *((uint32 *) out) = *((uint32 *) data);
806     out += 4;
807     data += 3;
808 stargo 822 )
809 jdmeijer 821 #endif
810     /* *INDENT-ON* */
811     }
812     else if (g_xserver_be)
813     {
814     while (out < end)
815 jsorg71 472 {
816 jdmeijer 821 pixel = *(data++) << 16;
817     pixel |= *(data++) << 8;
818     pixel |= *(data++);
819     SPLITCOLOUR24(pixel, pc);
820     value = MAKECOLOUR(pc);
821     BOUT32(out, value);
822 jsorg71 472 }
823 jdmeijer 821 }
824     else
825     {
826     while (out < end)
827 jsorg71 472 {
828 jdmeijer 821 pixel = *(data++) << 16;
829     pixel |= *(data++) << 8;
830     pixel |= *(data++);
831     SPLITCOLOUR24(pixel, pc);
832     value = MAKECOLOUR(pc);
833     LOUT32(out, value);
834 jsorg71 472 }
835 jsorg71 316 }
836     }
837    
838 matty 29 static uint8 *
839 astrand 64 translate_image(int width, int height, uint8 * data)
840 matty 28 {
841 jsorg71 644 int size;
842     uint8 *out;
843     uint8 *end;
844 matty 29
845 jsorg71 644 /* if server and xserver bpp match, */
846     /* and arch(endian) matches, no need to translate */
847     /* just return data */
848 jsorg71 645 if (g_arch_match)
849     {
850     if (g_depth == 15 && g_server_bpp == 15)
851     return data;
852     if (g_depth == 16 && g_server_bpp == 16)
853     return data;
854 jdmeijer 821 if (g_depth == 24 && g_bpp == 24 && g_server_bpp == 24)
855     return data;
856 jsorg71 645 }
857 jsorg71 644
858     size = width * height * (g_bpp / 8);
859     out = (uint8 *) xmalloc(size);
860     end = out + size;
861    
862 jsorg71 438 switch (g_server_bpp)
863 jsorg71 311 {
864 jsorg71 316 case 24:
865 jsorg71 450 switch (g_bpp)
866 jsorg71 316 {
867     case 32:
868 jsorg71 483 translate24to32(data, out, end);
869 jsorg71 316 break;
870     case 24:
871     translate24to24(data, out, end);
872     break;
873     case 16:
874 jsorg71 483 translate24to16(data, out, end);
875 jsorg71 316 break;
876     }
877 matty 29 break;
878     case 16:
879 jsorg71 450 switch (g_bpp)
880 jsorg71 316 {
881     case 32:
882 jsorg71 483 translate16to32((uint16 *) data, out, end);
883 jsorg71 316 break;
884     case 24:
885     translate16to24((uint16 *) data, out, end);
886     break;
887     case 16:
888 matthewc 528 translate16to16((uint16 *) data, out, end);
889 jsorg71 316 break;
890     }
891 matty 29 break;
892 jsorg71 316 case 15:
893 jsorg71 450 switch (g_bpp)
894 jsorg71 316 {
895     case 32:
896 jsorg71 483 translate15to32((uint16 *) data, out, end);
897 jsorg71 316 break;
898     case 24:
899     translate15to24((uint16 *) data, out, end);
900     break;
901     case 16:
902 jsorg71 483 translate15to16((uint16 *) data, out, end);
903 jsorg71 316 break;
904     }
905 matty 29 break;
906 jsorg71 316 case 8:
907 jsorg71 450 switch (g_bpp)
908 jsorg71 316 {
909     case 8:
910     translate8to8(data, out, end);
911     break;
912     case 16:
913 stargo 521 translate8to16(data, out, end);
914 jsorg71 316 break;
915     case 24:
916     translate8to24(data, out, end);
917     break;
918     case 32:
919 stargo 521 translate8to32(data, out, end);
920 jsorg71 316 break;
921     }
922 matty 29 break;
923     }
924     return out;
925 matty 28 }
926    
927 astrand 118 BOOL
928 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
929 astrand 102 {
930 matthewc 203 int modifierpos, key, keysymMask = 0;
931 astrand 102 int offset;
932    
933 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
934 astrand 102
935     if (keycode == NoSymbol)
936     return False;
937    
938     for (modifierpos = 0; modifierpos < 8; modifierpos++)
939     {
940 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
941 astrand 102
942 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
943 astrand 102 {
944 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
945 matthewc 203 keysymMask |= 1 << modifierpos;
946 astrand 102 }
947     }
948    
949 matthewc 203 return (state & keysymMask) ? True : False;
950 astrand 102 }
951    
952 matthewc 527 static void
953     calculate_shifts(uint32 mask, int *shift_r, int *shift_l)
954     {
955     *shift_l = ffs(mask) - 1;
956     mask >>= *shift_l;
957     *shift_r = 8 - ffs(mask & ~(mask >> 1));
958     }
959    
960 jsorg71 81 BOOL
961 matthewc 192 ui_init(void)
962 jsorg71 81 {
963 matthewc 527 XVisualInfo vi;
964 matthewc 121 XPixmapFormatValues *pfm;
965     uint16 test;
966 stargo 565 int i, screen_num, nvisuals;
967     XVisualInfo *vmatches = NULL;
968     XVisualInfo template;
969     Bool TrueColorVisual = False;
970 matthewc 121
971 jsorg71 450 g_display = XOpenDisplay(NULL);
972     if (g_display == NULL)
973 jsorg71 81 {
974 matthewc 210 error("Failed to open display: %s\n", XDisplayName(NULL));
975 jsorg71 81 return False;
976     }
977 matthewc 121
978 matthewc 527 screen_num = DefaultScreen(g_display);
979 jsorg71 450 g_x_socket = ConnectionNumber(g_display);
980 matthewc 527 g_screen = ScreenOfDisplay(g_display, screen_num);
981 jsorg71 450 g_depth = DefaultDepthOfScreen(g_screen);
982 matthewc 121
983 stargo 565 /* Search for best TrueColor depth */
984     template.class = TrueColor;
985     vmatches = XGetVisualInfo(g_display, VisualClassMask, &template, &nvisuals);
986    
987     nvisuals--;
988     while (nvisuals >= 0)
989 matthewc 527 {
990 stargo 565 if ((vmatches + nvisuals)->depth > g_depth)
991     {
992     g_depth = (vmatches + nvisuals)->depth;
993     }
994     nvisuals--;
995     TrueColorVisual = True;
996     }
997    
998 jsorg71 644 test = 1;
999     g_host_be = !(BOOL) (*(uint8 *) (&test));
1000     g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
1001    
1002 astrand 580 if ((g_server_bpp == 8) && ((!TrueColorVisual) || (g_depth <= 8)))
1003 stargo 565 {
1004     /* we use a colourmap, so the default visual should do */
1005 matthewc 527 g_visual = DefaultVisualOfScreen(g_screen);
1006 stargo 565 g_depth = DefaultDepthOfScreen(g_screen);
1007    
1008     /* Do not allocate colours on a TrueColor visual */
1009     if (g_visual->class == TrueColor)
1010     {
1011     g_owncolmap = False;
1012     }
1013 matthewc 527 }
1014     else
1015     {
1016     /* need a truecolour visual */
1017     if (!XMatchVisualInfo(g_display, screen_num, g_depth, TrueColor, &vi))
1018     {
1019     error("The display does not support true colour - high colour support unavailable.\n");
1020     return False;
1021     }
1022    
1023     g_visual = vi.visual;
1024     g_owncolmap = False;
1025 astrand 532 calculate_shifts(vi.red_mask, &g_red_shift_r, &g_red_shift_l);
1026     calculate_shifts(vi.blue_mask, &g_blue_shift_r, &g_blue_shift_l);
1027 matthewc 527 calculate_shifts(vi.green_mask, &g_green_shift_r, &g_green_shift_l);
1028 jsorg71 644
1029 jdmeijer 821 /* if RGB video and everything is little endian */
1030     if ((vi.red_mask > vi.green_mask && vi.green_mask > vi.blue_mask) &&
1031     !g_xserver_be && !g_host_be)
1032     {
1033     if (g_depth <= 16 || (g_red_shift_l == 16 && g_green_shift_l == 8 &&
1034     g_blue_shift_l == 0))
1035     {
1036 jsorg71 644 g_arch_match = True;
1037 jdmeijer 821 }
1038     }
1039    
1040     if (g_arch_match)
1041     {
1042     DEBUG(("Architectures match, enabling little endian optimisations.\n"));
1043     }
1044 matthewc 527 }
1045    
1046 jsorg71 450 pfm = XListPixmapFormats(g_display, &i);
1047 matthewc 121 if (pfm != NULL)
1048     {
1049     /* Use maximum bpp for this depth - this is generally
1050     desirable, e.g. 24 bits->32 bits. */
1051     while (i--)
1052     {
1053 jsorg71 450 if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
1054 matthewc 121 {
1055 jsorg71 450 g_bpp = pfm[i].bits_per_pixel;
1056 matthewc 121 }
1057     }
1058     XFree(pfm);
1059     }
1060    
1061 jsorg71 450 if (g_bpp < 8)
1062 matthewc 121 {
1063     error("Less than 8 bpp not currently supported.\n");
1064 jsorg71 450 XCloseDisplay(g_display);
1065 matthewc 121 return False;
1066     }
1067    
1068 matthewc 517 if (!g_owncolmap)
1069 n-ki 279 {
1070 astrand 580 g_xcolmap =
1071     XCreateColormap(g_display, RootWindowOfScreen(g_screen), g_visual,
1072     AllocNone);
1073 jsorg71 450 if (g_depth <= 8)
1074 matthewc 297 warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
1075 n-ki 279 }
1076    
1077 stargo 609 if ((!g_ownbackstore) && (DoesBackingStore(g_screen) != Always))
1078     {
1079     warning("External BackingStore not available, using internal\n");
1080 jsorg71 450 g_ownbackstore = True;
1081 stargo 609 }
1082 matthewc 121
1083 astrand 500 /*
1084     * Determine desktop size
1085     */
1086 astrand 547 if (g_fullscreen)
1087 astrand 263 {
1088 astrand 547 g_width = WidthOfScreen(g_screen);
1089     g_height = HeightOfScreen(g_screen);
1090     }
1091     else if (g_width < 0)
1092     {
1093 astrand 500 /* Percent of screen */
1094     g_height = HeightOfScreen(g_screen) * (-g_width) / 100;
1095     g_width = WidthOfScreen(g_screen) * (-g_width) / 100;
1096     }
1097     else if (g_width == 0)
1098     {
1099 astrand 263 /* Fetch geometry from _NET_WORKAREA */
1100 matthewc 300 uint32 x, y, cx, cy;
1101 astrand 263
1102 matthewc 300 if (get_current_workarea(&x, &y, &cx, &cy) == 0)
1103 astrand 263 {
1104 jsorg71 447 g_width = cx;
1105     g_height = cy;
1106 matthewc 300 }
1107     else
1108     {
1109 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
1110 jsorg71 447 g_width = 800;
1111     g_height = 600;
1112 astrand 263 }
1113     }
1114 matthewc 121
1115 matthewc 160 /* make sure width is a multiple of 4 */
1116 jsorg71 447 g_width = (g_width + 3) & ~3;
1117 matthewc 160
1118 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
1119 matthewc 203
1120 astrand 498 xkeymap_init();
1121    
1122 jsorg71 447 if (g_enable_compose)
1123 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
1124 matthewc 188
1125 matthewc 432 xclip_init();
1126 jsorg71 316
1127 matthewc 519 DEBUG_RDP5(("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth));
1128 jsorg71 316
1129 jsorg71 81 return True;
1130     }
1131 astrand 66
1132 matthewc 188 void
1133 matthewc 192 ui_deinit(void)
1134 matthewc 188 {
1135 jsorg71 450 if (g_IM != NULL)
1136     XCloseIM(g_IM);
1137 astrand 580
1138 stargo 576 if (g_null_cursor != NULL)
1139     ui_destroy_cursor(g_null_cursor);
1140 matthewc 188
1141 jsorg71 450 XFreeModifiermap(g_mod_map);
1142 matthewc 203
1143 jsorg71 450 if (g_ownbackstore)
1144     XFreePixmap(g_display, g_backstore);
1145 matthewc 188
1146 jsorg71 450 XFreeGC(g_display, g_gc);
1147     XCloseDisplay(g_display);
1148     g_display = NULL;
1149 matthewc 188 }
1150    
1151 matthewc 121 BOOL
1152 matthewc 192 ui_create_window(void)
1153 matty 6 {
1154 matthewc 536 uint8 null_pointer_mask[1] = { 0x80 };
1155 astrand 788 uint8 null_pointer_data[24] = { 0x00 };
1156    
1157 matthewc 121 XSetWindowAttributes attribs;
1158 matty 28 XClassHint *classhints;
1159     XSizeHints *sizehints;
1160 matthewc 188 int wndwidth, wndheight;
1161 matthewc 432 long input_mask, ic_input_mask;
1162 jsorg71 100 XEvent xevent;
1163    
1164 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
1165     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
1166 matthewc 188
1167 stargo 867 /* Handle -x-y portion of geometry string */
1168     if (g_xpos < 0 || (g_xpos == 0 && (g_pos & 2)))
1169     g_xpos = WidthOfScreen(g_screen) + g_xpos - g_width;
1170     if (g_ypos < 0 || (g_ypos == 0 && (g_pos & 4)))
1171     g_ypos = HeightOfScreen(g_screen) + g_ypos - g_height;
1172    
1173 jsorg71 450 attribs.background_pixel = BlackPixelOfScreen(g_screen);
1174 stargo 565 attribs.border_pixel = WhitePixelOfScreen(g_screen);
1175 jsorg71 450 attribs.backing_store = g_ownbackstore ? NotUseful : Always;
1176 jsorg71 447 attribs.override_redirect = g_fullscreen;
1177 stargo 565 attribs.colormap = g_xcolmap;
1178 matthewc 188
1179 astrand 801 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), g_xpos, g_ypos, wndwidth,
1180     wndheight, 0, g_depth, InputOutput, g_visual,
1181     CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap |
1182     CWBorderPixel, &attribs);
1183 jsorg71 100
1184 stargo 576 if (g_gc == NULL)
1185 stargo 566 g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1186 stargo 565
1187 jsorg71 725 if (g_create_bitmap_gc == NULL)
1188     g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
1189    
1190 stargo 603 if ((g_ownbackstore) && (g_backstore == 0))
1191 stargo 565 {
1192 astrand 580 g_backstore = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1193 stargo 565
1194     /* clear to prevent rubbish being exposed at startup */
1195     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1196     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
1197     }
1198    
1199 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
1200 jsorg71 100
1201 jsorg71 450 if (g_hide_decorations)
1202 astrand 262 mwm_hide_decorations();
1203    
1204 jsorg71 100 classhints = XAllocClassHint();
1205     if (classhints != NULL)
1206     {
1207     classhints->res_name = classhints->res_class = "rdesktop";
1208 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
1209 jsorg71 100 XFree(classhints);
1210     }
1211    
1212     sizehints = XAllocSizeHints();
1213     if (sizehints)
1214     {
1215     sizehints->flags = PMinSize | PMaxSize;
1216 stargo 867 if (g_pos)
1217     sizehints->flags |= PPosition;
1218 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
1219     sizehints->min_height = sizehints->max_height = g_height;
1220 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
1221 jsorg71 100 XFree(sizehints);
1222     }
1223    
1224 astrand 651 if (g_embed_wnd)
1225     {
1226     XReparentWindow(g_display, g_wnd, (Window) g_embed_wnd, 0, 0);
1227     }
1228 stargo 636
1229 matthewc 121 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
1230 jdmeijer 905 VisibilityChangeMask | FocusChangeMask | StructureNotifyMask;
1231 matthewc 121
1232 jsorg71 447 if (g_sendmotion)
1233 matthewc 121 input_mask |= PointerMotionMask;
1234 jsorg71 450 if (g_ownbackstore)
1235 matthewc 121 input_mask |= ExposureMask;
1236 jsorg71 450 if (g_fullscreen || g_grab_keyboard)
1237 matthewc 250 input_mask |= EnterWindowMask;
1238 jsorg71 450 if (g_grab_keyboard)
1239 jsorg71 257 input_mask |= LeaveWindowMask;
1240 jsorg71 100
1241 jsorg71 450 if (g_IM != NULL)
1242 matthewc 188 {
1243 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
1244 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
1245 matthewc 188
1246 jsorg71 450 if ((g_IC != NULL)
1247     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
1248 matthewc 188 input_mask |= ic_input_mask;
1249     }
1250    
1251 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
1252     XMapWindow(g_display, g_wnd);
1253 jsorg71 100
1254 matthewc 208 /* wait for VisibilityNotify */
1255 astrand 196 do
1256     {
1257 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
1258 astrand 196 }
1259 matthewc 208 while (xevent.type != VisibilityNotify);
1260 jsorg71 688 g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1261 matthewc 123
1262 jsorg71 447 g_focused = False;
1263     g_mouse_in_wnd = False;
1264 jsorg71 257
1265 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
1266 jsorg71 450 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
1267     g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
1268     XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
1269 astrand 275
1270 astrand 508 /* create invisible 1x1 cursor to be used as null cursor */
1271 stargo 576 if (g_null_cursor == NULL)
1272     g_null_cursor = ui_create_cursor(0, 0, 1, 1, null_pointer_mask, null_pointer_data);
1273 astrand 508
1274 matty 10 return True;
1275 matty 6 }
1276    
1277 matty 25 void
1278 n-ki 677 ui_resize_window()
1279     {
1280     XSizeHints *sizehints;
1281 jsorg71 708 Pixmap bs;
1282 n-ki 677
1283     sizehints = XAllocSizeHints();
1284     if (sizehints)
1285     {
1286     sizehints->flags = PMinSize | PMaxSize;
1287     sizehints->min_width = sizehints->max_width = g_width;
1288     sizehints->min_height = sizehints->max_height = g_height;
1289     XSetWMNormalHints(g_display, g_wnd, sizehints);
1290     XFree(sizehints);
1291     }
1292    
1293     if (!(g_fullscreen || g_embed_wnd))
1294     {
1295     XResizeWindow(g_display, g_wnd, g_width, g_height);
1296     }
1297 jsorg71 708
1298     /* create new backstore pixmap */
1299     if (g_backstore != 0)
1300     {
1301     bs = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1302     XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
1303     XFillRectangle(g_display, bs, g_gc, 0, 0, g_width, g_height);
1304     XCopyArea(g_display, g_backstore, bs, g_gc, 0, 0, g_width, g_height, 0, 0);
1305     XFreePixmap(g_display, g_backstore);
1306     g_backstore = bs;
1307     }
1308 n-ki 677 }
1309    
1310     void
1311 matthewc 192 ui_destroy_window(void)
1312 matty 6 {
1313 jsorg71 450 if (g_IC != NULL)
1314     XDestroyIC(g_IC);
1315 matty 31
1316 jsorg71 450 XDestroyWindow(g_display, g_wnd);
1317 matty 6 }
1318    
1319 jsorg71 100 void
1320 matthewc 192 xwin_toggle_fullscreen(void)
1321 jsorg71 100 {
1322 matthewc 188 Pixmap contents = 0;
1323 matthewc 123
1324 jsorg71 450 if (!g_ownbackstore)
1325 matthewc 188 {
1326     /* need to save contents of window */
1327 jsorg71 450 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
1328     XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
1329 matthewc 188 }
1330    
1331     ui_destroy_window();
1332 jsorg71 447 g_fullscreen = !g_fullscreen;
1333 matthewc 188 ui_create_window();
1334 matthewc 123
1335 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
1336 matthewc 188
1337 jsorg71 450 if (!g_ownbackstore)
1338 matthewc 188 {
1339 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
1340     XFreePixmap(g_display, contents);
1341 matthewc 188 }
1342 jsorg71 100 }
1343    
1344 astrand 988 static void
1345     handle_button_event(XEvent xevent, BOOL down)
1346     {
1347     uint16 button, flags = 0;
1348     g_last_gesturetime = xevent.xbutton.time;
1349     button = xkeymap_translate_button(xevent.xbutton.button);
1350     if (button == 0)
1351     return;
1352    
1353     if (down)
1354     flags = MOUSE_FLAG_DOWN;
1355    
1356     /* Stop moving window when button is released, regardless of cursor position */
1357     if (g_moving_wnd && (xevent.type == ButtonRelease))
1358     g_moving_wnd = False;
1359    
1360     /* If win_button_size is nonzero, enable single app mode */
1361     if (xevent.xbutton.y < g_win_button_size)
1362     {
1363     /* Check from right to left: */
1364     if (xevent.xbutton.x >= g_width - g_win_button_size)
1365     {
1366     /* The close button, continue */
1367     ;
1368     }
1369     else if (xevent.xbutton.x >= g_width - g_win_button_size * 2)
1370     {
1371     /* The maximize/restore button. Do not send to
1372     server. It might be a good idea to change the
1373     cursor or give some other visible indication
1374     that rdesktop inhibited this click */
1375     if (xevent.type == ButtonPress)
1376     return;
1377     }
1378     else if (xevent.xbutton.x >= g_width - g_win_button_size * 3)
1379     {
1380     /* The minimize button. Iconify window. */
1381     if (xevent.type == ButtonRelease)
1382     {
1383     /* Release the mouse button outside the minimize button, to prevent the
1384     actual minimazation to happen */
1385     rdp_send_input(time(NULL), RDP_INPUT_MOUSE, button, 1, 1);
1386     XIconifyWindow(g_display, g_wnd, DefaultScreen(g_display));
1387     return;
1388     }
1389     }
1390     else if (xevent.xbutton.x <= g_win_button_size)
1391     {
1392     /* The system menu. Ignore. */
1393     if (xevent.type == ButtonPress)
1394     return;
1395     }
1396     else
1397     {
1398     /* The title bar. */
1399     if (xevent.type == ButtonPress)
1400     {
1401     if (!g_fullscreen && g_hide_decorations)
1402     {
1403     g_moving_wnd = True;
1404     g_move_x_offset = xevent.xbutton.x;
1405     g_move_y_offset = xevent.xbutton.y;
1406     }
1407     return;
1408     }
1409     }
1410     }
1411    
1412     rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1413     flags | button, xevent.xbutton.x, xevent.xbutton.y);
1414     }
1415    
1416 stargo 887 /* Process events in Xlib queue
1417 astrand 275 Returns 0 after user quit, 1 otherwise */
1418     static int
1419 matthewc 192 xwin_process_events(void)
1420 matty 9 {
1421 n-ki 54 XEvent xevent;
1422 matthewc 38 KeySym keysym;
1423 matty 10 uint32 ev_time;
1424 astrand 66 char str[256];
1425     Status status;
1426 stargo 887 int events = 0;
1427 matty 9
1428 stargo 887 while ((XPending(g_display) > 0) && events++ < 20)
1429 matty 9 {
1430 jsorg71 450 XNextEvent(g_display, &xevent);
1431 matthewc 123
1432 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
1433 astrand 66 {
1434 astrand 84 DEBUG_KBD(("Filtering event\n"));
1435 astrand 66 continue;
1436     }
1437    
1438 n-ki 54 switch (xevent.type)
1439 matty 9 {
1440 jsorg71 688 case VisibilityNotify:
1441     g_Unobscured = xevent.xvisibility.state == VisibilityUnobscured;
1442     break;
1443 astrand 275 case ClientMessage:
1444     /* the window manager told us to quit */
1445 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
1446     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
1447 astrand 275 /* Quit */
1448     return 0;
1449     break;
1450    
1451 matty 9 case KeyPress:
1452 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1453     if (g_IC != NULL)
1454 astrand 66 /* Multi_key compatible version */
1455     {
1456 jsorg71 450 XmbLookupString(g_IC,
1457 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
1458     &status);
1459 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
1460 astrand 66 {
1461 astrand 82 error("XmbLookupString failed with status 0x%x\n",
1462     status);
1463 astrand 66 break;
1464     }
1465     }
1466     else
1467     {
1468     /* Plain old XLookupString */
1469 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
1470 astrand 66 XLookupString((XKeyEvent *) & xevent,
1471 astrand 82 str, sizeof(str), &keysym, NULL);
1472 astrand 66 }
1473    
1474 astrand 949 DEBUG_KBD(("KeyPress for keysym (0x%lx, %s)\n", keysym,
1475 astrand 261 get_ksname(keysym)));
1476 astrand 66
1477 matthewc 203 ev_time = time(NULL);
1478     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
1479 astrand 118 break;
1480    
1481 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1482 astrand 976 ev_time, True, 0);
1483 astrand 66 break;
1484 matthewc 203
1485 astrand 66 case KeyRelease:
1486 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
1487 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
1488     sizeof(str), &keysym, NULL);
1489 n-ki 52
1490 astrand 949 DEBUG_KBD(("\nKeyRelease for keysym (0x%lx, %s)\n", keysym,
1491 matthewc 203 get_ksname(keysym)));
1492 n-ki 52
1493 matthewc 203 ev_time = time(NULL);
1494     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
1495 astrand 118 break;
1496    
1497 astrand 949 xkeymap_send_keys(keysym, xevent.xkey.keycode, xevent.xkey.state,
1498 astrand 976 ev_time, False, 0);
1499 matty 9 break;
1500    
1501     case ButtonPress:
1502 astrand 988 handle_button_event(xevent, True);
1503     break;
1504 matty 9
1505     case ButtonRelease:
1506 astrand 988 handle_button_event(xevent, False);
1507 matty 10 break;
1508    
1509     case MotionNotify:
1510 jsorg71 450 if (g_moving_wnd)
1511 astrand 342 {
1512 jsorg71 450 XMoveWindow(g_display, g_wnd,
1513     xevent.xmotion.x_root - g_move_x_offset,
1514     xevent.xmotion.y_root - g_move_y_offset);
1515 astrand 342 break;
1516     }
1517    
1518 jsorg71 447 if (g_fullscreen && !g_focused)
1519 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1520 jsorg71 288 CurrentTime);
1521 matthewc 203 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
1522 astrand 82 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
1523 matty 28 break;
1524    
1525 matthewc 194 case FocusIn:
1526 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
1527     break;
1528 jsorg71 447 g_focused = True;
1529 astrand 543 reset_modifier_keys();
1530 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
1531     XGrabKeyboard(g_display, g_wnd, True,
1532 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
1533 matty 28 break;
1534    
1535 matthewc 194 case FocusOut:
1536 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
1537     break;
1538 jsorg71 447 g_focused = False;
1539 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
1540 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
1541 matty 28 break;
1542 matty 31
1543 matthewc 250 case EnterNotify:
1544     /* we only register for this event when in fullscreen mode */
1545 jsorg71 257 /* or grab_keyboard */
1546 jsorg71 447 g_mouse_in_wnd = True;
1547     if (g_fullscreen)
1548 jsorg71 257 {
1549 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
1550 astrand 261 CurrentTime);
1551 jsorg71 257 break;
1552     }
1553 jsorg71 447 if (g_focused)
1554 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
1555 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
1556 matthewc 250 break;
1557    
1558 matthewc 253 case LeaveNotify:
1559 jsorg71 257 /* we only register for this event when grab_keyboard */
1560 jsorg71 447 g_mouse_in_wnd = False;
1561 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
1562 matthewc 253 break;
1563    
1564 matty 31 case Expose:
1565 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
1566 n-ki 54 xevent.xexpose.x, xevent.xexpose.y,
1567 astrand 64 xevent.xexpose.width,
1568     xevent.xexpose.height,
1569 n-ki 54 xevent.xexpose.x, xevent.xexpose.y);
1570 matty 31 break;
1571 astrand 119
1572     case MappingNotify:
1573     /* Refresh keyboard mapping if it has changed. This is important for
1574     Xvnc, since it allocates keycodes dynamically */
1575     if (xevent.xmapping.request == MappingKeyboard
1576     || xevent.xmapping.request == MappingModifier)
1577     XRefreshKeyboardMapping(&xevent.xmapping);
1578 matthewc 203
1579     if (xevent.xmapping.request == MappingModifier)
1580     {
1581 jsorg71 450 XFreeModifiermap(g_mod_map);
1582     g_mod_map = XGetModifierMapping(g_display);
1583 matthewc 203 }
1584 astrand 119 break;
1585 matthewc 432
1586 astrand 435 /* clipboard stuff */
1587 forsberg 415 case SelectionNotify:
1588 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
1589 forsberg 415 break;
1590     case SelectionRequest:
1591 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1592 forsberg 415 break;
1593 matthewc 432 case SelectionClear:
1594     xclip_handle_SelectionClear();
1595     break;
1596 forsberg 415 case PropertyNotify:
1597 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
1598 forsberg 415 break;
1599 jdmeijer 905 case MapNotify:
1600     rdp_send_client_window_status(1);
1601     break;
1602     case UnmapNotify:
1603     rdp_send_client_window_status(0);
1604     break;
1605 matty 9 }
1606     }
1607 astrand 275 /* Keep going */
1608     return 1;
1609 matty 9 }
1610    
1611 astrand 275 /* Returns 0 after user quit, 1 otherwise */
1612     int
1613 matty 33 ui_select(int rdp_socket)
1614     {
1615 stargo 606 int n;
1616 matthewc 474 fd_set rfds, wfds;
1617 n-ki 592 struct timeval tv;
1618     BOOL s_timeout = False;
1619 matty 33
1620     while (True)
1621     {
1622 stargo 606 n = (rdp_socket > g_x_socket) ? rdp_socket : g_x_socket;
1623 matthewc 121 /* Process any events already waiting */
1624 astrand 275 if (!xwin_process_events())
1625     /* User quit */
1626     return 0;
1627 astrand 119
1628 matty 33 FD_ZERO(&rfds);
1629 matthewc 474 FD_ZERO(&wfds);
1630 matty 33 FD_SET(rdp_socket, &rfds);
1631 jsorg71 450 FD_SET(g_x_socket, &rfds);
1632 matty 33
1633 matthewc 474 #ifdef WITH_RDPSND
1634     /* FIXME: there should be an API for registering fds */
1635 stargo 504 if (g_dsp_busy)
1636 matty 33 {
1637 matthewc 474 FD_SET(g_dsp_fd, &wfds);
1638 n-ki 592 n = (g_dsp_fd > n) ? g_dsp_fd : n;
1639 astrand 499 }
1640 matthewc 474 #endif
1641 n-ki 592 /* default timeout */
1642     tv.tv_sec = 60;
1643     tv.tv_usec = 0;
1644 matthewc 474
1645 n-ki 592 /* add redirection handles */
1646     rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
1647    
1648     n++;
1649    
1650     switch (select(n, &rfds, &wfds, NULL, &tv))
1651 matthewc 474 {
1652 matty 33 case -1:
1653     error("select: %s\n", strerror(errno));
1654    
1655     case 0:
1656 stargo 795 /* Abort serial read calls */
1657     if (s_timeout)
1658     rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
1659 matty 33 continue;
1660     }
1661    
1662 n-ki 592 rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
1663    
1664 stargo 754 if (FD_ISSET(rdp_socket, &rfds))
1665     return 1;
1666    
1667 matthewc 474 #ifdef WITH_RDPSND
1668 stargo 504 if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
1669 matthewc 474 wave_out_play();
1670     #endif
1671 matty 33 }
1672     }
1673    
1674     void
1675 matty 25 ui_move_pointer(int x, int y)
1676 matty 9 {
1677 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1678 matty 9 }
1679    
1680 matty 25 HBITMAP
1681 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
1682 matty 6 {
1683     XImage *image;
1684 matty 9 Pixmap bitmap;
1685 matty 28 uint8 *tdata;
1686 stargo 521 int bitmap_pad;
1687 matty 29
1688 stargo 521 if (g_server_bpp == 8)
1689     {
1690     bitmap_pad = 8;
1691     }
1692     else
1693     {
1694     bitmap_pad = g_bpp;
1695    
1696     if (g_bpp == 24)
1697     bitmap_pad = 32;
1698     }
1699    
1700 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1701     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1702     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1703 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
1704 matty 6
1705 jsorg71 725 XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
1706 matty 9
1707     XFree(image);
1708 jsorg71 644 if (tdata != data)
1709 n-ki 279 xfree(tdata);
1710 matty 24 return (HBITMAP) bitmap;
1711 matty 6 }
1712    
1713 matty 25 void
1714 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1715 matty 6 {
1716 matty 10 XImage *image;
1717 matty 29 uint8 *tdata;
1718 stargo 521 int bitmap_pad;
1719    
1720     if (g_server_bpp == 8)
1721     {
1722     bitmap_pad = 8;
1723     }
1724     else
1725     {
1726     bitmap_pad = g_bpp;
1727    
1728     if (g_bpp == 24)
1729     bitmap_pad = 32;
1730     }
1731    
1732 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1733     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1734 stargo 521 (char *) tdata, width, height, bitmap_pad, 0);
1735 matty 28
1736 jsorg71 450 if (g_ownbackstore)
1737 matty 31 {
1738 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1739     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1740 matty 31 }
1741     else
1742     {
1743 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1744 matty 31 }
1745 matty 29
1746 matty 24 XFree(image);
1747 jsorg71 644 if (tdata != data)
1748 n-ki 279 xfree(tdata);
1749 matty 6 }
1750    
1751 matty 25 void
1752     ui_destroy_bitmap(HBITMAP bmp)
1753 matty 6 {
1754 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
1755 matty 10 }
1756    
1757 matty 25 HGLYPH
1758 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
1759 matty 10 {
1760 matty 9 XImage *image;
1761     Pixmap bitmap;
1762     int scanline;
1763 matty 6
1764 matty 9 scanline = (width + 7) / 8;
1765 matty 6
1766 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1767 jsorg71 725 if (g_create_glyph_gc == 0)
1768     g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
1769 matty 9
1770 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1771 astrand 73 width, height, 8, scanline);
1772 matty 23 image->byte_order = MSBFirst;
1773     image->bitmap_bit_order = MSBFirst;
1774     XInitImage(image);
1775    
1776 jsorg71 725 XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
1777 matty 29
1778 matty 9 XFree(image);
1779 astrand 64 return (HGLYPH) bitmap;
1780 matty 6 }
1781 matty 7
1782 matty 25 void
1783     ui_destroy_glyph(HGLYPH glyph)
1784 matty 7 {
1785 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
1786 matty 9 }
1787    
1788 matty 29 HCURSOR
1789 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1790     uint8 * andmask, uint8 * xormask)
1791 matty 9 {
1792 matty 29 HGLYPH maskglyph, cursorglyph;
1793     XColor bg, fg;
1794     Cursor xcursor;
1795     uint8 *cursor, *pcursor;
1796     uint8 *mask, *pmask;
1797     uint8 nextbit;
1798     int scanline, offset;
1799     int i, j;
1800    
1801     scanline = (width + 7) / 8;
1802     offset = scanline * height;
1803    
1804 forsberg 415 cursor = (uint8 *) xmalloc(offset);
1805 matty 29 memset(cursor, 0, offset);
1806    
1807 forsberg 415 mask = (uint8 *) xmalloc(offset);
1808 matty 29 memset(mask, 0, offset);
1809    
1810     /* approximate AND and XOR masks with a monochrome X pointer */
1811     for (i = 0; i < height; i++)
1812 matty 7 {
1813 matty 29 offset -= scanline;
1814     pcursor = &cursor[offset];
1815     pmask = &mask[offset];
1816    
1817     for (j = 0; j < scanline; j++)
1818 matty 28 {
1819 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1820     {
1821     if (xormask[0] || xormask[1] || xormask[2])
1822     {
1823     *pcursor |= (~(*andmask) & nextbit);
1824     *pmask |= nextbit;
1825     }
1826     else
1827     {
1828     *pcursor |= ((*andmask) & nextbit);
1829     *pmask |= (~(*andmask) & nextbit);
1830     }
1831    
1832     xormask += 3;
1833     }
1834    
1835     andmask++;
1836     pcursor++;
1837     pmask++;
1838 matty 28 }
1839 matty 7 }
1840 matty 29
1841     fg.red = fg.blue = fg.green = 0xffff;
1842     bg.red = bg.blue = bg.green = 0x0000;
1843     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1844    
1845     cursorglyph = ui_create_glyph(width, height, cursor);
1846     maskglyph = ui_create_glyph(width, height, mask);
1847    
1848 astrand 66 xcursor =
1849 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1850 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
1851 astrand 64
1852 matty 29 ui_destroy_glyph(maskglyph);
1853     ui_destroy_glyph(cursorglyph);
1854     xfree(mask);
1855     xfree(cursor);
1856 astrand 64 return (HCURSOR) xcursor;
1857 matty 29 }
1858    
1859     void
1860     ui_set_cursor(HCURSOR cursor)
1861     {
1862 jsorg71 450 g_current_cursor = (Cursor) cursor;
1863     XDefineCursor(g_display, g_wnd, g_current_cursor);
1864 matty 29 }
1865    
1866     void
1867     ui_destroy_cursor(HCURSOR cursor)
1868     {
1869 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
1870 matty 29 }
1871    
1872 astrand 508 void
1873     ui_set_null_cursor(void)
1874     {
1875     ui_set_cursor(g_null_cursor);
1876     }
1877    
1878 matty 29 #define MAKE_XCOLOR(xc,c) \
1879     (xc)->red = ((c)->red << 8) | (c)->red; \
1880     (xc)->green = ((c)->green << 8) | (c)->green; \
1881     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1882     (xc)->flags = DoRed | DoGreen | DoBlue;
1883    
1884 n-ki 279
1885 matty 29 HCOLOURMAP
1886 astrand 64 ui_create_colourmap(COLOURMAP * colours)
1887 matty 29 {
1888     COLOURENTRY *entry;
1889     int i, ncolours = colours->ncolours;
1890 jsorg71 450 if (!g_owncolmap)
1891 matty 28 {
1892 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1893 n-ki 279 XColor xentry;
1894     XColor xc_cache[256];
1895     uint32 colour;
1896     int colLookup = 256;
1897     for (i = 0; i < ncolours; i++)
1898 matty 28 {
1899 n-ki 279 entry = &colours->colours[i];
1900     MAKE_XCOLOR(&xentry, entry);
1901 matty 7
1902 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1903 astrand 196 {
1904 n-ki 279 /* Allocation failed, find closest match. */
1905     int j = 256;
1906     int nMinDist = 3 * 256 * 256;
1907     long nDist = nMinDist;
1908 matty 28
1909 n-ki 279 /* only get the colors once */
1910     while (colLookup--)
1911 astrand 196 {
1912 n-ki 279 xc_cache[colLookup].pixel = colLookup;
1913     xc_cache[colLookup].red = xc_cache[colLookup].green =
1914     xc_cache[colLookup].blue = 0;
1915     xc_cache[colLookup].flags = 0;
1916 jsorg71 450 XQueryColor(g_display,
1917     DefaultColormap(g_display,
1918     DefaultScreen(g_display)),
1919 n-ki 279 &xc_cache[colLookup]);
1920 n-ki 185 }
1921 n-ki 279 colLookup = 0;
1922    
1923     /* approximate the pixel */
1924     while (j--)
1925 astrand 196 {
1926 n-ki 279 if (xc_cache[j].flags)
1927     {
1928     nDist = ((long) (xc_cache[j].red >> 8) -
1929     (long) (xentry.red >> 8)) *
1930     ((long) (xc_cache[j].red >> 8) -
1931     (long) (xentry.red >> 8)) +
1932     ((long) (xc_cache[j].green >> 8) -
1933     (long) (xentry.green >> 8)) *
1934     ((long) (xc_cache[j].green >> 8) -
1935     (long) (xentry.green >> 8)) +
1936     ((long) (xc_cache[j].blue >> 8) -
1937     (long) (xentry.blue >> 8)) *
1938     ((long) (xc_cache[j].blue >> 8) -
1939     (long) (xentry.blue >> 8));
1940     }
1941     if (nDist < nMinDist)
1942     {
1943     nMinDist = nDist;
1944     xentry.pixel = j;
1945     }
1946 n-ki 185 }
1947     }
1948 n-ki 279 colour = xentry.pixel;
1949    
1950     /* update our cache */
1951     if (xentry.pixel < 256)
1952     {
1953     xc_cache[xentry.pixel].red = xentry.red;
1954     xc_cache[xentry.pixel].green = xentry.green;
1955     xc_cache[xentry.pixel].blue = xentry.blue;
1956    
1957     }
1958    
1959 matthewc 527 map[i] = colour;
1960 n-ki 185 }
1961 n-ki 279 return map;
1962     }
1963     else
1964     {
1965     XColor *xcolours, *xentry;
1966     Colormap map;
1967 matty 29
1968 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1969 n-ki 279 for (i = 0; i < ncolours; i++)
1970 astrand 196 {
1971 n-ki 279 entry = &colours->colours[i];
1972     xentry = &xcolours[i];
1973     xentry->pixel = i;
1974     MAKE_XCOLOR(xentry, entry);
1975 matty 29 }
1976    
1977 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1978     XStoreColors(g_display, map, xcolours, ncolours);
1979 n-ki 185
1980 n-ki 279 xfree(xcolours);
1981     return (HCOLOURMAP) map;
1982 matty 29 }
1983 matty 7 }
1984    
1985 matty 25 void
1986     ui_destroy_colourmap(HCOLOURMAP map)
1987 matty 7 {
1988 jsorg71 450 if (!g_owncolmap)
1989 n-ki 279 xfree(map);
1990     else
1991 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
1992 matty 7 }
1993    
1994 matty 25 void
1995     ui_set_colourmap(HCOLOURMAP map)
1996 matty 7 {
1997 jsorg71 450 if (!g_owncolmap)
1998 astrand 448 {
1999 jsorg71 450 if (g_colmap)
2000     xfree(g_colmap);
2001 astrand 448
2002 jsorg71 450 g_colmap = (uint32 *) map;
2003 astrand 448 }
2004 n-ki 279 else
2005 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
2006 matty 7 }
2007    
2008 matty 25 void
2009     ui_set_clip(int x, int y, int cx, int cy)
2010 matty 7 {
2011 matty 9 XRectangle rect;
2012 matty 7
2013 matty 9 rect.x = x;
2014     rect.y = y;
2015     rect.width = cx;
2016     rect.height = cy;
2017 jsorg71 450 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2018 matty 9 }
2019 matty 7
2020 matty 25 void
2021 matthewc 192 ui_reset_clip(void)
2022 matty 9 {
2023     XRectangle rect;
2024    
2025     rect.x = 0;
2026     rect.y = 0;
2027 jsorg71 447 rect.width = g_width;
2028     rect.height = g_height;
2029 jsorg71 450 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
2030 matty 7 }
2031    
2032 matty 25 void
2033 matthewc 192 ui_bell(void)
2034 matty 10 {
2035 jsorg71 450 XBell(g_display, 0);
2036 matty 10 }
2037    
2038 matty 25 void
2039     ui_destblt(uint8 opcode,
2040     /* dest */ int x, int y, int cx, int cy)
2041 matty 9 {
2042 matty 29 SET_FUNCTION(opcode);
2043 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2044 matty 29 RESET_FUNCTION(opcode);
2045 matty 9 }
2046    
2047 jsorg71 373 static uint8 hatch_patterns[] = {
2048 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
2049     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
2050     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
2051     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
2052     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
2053     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
2054 jsorg71 373 };
2055    
2056 matty 25 void
2057     ui_patblt(uint8 opcode,
2058     /* dest */ int x, int y, int cx, int cy,
2059 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2060 matty 9 {
2061     Pixmap fill;
2062 jsorg71 59 uint8 i, ipattern[8];
2063 matty 9
2064 matty 29 SET_FUNCTION(opcode);
2065 matty 9
2066     switch (brush->style)
2067     {
2068 matty 24 case 0: /* Solid */
2069 matty 29 SET_FOREGROUND(fgcolour);
2070 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2071 matty 9 break;
2072    
2073 jsorg71 373 case 2: /* Hatch */
2074 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
2075     hatch_patterns + brush->pattern[0] * 8);
2076 astrand 487 SET_FOREGROUND(fgcolour);
2077     SET_BACKGROUND(bgcolour);
2078 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2079     XSetStipple(g_display, g_gc, fill);
2080     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2081 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2082 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2083     XSetTSOrigin(g_display, g_gc, 0, 0);
2084 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
2085     break;
2086    
2087 matty 24 case 3: /* Pattern */
2088 jsorg71 59 for (i = 0; i != 8; i++)
2089     ipattern[7 - i] = brush->pattern[i];
2090     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2091 matty 29 SET_FOREGROUND(bgcolour);
2092     SET_BACKGROUND(fgcolour);
2093 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2094     XSetStipple(g_display, g_gc, fill);
2095     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2096 jsorg71 680 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2097 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2098     XSetTSOrigin(g_display, g_gc, 0, 0);
2099 astrand 64 ui_destroy_glyph((HGLYPH) fill);
2100 matty 9 break;
2101    
2102     default:
2103 matty 30 unimpl("brush %d\n", brush->style);
2104 matty 9 }
2105 matty 29
2106     RESET_FUNCTION(opcode);
2107 jsorg71 680
2108     if (g_ownbackstore)
2109     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2110 matty 9 }
2111    
2112 matty 25 void
2113     ui_screenblt(uint8 opcode,
2114     /* dest */ int x, int y, int cx, int cy,
2115     /* src */ int srcx, int srcy)
2116 matty 9 {
2117 matty 29 SET_FUNCTION(opcode);
2118 jsorg71 450 if (g_ownbackstore)
2119 stargo 609 {
2120 jsorg71 688 if (g_Unobscured)
2121     {
2122     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2123 astrand 691 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2124     y);
2125 jsorg71 688 }
2126     else
2127     {
2128     XCopyArea(g_display, g_backstore, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2129 astrand 691 XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x,
2130     y);
2131 jsorg71 688 }
2132 stargo 609 }
2133     else
2134     {
2135     XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2136     }
2137 matty 29 RESET_FUNCTION(opcode);
2138 matty 9 }
2139    
2140 matty 25 void
2141     ui_memblt(uint8 opcode,
2142     /* dest */ int x, int y, int cx, int cy,
2143     /* src */ HBITMAP src, int srcx, int srcy)
2144 matty 9 {
2145 matty 29 SET_FUNCTION(opcode);
2146 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
2147     if (g_ownbackstore)
2148     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
2149 matty 29 RESET_FUNCTION(opcode);
2150 matty 9 }
2151    
2152 matty 25 void
2153     ui_triblt(uint8 opcode,
2154     /* dest */ int x, int y, int cx, int cy,
2155     /* src */ HBITMAP src, int srcx, int srcy,
2156 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2157 matty 9 {
2158     /* This is potentially difficult to do in general. Until someone
2159 matty 10 comes up with a more efficient way of doing it I am using cases. */
2160 matty 9
2161     switch (opcode)
2162     {
2163 matty 24 case 0x69: /* PDSxxn */
2164 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
2165 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2166 matty 16 break;
2167    
2168 matty 24 case 0xb8: /* PSDPxax */
2169 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2170 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
2171 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
2172 matty 9 break;
2173    
2174 matty 29 case 0xc0: /* PSa */
2175 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2176 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
2177 matty 28 break;
2178    
2179 matty 9 default:
2180 matty 30 unimpl("triblt 0x%x\n", opcode);
2181 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
2182 matty 9 }
2183     }
2184    
2185 matty 25 void
2186     ui_line(uint8 opcode,
2187     /* dest */ int startx, int starty, int endx, int endy,
2188 astrand 64 /* pen */ PEN * pen)
2189 matty 9 {
2190 matty 29 SET_FUNCTION(opcode);
2191     SET_FOREGROUND(pen->colour);
2192 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
2193     if (g_ownbackstore)
2194     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
2195 matty 29 RESET_FUNCTION(opcode);
2196 matty 9 }
2197    
2198 matty 25 void
2199     ui_rect(
2200     /* dest */ int x, int y, int cx, int cy,
2201     /* brush */ int colour)
2202 matty 9 {
2203 matty 29 SET_FOREGROUND(colour);
2204 matty 31 FILL_RECTANGLE(x, y, cx, cy);
2205 matty 9 }
2206    
2207 jdmeijer 831 void
2208     ui_polygon(uint8 opcode,
2209     /* mode */ uint8 fillmode,
2210     /* dest */ POINT * point, int npoints,
2211     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2212     {
2213     uint8 style, i, ipattern[8];
2214     Pixmap fill;
2215    
2216     SET_FUNCTION(opcode);
2217    
2218     switch (fillmode)
2219     {
2220     case ALTERNATE:
2221     XSetFillRule(g_display, g_gc, EvenOddRule);
2222     break;
2223     case WINDING:
2224     XSetFillRule(g_display, g_gc, WindingRule);
2225     break;
2226     default:
2227     unimpl("fill mode %d\n", fillmode);
2228     }
2229    
2230     if (brush)
2231     style = brush->style;
2232     else
2233     style = 0;
2234    
2235     switch (style)
2236     {
2237     case 0: /* Solid */
2238     SET_FOREGROUND(fgcolour);
2239     FILL_POLYGON((XPoint *) point, npoints);
2240     break;
2241    
2242     case 2: /* Hatch */
2243     fill = (Pixmap) ui_create_glyph(8, 8,
2244     hatch_patterns + brush->pattern[0] * 8);
2245     SET_FOREGROUND(fgcolour);
2246     SET_BACKGROUND(bgcolour);
2247     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2248     XSetStipple(g_display, g_gc, fill);
2249     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2250     FILL_POLYGON((XPoint *) point, npoints);
2251     XSetFillStyle(g_display, g_gc, FillSolid);
2252     XSetTSOrigin(g_display, g_gc, 0, 0);
2253     ui_destroy_glyph((HGLYPH) fill);
2254     break;
2255    
2256     case 3: /* Pattern */
2257     for (i = 0; i != 8; i++)
2258     ipattern[7 - i] = brush->pattern[i];
2259     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2260     SET_FOREGROUND(bgcolour);
2261     SET_BACKGROUND(fgcolour);
2262     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2263     XSetStipple(g_display, g_gc, fill);
2264     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2265     FILL_POLYGON((XPoint *) point, npoints);
2266     XSetFillStyle(g_display, g_gc, FillSolid);
2267     XSetTSOrigin(g_display, g_gc, 0, 0);
2268     ui_destroy_glyph((HGLYPH) fill);
2269     break;
2270    
2271     default:
2272     unimpl("brush %d\n", brush->style);
2273     }
2274    
2275     RESET_FUNCTION(opcode);
2276     }
2277    
2278     void
2279 jdmeijer 844 ui_polyline(uint8 opcode,
2280     /* dest */ POINT * points, int npoints,
2281     /* pen */ PEN * pen)
2282     {
2283     /* TODO: set join style */
2284     SET_FUNCTION(opcode);
2285     SET_FOREGROUND(pen->colour);
2286     XDrawLines(g_display, g_wnd, g_gc, (XPoint *) points, npoints, CoordModePrevious);
2287     if (g_ownbackstore)
2288     XDrawLines(g_display, g_backstore, g_gc, (XPoint *) points, npoints,
2289     CoordModePrevious);
2290     RESET_FUNCTION(opcode);
2291     }
2292    
2293     void
2294 jdmeijer 831 ui_ellipse(uint8 opcode,
2295     /* mode */ uint8 fillmode,
2296     /* dest */ int x, int y, int cx, int cy,
2297     /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
2298     {
2299     uint8 style, i, ipattern[8];
2300     Pixmap fill;
2301    
2302     SET_FUNCTION(opcode);
2303    
2304     if (brush)
2305     style = brush->style;
2306     else
2307     style = 0;
2308    
2309     switch (style)
2310     {
2311     case 0: /* Solid */
2312     SET_FOREGROUND(fgcolour);
2313     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2314     break;
2315    
2316     case 2: /* Hatch */
2317     fill = (Pixmap) ui_create_glyph(8, 8,
2318     hatch_patterns + brush->pattern[0] * 8);
2319     SET_FOREGROUND(fgcolour);
2320     SET_BACKGROUND(bgcolour);
2321     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2322     XSetStipple(g_display, g_gc, fill);
2323     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2324     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2325     XSetFillStyle(g_display, g_gc, FillSolid);
2326     XSetTSOrigin(g_display, g_gc, 0, 0);
2327     ui_destroy_glyph((HGLYPH) fill);
2328     break;
2329    
2330     case 3: /* Pattern */
2331     for (i = 0; i != 8; i++)
2332     ipattern[7 - i] = brush->pattern[i];
2333     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
2334     SET_FOREGROUND(bgcolour);
2335     SET_BACKGROUND(fgcolour);
2336     XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
2337     XSetStipple(g_display, g_gc, fill);
2338     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
2339     DRAW_ELLIPSE(x, y, cx, cy, fillmode);
2340     XSetFillStyle(g_display, g_gc, FillSolid);
2341     XSetTSOrigin(g_display, g_gc, 0, 0);
2342     ui_destroy_glyph((HGLYPH) fill);
2343     break;
2344    
2345     default:
2346     unimpl("brush %d\n", brush->style);
2347     }
2348    
2349     RESET_FUNCTION(opcode);
2350     }
2351    
2352 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
2353 matty 25 void
2354     ui_draw_glyph(int mixmode,
2355     /* dest */ int x, int y, int cx, int cy,
2356 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
2357     int bgcolour, int fgcolour)
2358 matty 9 {
2359 matty 29 SET_FOREGROUND(fgcolour);
2360     SET_BACKGROUND(bgcolour);
2361 matty 9
2362 jsorg71 450 XSetFillStyle(g_display, g_gc,
2363 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
2364 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
2365     XSetTSOrigin(g_display, g_gc, x, y);
2366 matty 9
2367 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
2368 matty 9
2369 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
2370 matty 9 }
2371    
2372 mmihalik 49 #define DO_GLYPH(ttext,idx) \
2373     {\
2374     glyph = cache_get_font (font, ttext[idx]);\
2375     if (!(flags & TEXT2_IMPLICIT_X))\
2376 jsorg71 564 {\
2377     xyoffset = ttext[++idx];\
2378     if ((xyoffset & 0x80))\
2379 mmihalik 49 {\
2380 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2381     y += ttext[idx+1] | (ttext[idx+2] << 8);\
2382 mmihalik 49 else\
2383 jsorg71 564 x += ttext[idx+1] | (ttext[idx+2] << 8);\
2384     idx += 2;\
2385 mmihalik 49 }\
2386 jsorg71 564 else\
2387 mmihalik 49 {\
2388 jsorg71 564 if (flags & TEXT2_VERTICAL)\
2389     y += xyoffset;\
2390     else\
2391     x += xyoffset;\
2392 mmihalik 49 }\
2393 jsorg71 564 }\
2394     if (glyph != NULL)\
2395     {\
2396     x1 = x + glyph->offset;\
2397     y1 = y + glyph->baseline;\
2398     XSetStipple(g_display, g_gc, (Pixmap) glyph->pixmap);\
2399     XSetTSOrigin(g_display, g_gc, x1, y1);\
2400     FILL_RECTANGLE_BACKSTORE(x1, y1, glyph->width, glyph->height);\
2401     if (flags & TEXT2_IMPLICIT_X)\
2402     x += glyph->width;\
2403     }\
2404 mmihalik 49 }
2405    
2406 matty 25 void
2407 jdmeijer 843 ui_draw_text(uint8 font, uint8 flags, uint8 opcode, int mixmode, int x, int y,
2408 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
2409 jdmeijer 843 int boxx, int boxy, int boxcx, int boxcy, BRUSH * brush,
2410     int bgcolour, int fgcolour, uint8 * text, uint8 length)
2411 matty 9 {
2412 jdmeijer 843 /* TODO: use brush appropriately */
2413    
2414 matty 10 FONTGLYPH *glyph;
2415 jsorg71 564 int i, j, xyoffset, x1, y1;
2416 mmihalik 49 DATABLOB *entry;
2417 matty 9
2418 matty 29 SET_FOREGROUND(bgcolour);
2419 matty 28
2420 astrand 620 /* Sometimes, the boxcx value is something really large, like
2421     32691. This makes XCopyArea fail with Xvnc. The code below
2422     is a quick fix. */
2423     if (boxx + boxcx > g_width)
2424     boxcx = g_width - boxx;
2425    
2426 matty 9 if (boxcx > 1)
2427 matty 31 {
2428 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
2429 matty 31 }
2430 matty 17 else if (mixmode == MIX_OPAQUE)
2431 matty 31 {
2432 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
2433 matty 31 }
2434 matty 9
2435 jsorg71 564 SET_FOREGROUND(fgcolour);
2436     SET_BACKGROUND(bgcolour);
2437     XSetFillStyle(g_display, g_gc, FillStippled);
2438    
2439 matty 9 /* Paint text, character by character */
2440 astrand 64 for (i = 0; i < length;)
2441     {
2442     switch (text[i])
2443     {
2444     case 0xff:
2445     if (i + 2 < length)
2446 astrand 82 cache_put_text(text[i + 1], text, text[i + 2]);
2447 astrand 64 else
2448     {
2449     error("this shouldn't be happening\n");
2450 astrand 265 exit(1);
2451 astrand 64 }
2452     /* this will move pointer from start to first character after FF command */
2453     length -= i + 3;
2454     text = &(text[i + 3]);
2455     i = 0;
2456 mmihalik 49 break;
2457 matty 9
2458 astrand 64 case 0xfe:
2459     entry = cache_get_text(text[i + 1]);
2460     if (entry != NULL)
2461     {
2462     if ((((uint8 *) (entry->data))[1] ==
2463 astrand 82 0) && (!(flags & TEXT2_IMPLICIT_X)))
2464 astrand 64 {
2465     if (flags & TEXT2_VERTICAL)
2466     y += text[i + 2];
2467     else
2468     x += text[i + 2];
2469     }
2470     for (j = 0; j < entry->size; j++)
2471 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
2472 matthewc 44 }
2473 jsorg71 286 if (i + 2 < length)
2474     i += 3;
2475     else
2476     i += 2;
2477     length -= i;
2478     /* this will move pointer from start to first character after FE command */
2479     text = &(text[i]);
2480     i = 0;
2481 astrand 64 break;
2482 matty 17
2483 astrand 64 default:
2484     DO_GLYPH(text, i);
2485     i++;
2486     break;
2487 matty 29 }
2488 mmihalik 49 }
2489 jsorg71 564
2490     XSetFillStyle(g_display, g_gc, FillSolid);
2491    
2492 jsorg71 450 if (g_ownbackstore)
2493 jsorg71 278 {
2494     if (boxcx > 1)
2495 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
2496 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
2497     else
2498 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
2499 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
2500     }
2501 matty 9 }
2502    
2503 matty 25 void
2504     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
2505 matty 9 {
2506 matty 28 Pixmap pix;
2507 matty 9 XImage *image;
2508    
2509 jsorg71 450 if (g_ownbackstore)
2510 matty 31 {
2511 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
2512 matty 31 }
2513     else
2514     {
2515 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
2516     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
2517     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
2518     XFreePixmap(g_display, pix);
2519 matty 31 }
2520 matty 28
2521 jsorg71 450 offset *= g_bpp / 8;
2522     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
2523 matty 28
2524     XDestroyImage(image);
2525 matty 9 }
2526    
2527 matty 25 void
2528     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
2529 matty 9 {
2530     XImage *image;
2531 matty 10 uint8 *data;
2532 matty 9
2533 jsorg71 450 offset *= g_bpp / 8;
2534     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
2535 matty 10 if (data == NULL)
2536     return;
2537 matty 29
2538 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
2539     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
2540 matty 29
2541 jsorg71 450 if (g_ownbackstore)
2542 matty 31 {
2543 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
2544     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
2545 matty 31 }
2546     else
2547     {
2548 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
2549 matty 31 }
2550    
2551 matty 9 XFree(image);
2552     }
2553 jsorg71 713
2554     /* these do nothing here but are used in uiports */
2555     void
2556     ui_begin_update(void)
2557     {
2558     }
2559    
2560     void
2561     ui_end_update(void)
2562     {
2563     }

  ViewVC Help
Powered by ViewVC 1.1.26