/[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 470 - (hide annotations)
Mon Sep 15 08:03:30 2003 UTC (20 years, 8 months ago) by astrand
Original Path: sourceforge.net/trunk/rdesktop/xwin.c
File MIME type: text/plain
File size: 39947 byte(s)
Kbd fix: Shift was always reset after press

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 matty 10 #include <time.h>
24 matty 33 #include <errno.h>
25 matty 10 #include "rdesktop.h"
26 forsberg 415 #include "xproto.h"
27 matty 6
28 jsorg71 447 extern int g_width;
29     extern int g_height;
30     extern BOOL g_sendmotion;
31     extern BOOL g_fullscreen;
32 jsorg71 450 extern BOOL g_grab_keyboard;
33     extern BOOL g_hide_decorations;
34     extern char g_title[];
35 jsorg71 438 extern int g_server_bpp;
36 jsorg71 450 extern int g_win_button_size;
37 jsorg71 447 BOOL g_enable_compose = False;
38     BOOL g_focused;
39     BOOL g_mouse_in_wnd;
40 matty 10
41 jsorg71 450 Display *g_display;
42     Time g_last_gesturetime;
43     static int g_x_socket;
44     static Screen *g_screen;
45     Window g_wnd;
46     static GC g_gc;
47     static Visual *g_visual;
48     static int g_depth;
49     static int g_bpp;
50     static XIM g_IM;
51     static XIC g_IC;
52     static XModifierKeymap *g_mod_map;
53     static Cursor g_current_cursor;
54     static Atom g_protocol_atom, g_kill_atom;
55 matty 29
56 matty 33 /* endianness */
57 jsorg71 450 static BOOL g_host_be;
58     static BOOL g_xserver_be;
59 matty 33
60     /* software backing store */
61 jsorg71 450 static BOOL g_ownbackstore;
62     static Pixmap g_backstore;
63 matty 31
64 astrand 342 /* Moving in single app mode */
65 jsorg71 450 static BOOL g_moving_wnd;
66     static int g_move_x_offset = 0;
67     static int g_move_y_offset = 0;
68 astrand 342
69 astrand 262 /* MWM decorations */
70     #define MWM_HINTS_DECORATIONS (1L << 1)
71     #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
72     typedef struct
73     {
74 matthewc 301 uint32 flags;
75     uint32 functions;
76     uint32 decorations;
77     sint32 inputMode;
78     uint32 status;
79 astrand 262 }
80     PropMotifWmHints;
81    
82 jsorg71 316 typedef struct
83     {
84     uint32 red;
85     uint32 green;
86     uint32 blue;
87     }
88     PixelColour;
89 astrand 262
90 forsberg 415
91 matty 31 #define FILL_RECTANGLE(x,y,cx,cy)\
92     { \
93 jsorg71 450 XFillRectangle(g_display, g_wnd, g_gc, x, y, cx, cy); \
94     if (g_ownbackstore) \
95     XFillRectangle(g_display, g_backstore, g_gc, x, y, cx, cy); \
96 matty 31 }
97    
98 matthewc 296 #define FILL_RECTANGLE_BACKSTORE(x,y,cx,cy)\
99 jsorg71 281 { \
100 jsorg71 450 XFillRectangle(g_display, g_ownbackstore ? g_backstore : g_wnd, g_gc, x, y, cx, cy); \
101 jsorg71 281 }
102    
103 matty 33 /* colour maps */
104 jsorg71 450 BOOL g_owncolmap = False;
105     static Colormap g_xcolmap;
106     static uint32 *g_colmap = NULL;
107 matty 10
108 jsorg71 450 #define TRANSLATE(col) ( g_server_bpp != 8 ? translate_colour(col) : g_owncolmap ? col : translate_colour(g_colmap[col]) )
109     #define SET_FOREGROUND(col) XSetForeground(g_display, g_gc, TRANSLATE(col));
110     #define SET_BACKGROUND(col) XSetBackground(g_display, g_gc, TRANSLATE(col));
111 matty 28
112     static int rop2_map[] = {
113     GXclear, /* 0 */
114     GXnor, /* DPon */
115     GXandInverted, /* DPna */
116     GXcopyInverted, /* Pn */
117     GXandReverse, /* PDna */
118     GXinvert, /* Dn */
119     GXxor, /* DPx */
120     GXnand, /* DPan */
121     GXand, /* DPa */
122     GXequiv, /* DPxn */
123     GXnoop, /* D */
124     GXorInverted, /* DPno */
125     GXcopy, /* P */
126     GXorReverse, /* PDno */
127     GXor, /* DPo */
128     GXset /* 1 */
129     };
130    
131 jsorg71 450 #define SET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, rop2_map[rop2]); }
132     #define RESET_FUNCTION(rop2) { if (rop2 != ROP2_COPY) XSetFunction(g_display, g_gc, GXcopy); }
133 matty 29
134 astrand 319 static void
135 astrand 262 mwm_hide_decorations(void)
136     {
137     PropMotifWmHints motif_hints;
138     Atom hintsatom;
139    
140     /* setup the property */
141     motif_hints.flags = MWM_HINTS_DECORATIONS;
142     motif_hints.decorations = 0;
143    
144     /* get the atom for the property */
145 jsorg71 450 hintsatom = XInternAtom(g_display, "_MOTIF_WM_HINTS", False);
146 astrand 262 if (!hintsatom)
147     {
148 matthewc 297 warning("Failed to get atom _MOTIF_WM_HINTS: probably your window manager does not support MWM hints\n");
149 astrand 262 return;
150     }
151    
152 jsorg71 450 XChangeProperty(g_display, g_wnd, hintsatom, hintsatom, 32, PropModeReplace,
153 astrand 262 (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
154     }
155    
156 astrand 319 static PixelColour
157 jsorg71 316 split_colour15(uint32 colour)
158 jsorg71 311 {
159 jsorg71 316 PixelColour rv;
160     rv.red = (colour & 0x7c00) >> 10;
161     rv.red = (rv.red * 0xff) / 0x1f;
162     rv.green = (colour & 0x03e0) >> 5;
163     rv.green = (rv.green * 0xff) / 0x1f;
164     rv.blue = (colour & 0x1f);
165     rv.blue = (rv.blue * 0xff) / 0x1f;
166     return rv;
167 jsorg71 311 }
168    
169 astrand 319 static PixelColour
170 jsorg71 316 split_colour16(uint32 colour)
171 jsorg71 311 {
172 jsorg71 316 PixelColour rv;
173     rv.red = (colour & 0xf800) >> 11;
174     rv.red = (rv.red * 0xff) / 0x1f;
175     rv.green = (colour & 0x07e0) >> 5;
176     rv.green = (rv.green * 0xff) / 0x3f;
177     rv.blue = (colour & 0x001f);
178     rv.blue = (rv.blue * 0xff) / 0x1f;
179     return rv;
180 jsorg71 311 }
181    
182 astrand 319 static PixelColour
183 jsorg71 316 split_colour24(uint32 colour)
184 jsorg71 311 {
185 jsorg71 316 PixelColour rv;
186     rv.blue = (colour & 0xff0000) >> 16;
187     rv.green = (colour & 0xff00) >> 8;
188     rv.red = (colour & 0xff);
189     return rv;
190 jsorg71 311 }
191    
192 astrand 319 static uint32
193 astrand 318 make_colour16(PixelColour pc)
194 jsorg71 316 {
195     pc.red = (pc.red * 0x1f) / 0xff;
196     pc.green = (pc.green * 0x3f) / 0xff;
197     pc.blue = (pc.blue * 0x1f) / 0xff;
198     return (pc.red << 11) | (pc.green << 5) | pc.blue;
199     }
200    
201 astrand 319 static uint32
202 astrand 318 make_colour24(PixelColour pc)
203 jsorg71 316 {
204     return (pc.red << 16) | (pc.green << 8) | pc.blue;
205     }
206    
207 astrand 319 static uint32
208 astrand 318 make_colour32(PixelColour pc)
209 jsorg71 316 {
210     return (pc.red << 16) | (pc.green << 8) | pc.blue;
211     }
212    
213 jsorg71 311 #define BSWAP16(x) { x = (((x & 0xff) << 8) | (x >> 8)); }
214     #define BSWAP24(x) { x = (((x & 0xff) << 16) | (x >> 16) | ((x >> 8) & 0xff00)); }
215     #define BSWAP32(x) { x = (((x & 0xff00ff) << 8) | ((x >> 8) & 0xff00ff)); \
216     x = (x << 16) | (x >> 16); }
217    
218     static uint32
219     translate_colour(uint32 colour)
220     {
221 jsorg71 438 switch (g_server_bpp)
222 jsorg71 311 {
223 jsorg71 316 case 15:
224 jsorg71 450 switch (g_bpp)
225 jsorg71 316 {
226     case 16:
227     colour = make_colour16(split_colour15(colour));
228     break;
229     case 24:
230     colour = make_colour24(split_colour15(colour));
231     break;
232     case 32:
233     colour = make_colour32(split_colour15(colour));
234     break;
235     }
236     break;
237 jsorg71 311 case 16:
238 jsorg71 450 switch (g_bpp)
239 jsorg71 311 {
240     case 16:
241     break;
242     case 24:
243 jsorg71 316 colour = make_colour24(split_colour16(colour));
244 jsorg71 311 break;
245     case 32:
246 jsorg71 316 colour = make_colour32(split_colour16(colour));
247 jsorg71 311 break;
248     }
249     break;
250     case 24:
251 jsorg71 450 switch (g_bpp)
252 jsorg71 311 {
253 jsorg71 316 case 16:
254     colour = make_colour16(split_colour24(colour));
255     break;
256 jsorg71 311 case 24:
257     break;
258     case 32:
259 jsorg71 316 colour = make_colour32(split_colour24(colour));
260 jsorg71 311 break;
261     }
262     break;
263     }
264 jsorg71 450 switch (g_bpp)
265 jsorg71 311 {
266     case 16:
267 jsorg71 450 if (g_host_be != g_xserver_be)
268 jsorg71 311 BSWAP16(colour);
269     break;
270    
271     case 24:
272 jsorg71 450 if (g_xserver_be)
273 jsorg71 311 BSWAP24(colour);
274     break;
275    
276     case 32:
277 jsorg71 450 if (g_host_be != g_xserver_be)
278 jsorg71 311 BSWAP32(colour);
279     break;
280     }
281    
282     return colour;
283     }
284    
285 matty 28 static void
286 jsorg71 311 translate8to8(uint8 * data, uint8 * out, uint8 * end)
287 matty 28 {
288 matty 29 while (out < end)
289 jsorg71 450 *(out++) = (uint8) g_colmap[*(data++)];
290 matty 29 }
291 matty 28
292 matty 29 static void
293 jsorg71 311 translate8to16(uint8 * data, uint16 * out, uint16 * end)
294 matty 29 {
295     while (out < end)
296 jsorg71 450 *(out++) = (uint16) g_colmap[*(data++)];
297 matty 29 }
298    
299 jsorg71 316 /* little endian - conversion happens when colourmap is built */
300 jsorg71 311 static void
301 jsorg71 316 translate8to24(uint8 * data, uint8 * out, uint8 * end)
302 jsorg71 311 {
303 jsorg71 316 uint32 value;
304    
305 jsorg71 311 while (out < end)
306 jsorg71 316 {
307 jsorg71 450 value = g_colmap[*(data++)];
308 jsorg71 316 *(out++) = value;
309     *(out++) = value >> 8;
310     *(out++) = value >> 16;
311     }
312 jsorg71 311 }
313    
314 matty 29 static void
315 jsorg71 316 translate8to32(uint8 * data, uint32 * out, uint32 * end)
316 matty 29 {
317 jsorg71 316 while (out < end)
318 jsorg71 450 *(out++) = g_colmap[*(data++)];
319 jsorg71 316 }
320    
321     /* todo the remaining translate function might need some big endian check ?? */
322    
323     static void
324     translate15to16(uint16 * data, uint16 * out, uint16 * end)
325     {
326     while (out < end)
327     *(out++) = (uint16) make_colour16(split_colour15(*(data++)));
328     }
329    
330     static void
331     translate15to24(uint16 * data, uint8 * out, uint8 * end)
332     {
333 matty 29 uint32 value;
334    
335     while (out < end)
336 matty 28 {
337 jsorg71 316 value = make_colour24(split_colour15(*(data++)));
338 matty 29 *(out++) = value;
339     *(out++) = value >> 8;
340     *(out++) = value >> 16;
341 matty 28 }
342     }
343    
344     static void
345 jsorg71 316 translate15to32(uint16 * data, uint32 * out, uint32 * end)
346     {
347     while (out < end)
348     *(out++) = make_colour32(split_colour15(*(data++)));
349     }
350    
351     static void
352     translate16to16(uint16 * data, uint16 * out, uint16 * end)
353     {
354     while (out < end)
355     *(out++) = (uint16) (*(data++));
356     }
357    
358    
359     static void
360 jsorg71 311 translate16to24(uint16 * data, uint8 * out, uint8 * end)
361 matty 28 {
362 jsorg71 311 uint32 value;
363    
364 matty 29 while (out < end)
365 jsorg71 311 {
366 jsorg71 316 value = make_colour24(split_colour16(*(data++)));
367 jsorg71 311 *(out++) = value;
368     *(out++) = value >> 8;
369     *(out++) = value >> 16;
370     }
371     }
372    
373     static void
374 jsorg71 316 translate16to32(uint16 * data, uint32 * out, uint32 * end)
375 jsorg71 311 {
376     while (out < end)
377 jsorg71 316 *(out++) = make_colour32(split_colour16(*(data++)));
378 matty 28 }
379    
380 jsorg71 311 static void
381 jsorg71 316 translate24to16(uint8 * data, uint16 * out, uint16 * end)
382 jsorg71 311 {
383 jsorg71 316 uint32 pixel = 0;
384 jsorg71 311 while (out < end)
385 jsorg71 316 {
386     pixel = *(data++) << 16;
387     pixel |= *(data++) << 8;
388     pixel |= *(data++);
389     *(out++) = (uint16) make_colour16(split_colour24(pixel));
390     }
391 jsorg71 311 }
392    
393 jsorg71 316 static void
394     translate24to24(uint8 * data, uint8 * out, uint8 * end)
395     {
396     while (out < end)
397     {
398     *(out++) = (*(data++));
399     }
400     }
401    
402     static void
403     translate24to32(uint8 * data, uint32 * out, uint32 * end)
404     {
405     uint32 pixel = 0;
406     while (out < end)
407     {
408 matthewc 368 pixel = *(data++);
409     pixel |= *(data++) << 8;
410     pixel |= *(data++) << 16;
411 jsorg71 316 *(out++) = pixel;
412     }
413     }
414    
415 matty 29 static uint8 *
416 astrand 64 translate_image(int width, int height, uint8 * data)
417 matty 28 {
418 jsorg71 450 int size = width * height * g_bpp / 8;
419 forsberg 415 uint8 *out = (uint8 *) xmalloc(size);
420 matty 29 uint8 *end = out + size;
421    
422 jsorg71 438 switch (g_server_bpp)
423 jsorg71 311 {
424 jsorg71 316 case 24:
425 jsorg71 450 switch (g_bpp)
426 jsorg71 316 {
427     case 32:
428     translate24to32(data, (uint32 *) out, (uint32 *) end);
429     break;
430     case 24:
431     translate24to24(data, out, end);
432     break;
433     case 16:
434     translate24to16(data, (uint16 *) out, (uint16 *) end);
435     break;
436     }
437 matty 29 break;
438     case 16:
439 jsorg71 450 switch (g_bpp)
440 jsorg71 316 {
441     case 32:
442 astrand 318 translate16to32((uint16 *) data, (uint32 *) out,
443     (uint32 *) end);
444 jsorg71 316 break;
445     case 24:
446     translate16to24((uint16 *) data, out, end);
447     break;
448     case 16:
449 astrand 318 translate16to16((uint16 *) data, (uint16 *) out,
450     (uint16 *) end);
451 jsorg71 316 break;
452     }
453 matty 29 break;
454 jsorg71 316 case 15:
455 jsorg71 450 switch (g_bpp)
456 jsorg71 316 {
457     case 32:
458 astrand 318 translate15to32((uint16 *) data, (uint32 *) out,
459     (uint32 *) end);
460 jsorg71 316 break;
461     case 24:
462     translate15to24((uint16 *) data, out, end);
463     break;
464     case 16:
465 astrand 318 translate15to16((uint16 *) data, (uint16 *) out,
466     (uint16 *) end);
467 jsorg71 316 break;
468     }
469 matty 29 break;
470 jsorg71 316 case 8:
471 jsorg71 450 switch (g_bpp)
472 jsorg71 316 {
473     case 8:
474     translate8to8(data, out, end);
475     break;
476     case 16:
477     translate8to16(data, (uint16 *) out, (uint16 *) end);
478     break;
479     case 24:
480     translate8to24(data, out, end);
481     break;
482     case 32:
483     translate8to32(data, (uint32 *) out, (uint32 *) end);
484     break;
485     }
486 matty 29 break;
487     }
488     return out;
489 matty 28 }
490    
491 astrand 118 BOOL
492 matthewc 209 get_key_state(unsigned int state, uint32 keysym)
493 astrand 102 {
494 matthewc 203 int modifierpos, key, keysymMask = 0;
495 astrand 102 int offset;
496    
497 jsorg71 450 KeyCode keycode = XKeysymToKeycode(g_display, keysym);
498 astrand 102
499     if (keycode == NoSymbol)
500     return False;
501    
502     for (modifierpos = 0; modifierpos < 8; modifierpos++)
503     {
504 jsorg71 450 offset = g_mod_map->max_keypermod * modifierpos;
505 astrand 102
506 jsorg71 450 for (key = 0; key < g_mod_map->max_keypermod; key++)
507 astrand 102 {
508 jsorg71 450 if (g_mod_map->modifiermap[offset + key] == keycode)
509 matthewc 203 keysymMask |= 1 << modifierpos;
510 astrand 102 }
511     }
512    
513 matthewc 203 return (state & keysymMask) ? True : False;
514 astrand 102 }
515    
516 jsorg71 81 BOOL
517 matthewc 192 ui_init(void)
518 jsorg71 81 {
519 matthewc 121 XPixmapFormatValues *pfm;
520     uint16 test;
521     int i;
522    
523 jsorg71 450 g_display = XOpenDisplay(NULL);
524     if (g_display == NULL)
525 jsorg71 81 {
526 matthewc 210 error("Failed to open display: %s\n", XDisplayName(NULL));
527 jsorg71 81 return False;
528     }
529 matthewc 121
530 jsorg71 450 g_x_socket = ConnectionNumber(g_display);
531     g_screen = DefaultScreenOfDisplay(g_display);
532     g_visual = DefaultVisualOfScreen(g_screen);
533     g_depth = DefaultDepthOfScreen(g_screen);
534 matthewc 121
535 jsorg71 450 pfm = XListPixmapFormats(g_display, &i);
536 matthewc 121 if (pfm != NULL)
537     {
538     /* Use maximum bpp for this depth - this is generally
539     desirable, e.g. 24 bits->32 bits. */
540     while (i--)
541     {
542 jsorg71 450 if ((pfm[i].depth == g_depth) && (pfm[i].bits_per_pixel > g_bpp))
543 matthewc 121 {
544 jsorg71 450 g_bpp = pfm[i].bits_per_pixel;
545 matthewc 121 }
546     }
547     XFree(pfm);
548     }
549    
550 jsorg71 450 if (g_bpp < 8)
551 matthewc 121 {
552     error("Less than 8 bpp not currently supported.\n");
553 jsorg71 450 XCloseDisplay(g_display);
554 matthewc 121 return False;
555     }
556    
557 jsorg71 450 if (g_owncolmap != True)
558 n-ki 279 {
559 jsorg71 450 g_xcolmap = DefaultColormapOfScreen(g_screen);
560     if (g_depth <= 8)
561 matthewc 297 warning("Screen depth is 8 bits or lower: you may want to use -C for a private colourmap\n");
562 n-ki 279 }
563    
564 jsorg71 450 g_gc = XCreateGC(g_display, RootWindowOfScreen(g_screen), 0, NULL);
565 matthewc 121
566 jsorg71 450 if (DoesBackingStore(g_screen) != Always)
567     g_ownbackstore = True;
568 matthewc 121
569     test = 1;
570 jsorg71 450 g_host_be = !(BOOL) (*(uint8 *) (&test));
571     g_xserver_be = (ImageByteOrder(g_display) == MSBFirst);
572 matthewc 121
573 jsorg71 447 if ((g_width == 0) || (g_height == 0))
574 astrand 263 {
575     /* Fetch geometry from _NET_WORKAREA */
576 matthewc 300 uint32 x, y, cx, cy;
577 astrand 263
578 matthewc 300 if (get_current_workarea(&x, &y, &cx, &cy) == 0)
579 astrand 263 {
580 jsorg71 447 g_width = cx;
581     g_height = cy;
582 matthewc 300 }
583     else
584     {
585 matthewc 297 warning("Failed to get workarea: probably your window manager does not support extended hints\n");
586 jsorg71 447 g_width = 800;
587     g_height = 600;
588 astrand 263 }
589     }
590    
591 jsorg71 447 if (g_fullscreen)
592 jsorg71 81 {
593 jsorg71 450 g_width = WidthOfScreen(g_screen);
594     g_height = HeightOfScreen(g_screen);
595 jsorg71 81 }
596 matthewc 121
597 matthewc 160 /* make sure width is a multiple of 4 */
598 jsorg71 447 g_width = (g_width + 3) & ~3;
599 matthewc 160
600 jsorg71 450 if (g_ownbackstore)
601 matthewc 188 {
602 jsorg71 450 g_backstore =
603     XCreatePixmap(g_display, RootWindowOfScreen(g_screen), g_width, g_height,
604     g_depth);
605 matthewc 188
606     /* clear to prevent rubbish being exposed at startup */
607 jsorg71 450 XSetForeground(g_display, g_gc, BlackPixelOfScreen(g_screen));
608     XFillRectangle(g_display, g_backstore, g_gc, 0, 0, g_width, g_height);
609 matthewc 188 }
610    
611 jsorg71 450 g_mod_map = XGetModifierMapping(g_display);
612 matthewc 203
613 jsorg71 447 if (g_enable_compose)
614 jsorg71 450 g_IM = XOpenIM(g_display, NULL, NULL, NULL);
615 matthewc 188
616 matthewc 121 xkeymap_init();
617 matthewc 432 xclip_init();
618 jsorg71 316
619     /* todo take this out when high colour is done */
620 jsorg71 450 printf("server bpp %d client bpp %d depth %d\n", g_server_bpp, g_bpp, g_depth);
621 jsorg71 316
622 jsorg71 81 return True;
623     }
624 astrand 66
625 matthewc 188 void
626 matthewc 192 ui_deinit(void)
627 matthewc 188 {
628 jsorg71 450 if (g_IM != NULL)
629     XCloseIM(g_IM);
630 matthewc 188
631 jsorg71 450 XFreeModifiermap(g_mod_map);
632 matthewc 203
633 jsorg71 450 if (g_ownbackstore)
634     XFreePixmap(g_display, g_backstore);
635 matthewc 188
636 jsorg71 450 XFreeGC(g_display, g_gc);
637     XCloseDisplay(g_display);
638     g_display = NULL;
639 matthewc 188 }
640    
641 matthewc 121 BOOL
642 matthewc 192 ui_create_window(void)
643 matty 6 {
644 matthewc 121 XSetWindowAttributes attribs;
645 matty 28 XClassHint *classhints;
646     XSizeHints *sizehints;
647 matthewc 188 int wndwidth, wndheight;
648 matthewc 432 long input_mask, ic_input_mask;
649 jsorg71 100 XEvent xevent;
650    
651 jsorg71 450 wndwidth = g_fullscreen ? WidthOfScreen(g_screen) : g_width;
652     wndheight = g_fullscreen ? HeightOfScreen(g_screen) : g_height;
653 matthewc 188
654 jsorg71 450 attribs.background_pixel = BlackPixelOfScreen(g_screen);
655     attribs.backing_store = g_ownbackstore ? NotUseful : Always;
656 jsorg71 447 attribs.override_redirect = g_fullscreen;
657 matthewc 188
658 jsorg71 450 g_wnd = XCreateWindow(g_display, RootWindowOfScreen(g_screen), 0, 0, wndwidth, wndheight,
659 astrand 456 0, CopyFromParent, InputOutput, CopyFromParent,
660     CWBackPixel | CWBackingStore | CWOverrideRedirect, &attribs);
661 jsorg71 100
662 jsorg71 450 XStoreName(g_display, g_wnd, g_title);
663 jsorg71 100
664 jsorg71 450 if (g_hide_decorations)
665 astrand 262 mwm_hide_decorations();
666    
667 jsorg71 100 classhints = XAllocClassHint();
668     if (classhints != NULL)
669     {
670     classhints->res_name = classhints->res_class = "rdesktop";
671 jsorg71 450 XSetClassHint(g_display, g_wnd, classhints);
672 jsorg71 100 XFree(classhints);
673     }
674    
675     sizehints = XAllocSizeHints();
676     if (sizehints)
677     {
678     sizehints->flags = PMinSize | PMaxSize;
679 jsorg71 447 sizehints->min_width = sizehints->max_width = g_width;
680     sizehints->min_height = sizehints->max_height = g_height;
681 jsorg71 450 XSetWMNormalHints(g_display, g_wnd, sizehints);
682 jsorg71 100 XFree(sizehints);
683     }
684    
685 matthewc 121 input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
686 jsorg71 257 VisibilityChangeMask | FocusChangeMask;
687 matthewc 121
688 jsorg71 447 if (g_sendmotion)
689 matthewc 121 input_mask |= PointerMotionMask;
690 jsorg71 450 if (g_ownbackstore)
691 matthewc 121 input_mask |= ExposureMask;
692 jsorg71 450 if (g_fullscreen || g_grab_keyboard)
693 matthewc 250 input_mask |= EnterWindowMask;
694 jsorg71 450 if (g_grab_keyboard)
695 jsorg71 257 input_mask |= LeaveWindowMask;
696 jsorg71 100
697 jsorg71 450 if (g_IM != NULL)
698 matthewc 188 {
699 jsorg71 450 g_IC = XCreateIC(g_IM, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing),
700 astrand 456 XNClientWindow, g_wnd, XNFocusWindow, g_wnd, NULL);
701 matthewc 188
702 jsorg71 450 if ((g_IC != NULL)
703     && (XGetICValues(g_IC, XNFilterEvents, &ic_input_mask, NULL) == NULL))
704 matthewc 188 input_mask |= ic_input_mask;
705     }
706    
707 jsorg71 450 XSelectInput(g_display, g_wnd, input_mask);
708     XMapWindow(g_display, g_wnd);
709 jsorg71 100
710 matthewc 208 /* wait for VisibilityNotify */
711 astrand 196 do
712     {
713 jsorg71 450 XMaskEvent(g_display, VisibilityChangeMask, &xevent);
714 astrand 196 }
715 matthewc 208 while (xevent.type != VisibilityNotify);
716 matthewc 123
717 jsorg71 447 g_focused = False;
718     g_mouse_in_wnd = False;
719 jsorg71 257
720 astrand 275 /* handle the WM_DELETE_WINDOW protocol */
721 jsorg71 450 g_protocol_atom = XInternAtom(g_display, "WM_PROTOCOLS", True);
722     g_kill_atom = XInternAtom(g_display, "WM_DELETE_WINDOW", True);
723     XSetWMProtocols(g_display, g_wnd, &g_kill_atom, 1);
724 astrand 275
725 matty 10 return True;
726 matty 6 }
727    
728 matty 25 void
729 matthewc 192 ui_destroy_window(void)
730 matty 6 {
731 jsorg71 450 if (g_IC != NULL)
732     XDestroyIC(g_IC);
733 matty 31
734 jsorg71 450 XDestroyWindow(g_display, g_wnd);
735 matty 6 }
736    
737 jsorg71 100 void
738 matthewc 192 xwin_toggle_fullscreen(void)
739 jsorg71 100 {
740 matthewc 188 Pixmap contents = 0;
741 matthewc 123
742 jsorg71 450 if (!g_ownbackstore)
743 matthewc 188 {
744     /* need to save contents of window */
745 jsorg71 450 contents = XCreatePixmap(g_display, g_wnd, g_width, g_height, g_depth);
746     XCopyArea(g_display, g_wnd, contents, g_gc, 0, 0, g_width, g_height, 0, 0);
747 matthewc 188 }
748    
749     ui_destroy_window();
750 jsorg71 447 g_fullscreen = !g_fullscreen;
751 matthewc 188 ui_create_window();
752 matthewc 123
753 jsorg71 450 XDefineCursor(g_display, g_wnd, g_current_cursor);
754 matthewc 188
755 jsorg71 450 if (!g_ownbackstore)
756 matthewc 188 {
757 jsorg71 450 XCopyArea(g_display, contents, g_wnd, g_gc, 0, 0, g_width, g_height, 0, 0);
758     XFreePixmap(g_display, contents);
759 matthewc 188 }
760 jsorg71 100 }
761    
762 jsorg71 447 /* Process all events in Xlib queue
763 astrand 275 Returns 0 after user quit, 1 otherwise */
764     static int
765 matthewc 192 xwin_process_events(void)
766 matty 9 {
767 n-ki 54 XEvent xevent;
768 matthewc 38 KeySym keysym;
769 matthewc 50 uint16 button, flags;
770 matty 10 uint32 ev_time;
771 astrand 66 key_translation tr;
772     char str[256];
773     Status status;
774 matthewc 203 unsigned int state;
775     Window wdummy;
776     int dummy;
777 matty 9
778 jsorg71 450 while (XPending(g_display) > 0)
779 matty 9 {
780 jsorg71 450 XNextEvent(g_display, &xevent);
781 matthewc 123
782 jsorg71 450 if ((g_IC != NULL) && (XFilterEvent(&xevent, None) == True))
783 astrand 66 {
784 astrand 84 DEBUG_KBD(("Filtering event\n"));
785 astrand 66 continue;
786     }
787    
788 matthewc 50 flags = 0;
789 matty 10
790 n-ki 54 switch (xevent.type)
791 matty 9 {
792 astrand 275 case ClientMessage:
793     /* the window manager told us to quit */
794 jsorg71 450 if ((xevent.xclient.message_type == g_protocol_atom)
795     && ((Atom) xevent.xclient.data.l[0] == g_kill_atom))
796 astrand 275 /* Quit */
797     return 0;
798     break;
799    
800 matty 9 case KeyPress:
801 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
802     if (g_IC != NULL)
803 astrand 66 /* Multi_key compatible version */
804     {
805 jsorg71 450 XmbLookupString(g_IC,
806 astrand 435 &xevent.xkey, str, sizeof(str), &keysym,
807     &status);
808 astrand 82 if (!((status == XLookupKeySym) || (status == XLookupBoth)))
809 astrand 66 {
810 astrand 82 error("XmbLookupString failed with status 0x%x\n",
811     status);
812 astrand 66 break;
813     }
814     }
815     else
816     {
817     /* Plain old XLookupString */
818 astrand 182 DEBUG_KBD(("\nNo input context, using XLookupString\n"));
819 astrand 66 XLookupString((XKeyEvent *) & xevent,
820 astrand 82 str, sizeof(str), &keysym, NULL);
821 astrand 66 }
822    
823 astrand 261 DEBUG_KBD(("KeyPress for (keysym 0x%lx, %s)\n", keysym,
824     get_ksname(keysym)));
825 astrand 66
826 matthewc 203 ev_time = time(NULL);
827     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, True))
828 astrand 118 break;
829    
830 astrand 66 tr = xkeymap_translate_key(keysym,
831 astrand 82 xevent.xkey.keycode, xevent.xkey.state);
832 astrand 69
833 astrand 66 if (tr.scancode == 0)
834 n-ki 52 break;
835    
836 astrand 470 save_remote_modifiers(tr.scancode);
837 astrand 115 ensure_remote_modifiers(ev_time, tr);
838 astrand 449 rdp_send_scancode(ev_time, RDP_KEYPRESS, tr.scancode);
839 astrand 470 restore_remote_modifiers(ev_time, tr.scancode);
840 astrand 115
841 astrand 66 break;
842 matthewc 203
843 astrand 66 case KeyRelease:
844 jsorg71 450 g_last_gesturetime = xevent.xkey.time;
845 astrand 66 XLookupString((XKeyEvent *) & xevent, str,
846     sizeof(str), &keysym, NULL);
847 n-ki 52
848 astrand 84 DEBUG_KBD(("\nKeyRelease for (keysym 0x%lx, %s)\n", keysym,
849 matthewc 203 get_ksname(keysym)));
850 n-ki 52
851 matthewc 203 ev_time = time(NULL);
852     if (handle_special_keys(keysym, xevent.xkey.state, ev_time, False))
853 astrand 118 break;
854    
855 astrand 66 tr = xkeymap_translate_key(keysym,
856 astrand 82 xevent.xkey.keycode, xevent.xkey.state);
857 astrand 66
858     if (tr.scancode == 0)
859     break;
860    
861 astrand 82 rdp_send_scancode(ev_time, RDP_KEYRELEASE, tr.scancode);
862 matty 9 break;
863    
864     case ButtonPress:
865 matthewc 50 flags = MOUSE_FLAG_DOWN;
866     /* fall through */
867 matty 9
868     case ButtonRelease:
869 jsorg71 450 g_last_gesturetime = xevent.xbutton.time;
870 astrand 82 button = xkeymap_translate_button(xevent.xbutton.button);
871 matty 9 if (button == 0)
872     break;
873    
874 astrand 328 /* If win_button_size is nonzero, enable single app mode */
875 jsorg71 450 if (xevent.xbutton.y < g_win_button_size)
876 astrand 328 {
877 astrand 342 /* Stop moving window when button is released, regardless of cursor position */
878 jsorg71 450 if (g_moving_wnd && (xevent.type == ButtonRelease))
879     g_moving_wnd = False;
880 astrand 332
881 astrand 342 /* Check from right to left: */
882    
883 jsorg71 450 if (xevent.xbutton.x >= g_width - g_win_button_size)
884 astrand 328 {
885 astrand 331 /* The close button, continue */
886 astrand 328 ;
887     }
888 astrand 456 else if (xevent.xbutton.x >=
889     g_width - g_win_button_size * 2)
890 astrand 328 {
891     /* The maximize/restore button. Do not send to
892     server. It might be a good idea to change the
893 jsorg71 447 cursor or give some other visible indication
894 astrand 328 that rdesktop inhibited this click */
895     break;
896     }
897 astrand 456 else if (xevent.xbutton.x >=
898     g_width - g_win_button_size * 3)
899 astrand 328 {
900     /* The minimize button. Iconify window. */
901 jsorg71 450 XIconifyWindow(g_display, g_wnd,
902     DefaultScreen(g_display));
903 astrand 328 break;
904     }
905 jsorg71 450 else if (xevent.xbutton.x <= g_win_button_size)
906 astrand 342 {
907     /* The system menu. Ignore. */
908     break;
909     }
910 astrand 332 else
911     {
912 astrand 342 /* The title bar. */
913 jsorg71 447 if ((xevent.type == ButtonPress) && !g_fullscreen
914 jsorg71 450 && g_hide_decorations)
915 astrand 342 {
916 jsorg71 450 g_moving_wnd = True;
917     g_move_x_offset = xevent.xbutton.x;
918     g_move_y_offset = xevent.xbutton.y;
919 astrand 342 }
920 astrand 332 break;
921 astrand 342
922 astrand 332 }
923 astrand 328 }
924    
925 matthewc 203 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
926 astrand 82 flags | button, xevent.xbutton.x, xevent.xbutton.y);
927 matty 10 break;
928    
929     case MotionNotify:
930 jsorg71 450 if (g_moving_wnd)
931 astrand 342 {
932 jsorg71 450 XMoveWindow(g_display, g_wnd,
933     xevent.xmotion.x_root - g_move_x_offset,
934     xevent.xmotion.y_root - g_move_y_offset);
935 astrand 342 break;
936     }
937    
938 jsorg71 447 if (g_fullscreen && !g_focused)
939 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
940 jsorg71 288 CurrentTime);
941 matthewc 203 rdp_send_input(time(NULL), RDP_INPUT_MOUSE,
942 astrand 82 MOUSE_FLAG_MOVE, xevent.xmotion.x, xevent.xmotion.y);
943 matty 28 break;
944    
945 matthewc 194 case FocusIn:
946 jsorg71 257 if (xevent.xfocus.mode == NotifyGrab)
947     break;
948 jsorg71 447 g_focused = True;
949 jsorg71 450 XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy,
950 astrand 261 &dummy, &dummy, &state);
951 matthewc 203 reset_modifier_keys(state);
952 jsorg71 450 if (g_grab_keyboard && g_mouse_in_wnd)
953     XGrabKeyboard(g_display, g_wnd, True,
954 astrand 82 GrabModeAsync, GrabModeAsync, CurrentTime);
955 matty 28 break;
956    
957 matthewc 194 case FocusOut:
958 jsorg71 257 if (xevent.xfocus.mode == NotifyUngrab)
959     break;
960 jsorg71 447 g_focused = False;
961 matthewc 201 if (xevent.xfocus.mode == NotifyWhileGrabbed)
962 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
963 matty 28 break;
964 matty 31
965 matthewc 250 case EnterNotify:
966     /* we only register for this event when in fullscreen mode */
967 jsorg71 257 /* or grab_keyboard */
968 jsorg71 447 g_mouse_in_wnd = True;
969     if (g_fullscreen)
970 jsorg71 257 {
971 jsorg71 450 XSetInputFocus(g_display, g_wnd, RevertToPointerRoot,
972 astrand 261 CurrentTime);
973 jsorg71 257 break;
974     }
975 jsorg71 447 if (g_focused)
976 jsorg71 450 XGrabKeyboard(g_display, g_wnd, True,
977 jsorg71 257 GrabModeAsync, GrabModeAsync, CurrentTime);
978 matthewc 250 break;
979    
980 matthewc 253 case LeaveNotify:
981 jsorg71 257 /* we only register for this event when grab_keyboard */
982 jsorg71 447 g_mouse_in_wnd = False;
983 jsorg71 450 XUngrabKeyboard(g_display, CurrentTime);
984 matthewc 253 break;
985    
986 matty 31 case Expose:
987 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc,
988 n-ki 54 xevent.xexpose.x, xevent.xexpose.y,
989 astrand 64 xevent.xexpose.width,
990     xevent.xexpose.height,
991 n-ki 54 xevent.xexpose.x, xevent.xexpose.y);
992 matty 31 break;
993 astrand 119
994     case MappingNotify:
995     /* Refresh keyboard mapping if it has changed. This is important for
996     Xvnc, since it allocates keycodes dynamically */
997     if (xevent.xmapping.request == MappingKeyboard
998     || xevent.xmapping.request == MappingModifier)
999     XRefreshKeyboardMapping(&xevent.xmapping);
1000 matthewc 203
1001     if (xevent.xmapping.request == MappingModifier)
1002     {
1003 jsorg71 450 XFreeModifiermap(g_mod_map);
1004     g_mod_map = XGetModifierMapping(g_display);
1005 matthewc 203 }
1006 astrand 119 break;
1007 matthewc 432
1008 astrand 435 /* clipboard stuff */
1009 forsberg 415 case SelectionNotify:
1010 matthewc 432 xclip_handle_SelectionNotify(&xevent.xselection);
1011 forsberg 415 break;
1012     case SelectionRequest:
1013 matthewc 432 xclip_handle_SelectionRequest(&xevent.xselectionrequest);
1014 forsberg 415 break;
1015 matthewc 432 case SelectionClear:
1016     xclip_handle_SelectionClear();
1017     break;
1018 forsberg 415 case PropertyNotify:
1019 matthewc 432 xclip_handle_PropertyNotify(&xevent.xproperty);
1020 forsberg 415 break;
1021 matty 9 }
1022     }
1023 astrand 275 /* Keep going */
1024     return 1;
1025 matty 9 }
1026    
1027 astrand 275 /* Returns 0 after user quit, 1 otherwise */
1028     int
1029 matty 33 ui_select(int rdp_socket)
1030     {
1031 jsorg71 450 int n = (rdp_socket > g_x_socket) ? rdp_socket + 1 : g_x_socket + 1;
1032 matty 33 fd_set rfds;
1033    
1034     FD_ZERO(&rfds);
1035    
1036     while (True)
1037     {
1038 matthewc 121 /* Process any events already waiting */
1039 astrand 275 if (!xwin_process_events())
1040     /* User quit */
1041     return 0;
1042 astrand 119
1043 matty 33 FD_ZERO(&rfds);
1044     FD_SET(rdp_socket, &rfds);
1045 jsorg71 450 FD_SET(g_x_socket, &rfds);
1046 matty 33
1047     switch (select(n, &rfds, NULL, NULL, NULL))
1048     {
1049     case -1:
1050     error("select: %s\n", strerror(errno));
1051    
1052     case 0:
1053     continue;
1054     }
1055    
1056     if (FD_ISSET(rdp_socket, &rfds))
1057 astrand 275 return 1;
1058 matty 33 }
1059     }
1060    
1061     void
1062 matty 25 ui_move_pointer(int x, int y)
1063 matty 9 {
1064 jsorg71 450 XWarpPointer(g_display, g_wnd, g_wnd, 0, 0, 0, 0, x, y);
1065 matty 9 }
1066    
1067 matty 25 HBITMAP
1068 astrand 64 ui_create_bitmap(int width, int height, uint8 * data)
1069 matty 6 {
1070     XImage *image;
1071 matty 9 Pixmap bitmap;
1072 matty 28 uint8 *tdata;
1073 matty 29
1074 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1075     bitmap = XCreatePixmap(g_display, g_wnd, width, height, g_depth);
1076     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1077     (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1078 matty 6
1079 jsorg71 450 XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
1080 matty 9
1081     XFree(image);
1082 jsorg71 450 if (!g_owncolmap)
1083 n-ki 279 xfree(tdata);
1084 matty 24 return (HBITMAP) bitmap;
1085 matty 6 }
1086    
1087 matty 25 void
1088 astrand 82 ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
1089 matty 6 {
1090 matty 10 XImage *image;
1091 matty 29 uint8 *tdata;
1092 jsorg71 450 tdata = (g_owncolmap ? data : translate_image(width, height, data));
1093     image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1094     (char *) tdata, width, height, g_server_bpp == 8 ? 8 : g_bpp, 0);
1095 matty 28
1096 jsorg71 450 if (g_ownbackstore)
1097 matty 31 {
1098 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1099     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1100 matty 31 }
1101     else
1102     {
1103 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1104 matty 31 }
1105 matty 29
1106 matty 24 XFree(image);
1107 jsorg71 450 if (!g_owncolmap)
1108 n-ki 279 xfree(tdata);
1109 matty 6 }
1110    
1111 matty 25 void
1112     ui_destroy_bitmap(HBITMAP bmp)
1113 matty 6 {
1114 jsorg71 450 XFreePixmap(g_display, (Pixmap) bmp);
1115 matty 10 }
1116    
1117 matty 25 HGLYPH
1118 astrand 64 ui_create_glyph(int width, int height, uint8 * data)
1119 matty 10 {
1120 matty 9 XImage *image;
1121     Pixmap bitmap;
1122     int scanline;
1123     GC gc;
1124 matty 6
1125 matty 9 scanline = (width + 7) / 8;
1126 matty 6
1127 jsorg71 450 bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
1128     gc = XCreateGC(g_display, bitmap, 0, NULL);
1129 matty 9
1130 jsorg71 450 image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
1131 astrand 73 width, height, 8, scanline);
1132 matty 23 image->byte_order = MSBFirst;
1133     image->bitmap_bit_order = MSBFirst;
1134     XInitImage(image);
1135    
1136 jsorg71 450 XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
1137 matty 29
1138 matty 9 XFree(image);
1139 jsorg71 450 XFreeGC(g_display, gc);
1140 astrand 64 return (HGLYPH) bitmap;
1141 matty 6 }
1142 matty 7
1143 matty 25 void
1144     ui_destroy_glyph(HGLYPH glyph)
1145 matty 7 {
1146 jsorg71 450 XFreePixmap(g_display, (Pixmap) glyph);
1147 matty 9 }
1148    
1149 matty 29 HCURSOR
1150 astrand 66 ui_create_cursor(unsigned int x, unsigned int y, int width, int height,
1151     uint8 * andmask, uint8 * xormask)
1152 matty 9 {
1153 matty 29 HGLYPH maskglyph, cursorglyph;
1154     XColor bg, fg;
1155     Cursor xcursor;
1156     uint8 *cursor, *pcursor;
1157     uint8 *mask, *pmask;
1158     uint8 nextbit;
1159     int scanline, offset;
1160     int i, j;
1161    
1162     scanline = (width + 7) / 8;
1163     offset = scanline * height;
1164    
1165 forsberg 415 cursor = (uint8 *) xmalloc(offset);
1166 matty 29 memset(cursor, 0, offset);
1167    
1168 forsberg 415 mask = (uint8 *) xmalloc(offset);
1169 matty 29 memset(mask, 0, offset);
1170    
1171     /* approximate AND and XOR masks with a monochrome X pointer */
1172     for (i = 0; i < height; i++)
1173 matty 7 {
1174 matty 29 offset -= scanline;
1175     pcursor = &cursor[offset];
1176     pmask = &mask[offset];
1177    
1178     for (j = 0; j < scanline; j++)
1179 matty 28 {
1180 matty 29 for (nextbit = 0x80; nextbit != 0; nextbit >>= 1)
1181     {
1182     if (xormask[0] || xormask[1] || xormask[2])
1183     {
1184     *pcursor |= (~(*andmask) & nextbit);
1185     *pmask |= nextbit;
1186     }
1187     else
1188     {
1189     *pcursor |= ((*andmask) & nextbit);
1190     *pmask |= (~(*andmask) & nextbit);
1191     }
1192    
1193     xormask += 3;
1194     }
1195    
1196     andmask++;
1197     pcursor++;
1198     pmask++;
1199 matty 28 }
1200 matty 7 }
1201 matty 29
1202     fg.red = fg.blue = fg.green = 0xffff;
1203     bg.red = bg.blue = bg.green = 0x0000;
1204     fg.flags = bg.flags = DoRed | DoBlue | DoGreen;
1205    
1206     cursorglyph = ui_create_glyph(width, height, cursor);
1207     maskglyph = ui_create_glyph(width, height, mask);
1208    
1209 astrand 66 xcursor =
1210 jsorg71 450 XCreatePixmapCursor(g_display, (Pixmap) cursorglyph,
1211 astrand 66 (Pixmap) maskglyph, &fg, &bg, x, y);
1212 astrand 64
1213 matty 29 ui_destroy_glyph(maskglyph);
1214     ui_destroy_glyph(cursorglyph);
1215     xfree(mask);
1216     xfree(cursor);
1217 astrand 64 return (HCURSOR) xcursor;
1218 matty 29 }
1219    
1220     void
1221     ui_set_cursor(HCURSOR cursor)
1222     {
1223 jsorg71 450 g_current_cursor = (Cursor) cursor;
1224     XDefineCursor(g_display, g_wnd, g_current_cursor);
1225 matty 29 }
1226    
1227     void
1228     ui_destroy_cursor(HCURSOR cursor)
1229     {
1230 jsorg71 450 XFreeCursor(g_display, (Cursor) cursor);
1231 matty 29 }
1232    
1233     #define MAKE_XCOLOR(xc,c) \
1234     (xc)->red = ((c)->red << 8) | (c)->red; \
1235     (xc)->green = ((c)->green << 8) | (c)->green; \
1236     (xc)->blue = ((c)->blue << 8) | (c)->blue; \
1237     (xc)->flags = DoRed | DoGreen | DoBlue;
1238    
1239 n-ki 279
1240 matty 29 HCOLOURMAP
1241 astrand 64 ui_create_colourmap(COLOURMAP * colours)
1242 matty 29 {
1243     COLOURENTRY *entry;
1244     int i, ncolours = colours->ncolours;
1245 jsorg71 450 if (!g_owncolmap)
1246 matty 28 {
1247 jsorg71 450 uint32 *map = (uint32 *) xmalloc(sizeof(*g_colmap) * ncolours);
1248 n-ki 279 XColor xentry;
1249     XColor xc_cache[256];
1250     uint32 colour;
1251     int colLookup = 256;
1252     for (i = 0; i < ncolours; i++)
1253 matty 28 {
1254 n-ki 279 entry = &colours->colours[i];
1255     MAKE_XCOLOR(&xentry, entry);
1256 matty 7
1257 jsorg71 450 if (XAllocColor(g_display, g_xcolmap, &xentry) == 0)
1258 astrand 196 {
1259 n-ki 279 /* Allocation failed, find closest match. */
1260     int j = 256;
1261     int nMinDist = 3 * 256 * 256;
1262     long nDist = nMinDist;
1263 matty 28
1264 n-ki 279 /* only get the colors once */
1265     while (colLookup--)
1266 astrand 196 {
1267 n-ki 279 xc_cache[colLookup].pixel = colLookup;
1268     xc_cache[colLookup].red = xc_cache[colLookup].green =
1269     xc_cache[colLookup].blue = 0;
1270     xc_cache[colLookup].flags = 0;
1271 jsorg71 450 XQueryColor(g_display,
1272     DefaultColormap(g_display,
1273     DefaultScreen(g_display)),
1274 n-ki 279 &xc_cache[colLookup]);
1275 n-ki 185 }
1276 n-ki 279 colLookup = 0;
1277    
1278     /* approximate the pixel */
1279     while (j--)
1280 astrand 196 {
1281 n-ki 279 if (xc_cache[j].flags)
1282     {
1283     nDist = ((long) (xc_cache[j].red >> 8) -
1284     (long) (xentry.red >> 8)) *
1285     ((long) (xc_cache[j].red >> 8) -
1286     (long) (xentry.red >> 8)) +
1287     ((long) (xc_cache[j].green >> 8) -
1288     (long) (xentry.green >> 8)) *
1289     ((long) (xc_cache[j].green >> 8) -
1290     (long) (xentry.green >> 8)) +
1291     ((long) (xc_cache[j].blue >> 8) -
1292     (long) (xentry.blue >> 8)) *
1293     ((long) (xc_cache[j].blue >> 8) -
1294     (long) (xentry.blue >> 8));
1295     }
1296     if (nDist < nMinDist)
1297     {
1298     nMinDist = nDist;
1299     xentry.pixel = j;
1300     }
1301 n-ki 185 }
1302     }
1303 n-ki 279 colour = xentry.pixel;
1304    
1305     /* update our cache */
1306     if (xentry.pixel < 256)
1307     {
1308     xc_cache[xentry.pixel].red = xentry.red;
1309     xc_cache[xentry.pixel].green = xentry.green;
1310     xc_cache[xentry.pixel].blue = xentry.blue;
1311    
1312     }
1313    
1314    
1315     /* byte swap here to make translate_image faster */
1316     map[i] = translate_colour(colour);
1317 n-ki 185 }
1318 n-ki 279 return map;
1319     }
1320     else
1321     {
1322     XColor *xcolours, *xentry;
1323     Colormap map;
1324 matty 29
1325 forsberg 415 xcolours = (XColor *) xmalloc(sizeof(XColor) * ncolours);
1326 n-ki 279 for (i = 0; i < ncolours; i++)
1327 astrand 196 {
1328 n-ki 279 entry = &colours->colours[i];
1329     xentry = &xcolours[i];
1330     xentry->pixel = i;
1331     MAKE_XCOLOR(xentry, entry);
1332 matty 29 }
1333    
1334 jsorg71 450 map = XCreateColormap(g_display, g_wnd, g_visual, AllocAll);
1335     XStoreColors(g_display, map, xcolours, ncolours);
1336 n-ki 185
1337 n-ki 279 xfree(xcolours);
1338     return (HCOLOURMAP) map;
1339 matty 29 }
1340 matty 7 }
1341    
1342 matty 25 void
1343     ui_destroy_colourmap(HCOLOURMAP map)
1344 matty 7 {
1345 jsorg71 450 if (!g_owncolmap)
1346 n-ki 279 xfree(map);
1347     else
1348 jsorg71 450 XFreeColormap(g_display, (Colormap) map);
1349 matty 7 }
1350    
1351 matty 25 void
1352     ui_set_colourmap(HCOLOURMAP map)
1353 matty 7 {
1354 jsorg71 450 if (!g_owncolmap)
1355 astrand 448 {
1356 jsorg71 450 if (g_colmap)
1357     xfree(g_colmap);
1358 astrand 448
1359 jsorg71 450 g_colmap = (uint32 *) map;
1360 astrand 448 }
1361 n-ki 279 else
1362 jsorg71 450 XSetWindowColormap(g_display, g_wnd, (Colormap) map);
1363 matty 7 }
1364    
1365 matty 25 void
1366     ui_set_clip(int x, int y, int cx, int cy)
1367 matty 7 {
1368 matty 9 XRectangle rect;
1369 matty 7
1370 matty 9 rect.x = x;
1371     rect.y = y;
1372     rect.width = cx;
1373     rect.height = cy;
1374 jsorg71 450 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1375 matty 9 }
1376 matty 7
1377 matty 25 void
1378 matthewc 192 ui_reset_clip(void)
1379 matty 9 {
1380     XRectangle rect;
1381    
1382     rect.x = 0;
1383     rect.y = 0;
1384 jsorg71 447 rect.width = g_width;
1385     rect.height = g_height;
1386 jsorg71 450 XSetClipRectangles(g_display, g_gc, 0, 0, &rect, 1, YXBanded);
1387 matty 7 }
1388    
1389 matty 25 void
1390 matthewc 192 ui_bell(void)
1391 matty 10 {
1392 jsorg71 450 XBell(g_display, 0);
1393 matty 10 }
1394    
1395 matty 25 void
1396     ui_destblt(uint8 opcode,
1397     /* dest */ int x, int y, int cx, int cy)
1398 matty 9 {
1399 matty 29 SET_FUNCTION(opcode);
1400 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1401 matty 29 RESET_FUNCTION(opcode);
1402 matty 9 }
1403    
1404 jsorg71 373 static uint8 hatch_patterns[] = {
1405 forsberg 415 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
1406     0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
1407     0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
1408     0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
1409     0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
1410     0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
1411 jsorg71 373 };
1412    
1413 matty 25 void
1414     ui_patblt(uint8 opcode,
1415     /* dest */ int x, int y, int cx, int cy,
1416 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1417 matty 9 {
1418     Pixmap fill;
1419 jsorg71 59 uint8 i, ipattern[8];
1420 matty 9
1421 matty 29 SET_FUNCTION(opcode);
1422 matty 9
1423     switch (brush->style)
1424     {
1425 matty 24 case 0: /* Solid */
1426 matty 29 SET_FOREGROUND(fgcolour);
1427 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1428 matty 9 break;
1429    
1430 jsorg71 373 case 2: /* Hatch */
1431 forsberg 415 fill = (Pixmap) ui_create_glyph(8, 8,
1432     hatch_patterns + brush->pattern[0] * 8);
1433 jsorg71 373 SET_FOREGROUND(bgcolour);
1434     SET_BACKGROUND(fgcolour);
1435 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1436     XSetStipple(g_display, g_gc, fill);
1437     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1438 jsorg71 373 FILL_RECTANGLE(x, y, cx, cy);
1439 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
1440     XSetTSOrigin(g_display, g_gc, 0, 0);
1441 jsorg71 373 ui_destroy_glyph((HGLYPH) fill);
1442     break;
1443    
1444 matty 24 case 3: /* Pattern */
1445 jsorg71 59 for (i = 0; i != 8; i++)
1446     ipattern[7 - i] = brush->pattern[i];
1447     fill = (Pixmap) ui_create_glyph(8, 8, ipattern);
1448 matty 9
1449 matty 29 SET_FOREGROUND(bgcolour);
1450     SET_BACKGROUND(fgcolour);
1451 jsorg71 450 XSetFillStyle(g_display, g_gc, FillOpaqueStippled);
1452     XSetStipple(g_display, g_gc, fill);
1453     XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin);
1454 matty 9
1455 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1456 matty 9
1457 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
1458     XSetTSOrigin(g_display, g_gc, 0, 0);
1459 astrand 64 ui_destroy_glyph((HGLYPH) fill);
1460 matty 9 break;
1461    
1462     default:
1463 matty 30 unimpl("brush %d\n", brush->style);
1464 matty 9 }
1465 matty 29
1466     RESET_FUNCTION(opcode);
1467 matty 9 }
1468    
1469 matty 25 void
1470     ui_screenblt(uint8 opcode,
1471     /* dest */ int x, int y, int cx, int cy,
1472     /* src */ int srcx, int srcy)
1473 matty 9 {
1474 matty 29 SET_FUNCTION(opcode);
1475 jsorg71 450 XCopyArea(g_display, g_wnd, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1476     if (g_ownbackstore)
1477     XCopyArea(g_display, g_backstore, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1478 matty 29 RESET_FUNCTION(opcode);
1479 matty 9 }
1480    
1481 matty 25 void
1482     ui_memblt(uint8 opcode,
1483     /* dest */ int x, int y, int cx, int cy,
1484     /* src */ HBITMAP src, int srcx, int srcy)
1485 matty 9 {
1486 matty 29 SET_FUNCTION(opcode);
1487 jsorg71 450 XCopyArea(g_display, (Pixmap) src, g_wnd, g_gc, srcx, srcy, cx, cy, x, y);
1488     if (g_ownbackstore)
1489     XCopyArea(g_display, (Pixmap) src, g_backstore, g_gc, srcx, srcy, cx, cy, x, y);
1490 matty 29 RESET_FUNCTION(opcode);
1491 matty 9 }
1492    
1493 matty 25 void
1494     ui_triblt(uint8 opcode,
1495     /* dest */ int x, int y, int cx, int cy,
1496     /* src */ HBITMAP src, int srcx, int srcy,
1497 astrand 64 /* brush */ BRUSH * brush, int bgcolour, int fgcolour)
1498 matty 9 {
1499     /* This is potentially difficult to do in general. Until someone
1500 matty 10 comes up with a more efficient way of doing it I am using cases. */
1501 matty 9
1502     switch (opcode)
1503     {
1504 matty 24 case 0x69: /* PDSxxn */
1505 matty 16 ui_memblt(ROP2_XOR, x, y, cx, cy, src, srcx, srcy);
1506 astrand 82 ui_patblt(ROP2_NXOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1507 matty 16 break;
1508    
1509 matty 24 case 0xb8: /* PSDPxax */
1510 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1511 matty 16 ui_memblt(ROP2_AND, x, y, cx, cy, src, srcx, srcy);
1512 astrand 82 ui_patblt(ROP2_XOR, x, y, cx, cy, brush, bgcolour, fgcolour);
1513 matty 9 break;
1514    
1515 matty 29 case 0xc0: /* PSa */
1516 matty 28 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1517 astrand 82 ui_patblt(ROP2_AND, x, y, cx, cy, brush, bgcolour, fgcolour);
1518 matty 28 break;
1519    
1520 matty 9 default:
1521 matty 30 unimpl("triblt 0x%x\n", opcode);
1522 matty 16 ui_memblt(ROP2_COPY, x, y, cx, cy, src, srcx, srcy);
1523 matty 9 }
1524     }
1525    
1526 matty 25 void
1527     ui_line(uint8 opcode,
1528     /* dest */ int startx, int starty, int endx, int endy,
1529 astrand 64 /* pen */ PEN * pen)
1530 matty 9 {
1531 matty 29 SET_FUNCTION(opcode);
1532     SET_FOREGROUND(pen->colour);
1533 jsorg71 450 XDrawLine(g_display, g_wnd, g_gc, startx, starty, endx, endy);
1534     if (g_ownbackstore)
1535     XDrawLine(g_display, g_backstore, g_gc, startx, starty, endx, endy);
1536 matty 29 RESET_FUNCTION(opcode);
1537 matty 9 }
1538    
1539 matty 25 void
1540     ui_rect(
1541     /* dest */ int x, int y, int cx, int cy,
1542     /* brush */ int colour)
1543 matty 9 {
1544 matty 29 SET_FOREGROUND(colour);
1545 matty 31 FILL_RECTANGLE(x, y, cx, cy);
1546 matty 9 }
1547    
1548 jsorg71 278 /* warning, this function only draws on wnd or backstore, not both */
1549 matty 25 void
1550     ui_draw_glyph(int mixmode,
1551     /* dest */ int x, int y, int cx, int cy,
1552 astrand 66 /* src */ HGLYPH glyph, int srcx, int srcy,
1553     int bgcolour, int fgcolour)
1554 matty 9 {
1555 matty 29 SET_FOREGROUND(fgcolour);
1556     SET_BACKGROUND(bgcolour);
1557 matty 9
1558 jsorg71 450 XSetFillStyle(g_display, g_gc,
1559 astrand 82 (mixmode == MIX_TRANSPARENT) ? FillStippled : FillOpaqueStippled);
1560 jsorg71 450 XSetStipple(g_display, g_gc, (Pixmap) glyph);
1561     XSetTSOrigin(g_display, g_gc, x, y);
1562 matty 9
1563 matthewc 296 FILL_RECTANGLE_BACKSTORE(x, y, cx, cy);
1564 matty 9
1565 jsorg71 450 XSetFillStyle(g_display, g_gc, FillSolid);
1566 matty 9 }
1567    
1568 mmihalik 49 #define DO_GLYPH(ttext,idx) \
1569     {\
1570     glyph = cache_get_font (font, ttext[idx]);\
1571     if (!(flags & TEXT2_IMPLICIT_X))\
1572     {\
1573     xyoffset = ttext[++idx];\
1574     if ((xyoffset & 0x80))\
1575     {\
1576     if (flags & TEXT2_VERTICAL) \
1577 astrand 72 y += ttext[idx+1] | (ttext[idx+2] << 8);\
1578 mmihalik 49 else\
1579 astrand 72 x += ttext[idx+1] | (ttext[idx+2] << 8);\
1580     idx += 2;\
1581 mmihalik 49 }\
1582     else\
1583     {\
1584     if (flags & TEXT2_VERTICAL) \
1585     y += xyoffset;\
1586     else\
1587     x += xyoffset;\
1588     }\
1589     }\
1590     if (glyph != NULL)\
1591     {\
1592 matthewc 299 ui_draw_glyph (mixmode, x + glyph->offset,\
1593     y + glyph->baseline,\
1594 mmihalik 49 glyph->width, glyph->height,\
1595     glyph->pixmap, 0, 0, bgcolour, fgcolour);\
1596     if (flags & TEXT2_IMPLICIT_X)\
1597     x += glyph->width;\
1598     }\
1599     }
1600    
1601 matty 25 void
1602     ui_draw_text(uint8 font, uint8 flags, int mixmode, int x, int y,
1603 astrand 66 int clipx, int clipy, int clipcx, int clipcy,
1604     int boxx, int boxy, int boxcx, int boxcy, int bgcolour,
1605 mmihalik 49 int fgcolour, uint8 * text, uint8 length)
1606 matty 9 {
1607 matty 10 FONTGLYPH *glyph;
1608 mmihalik 49 int i, j, xyoffset;
1609     DATABLOB *entry;
1610 matty 9
1611 matty 29 SET_FOREGROUND(bgcolour);
1612 matty 28
1613 matty 9 if (boxcx > 1)
1614 matty 31 {
1615 matthewc 296 FILL_RECTANGLE_BACKSTORE(boxx, boxy, boxcx, boxcy);
1616 matty 31 }
1617 matty 17 else if (mixmode == MIX_OPAQUE)
1618 matty 31 {
1619 matthewc 296 FILL_RECTANGLE_BACKSTORE(clipx, clipy, clipcx, clipcy);
1620 matty 31 }
1621 matty 9
1622     /* Paint text, character by character */
1623 astrand 64 for (i = 0; i < length;)
1624     {
1625     switch (text[i])
1626     {
1627     case 0xff:
1628     if (i + 2 < length)
1629 astrand 82 cache_put_text(text[i + 1], text, text[i + 2]);
1630 astrand 64 else
1631     {
1632     error("this shouldn't be happening\n");
1633 astrand 265 exit(1);
1634 astrand 64 }
1635     /* this will move pointer from start to first character after FF command */
1636     length -= i + 3;
1637     text = &(text[i + 3]);
1638     i = 0;
1639 mmihalik 49 break;
1640 matty 9
1641 astrand 64 case 0xfe:
1642     entry = cache_get_text(text[i + 1]);
1643     if (entry != NULL)
1644     {
1645     if ((((uint8 *) (entry->data))[1] ==
1646 astrand 82 0) && (!(flags & TEXT2_IMPLICIT_X)))
1647 astrand 64 {
1648     if (flags & TEXT2_VERTICAL)
1649     y += text[i + 2];
1650     else
1651     x += text[i + 2];
1652     }
1653     for (j = 0; j < entry->size; j++)
1654 astrand 82 DO_GLYPH(((uint8 *) (entry->data)), j);
1655 matthewc 44 }
1656 jsorg71 286 if (i + 2 < length)
1657     i += 3;
1658     else
1659     i += 2;
1660     length -= i;
1661     /* this will move pointer from start to first character after FE command */
1662     text = &(text[i]);
1663     i = 0;
1664 astrand 64 break;
1665 matty 17
1666 astrand 64 default:
1667     DO_GLYPH(text, i);
1668     i++;
1669     break;
1670 matty 29 }
1671 mmihalik 49 }
1672 jsorg71 450 if (g_ownbackstore)
1673 jsorg71 278 {
1674     if (boxcx > 1)
1675 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, boxx,
1676 jsorg71 278 boxy, boxcx, boxcy, boxx, boxy);
1677     else
1678 jsorg71 450 XCopyArea(g_display, g_backstore, g_wnd, g_gc, clipx,
1679 jsorg71 278 clipy, clipcx, clipcy, clipx, clipy);
1680     }
1681 matty 9 }
1682    
1683 matty 25 void
1684     ui_desktop_save(uint32 offset, int x, int y, int cx, int cy)
1685 matty 9 {
1686 matty 28 Pixmap pix;
1687 matty 9 XImage *image;
1688    
1689 jsorg71 450 if (g_ownbackstore)
1690 matty 31 {
1691 jsorg71 450 image = XGetImage(g_display, g_backstore, x, y, cx, cy, AllPlanes, ZPixmap);
1692 matty 31 }
1693     else
1694     {
1695 jsorg71 450 pix = XCreatePixmap(g_display, g_wnd, cx, cy, g_depth);
1696     XCopyArea(g_display, g_wnd, pix, g_gc, x, y, cx, cy, 0, 0);
1697     image = XGetImage(g_display, pix, 0, 0, cx, cy, AllPlanes, ZPixmap);
1698     XFreePixmap(g_display, pix);
1699 matty 31 }
1700 matty 28
1701 jsorg71 450 offset *= g_bpp / 8;
1702     cache_put_desktop(offset, cx, cy, image->bytes_per_line, g_bpp / 8, (uint8 *) image->data);
1703 matty 28
1704     XDestroyImage(image);
1705 matty 9 }
1706    
1707 matty 25 void
1708     ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy)
1709 matty 9 {
1710     XImage *image;
1711 matty 10 uint8 *data;
1712 matty 9
1713 jsorg71 450 offset *= g_bpp / 8;
1714     data = cache_get_desktop(offset, cx, cy, g_bpp / 8);
1715 matty 10 if (data == NULL)
1716     return;
1717 matty 29
1718 jsorg71 450 image = XCreateImage(g_display, g_visual, g_depth, ZPixmap, 0,
1719     (char *) data, cx, cy, BitmapPad(g_display), cx * g_bpp / 8);
1720 matty 29
1721 jsorg71 450 if (g_ownbackstore)
1722 matty 31 {
1723 jsorg71 450 XPutImage(g_display, g_backstore, g_gc, image, 0, 0, x, y, cx, cy);
1724     XCopyArea(g_display, g_backstore, g_wnd, g_gc, x, y, cx, cy, x, y);
1725 matty 31 }
1726     else
1727     {
1728 jsorg71 450 XPutImage(g_display, g_wnd, g_gc, image, 0, 0, x, y, cx, cy);
1729 matty 31 }
1730    
1731 matty 9 XFree(image);
1732     }

  ViewVC Help
Powered by ViewVC 1.1.26