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

Annotation of /sourceforge.net/trunk/rdesktop/xwin.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 415 - (hide annotations)
Fri Jun 6 11:10:48 2003 UTC (20 years, 11 months ago) by forsberg
File MIME type: text/plain
File size: 41335 byte(s)
Listen for clipboard-related events and handle them.
Listen for IPC-related events and handle them.
Changes after running indent-all.sh

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

  ViewVC Help
Powered by ViewVC 1.1.26