/[rdesktop]/sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/branches/seamlessrdp-branch/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 822 - (hide annotations)
Mon Feb 28 22:38:24 2005 UTC (19 years, 2 months ago) by stargo
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 51773 byte(s)
compile fix for older gcc

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

  ViewVC Help
Powered by ViewVC 1.1.26