Line data Source code
1 : /* Copyright (C) 2000-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 :
28 : #if defined(__MINGW32__)
29 : #include <winsock2.h>
30 : #include <windows.h>
31 : #endif
32 :
33 : #include "gxdrawP.h"
34 : #include "gxcdrawP.h"
35 :
36 : #include <stdlib.h>
37 : #include <math.h>
38 :
39 : #if !defined(__MINGW32__)
40 : #include <unistd.h> /* for timers & select */
41 : #endif
42 : #include <sys/types.h> /* for timers & select */
43 : #include <sys/time.h> /* for timers & select */
44 : #include <signal.h> /* error handler */
45 : #include <locale.h> /* for setting the X locale properly */
46 :
47 : #ifdef HAVE_PTHREAD_H
48 : # ifndef __MINGW32__
49 : # include <sys/socket.h>
50 : # include <sys/un.h>
51 : # endif
52 : #endif
53 :
54 : #include <ustring.h>
55 : #include <utype.h>
56 : #include "fontP.h"
57 : #include <gresource.h>
58 :
59 : enum cm_type { cmt_default=-1, cmt_current, cmt_copy, cmt_private };
60 :
61 : void GDrawIErrorRun(const char *fmt,...);
62 : void GDrawIError(const char *fmt,...);
63 :
64 :
65 : #ifndef X_DISPLAY_MISSING
66 : # include <X11/Xatom.h>
67 : # include <X11/keysym.h>
68 : # include <X11/cursorfont.h>
69 : # include <X11/Xresource.h>
70 :
71 : #define XKeysym_Mask 0x01000000
72 :
73 : #define XKEYSYM_TOP 8364
74 : extern int gdraw_xkeysym_2_unicode[];
75 :
76 :
77 : extern int cmdlinearg_forceUIHidden;
78 :
79 : static void GXDrawTransmitSelection(GXDisplay *gd,XEvent *event);
80 : static void GXDrawClearSelData(GXDisplay *gd,enum selnames sel);
81 :
82 : /* ************************************************************************** */
83 : /* ******************************* Font Stuff ******************************* */
84 : /* ************************************************************************** */
85 :
86 0 : static void _GXDraw_InitFonts(GXDisplay *gxdisplay) {
87 0 : FState *fs = calloc(1,sizeof(FState));
88 :
89 : /* In inches, because that's how fonts are measured */
90 0 : gxdisplay->fontstate = fs;
91 0 : fs->res = gxdisplay->res;
92 0 : }
93 :
94 : /* ************************************************************************** */
95 : /* ****************************** COLOR Stuff ******************************* */
96 : /* ************************************************************************** */
97 :
98 : #define DIV_BY_0x33(x) (((x)*1286)>>16) /* Fast way to do x/0x33 */
99 : #define RND_BY_0x33(x) (((x+0x19)*1286)>>16)
100 : #define DIV_BY_0x11(x) (((x)*241)>>12) /* Fast way to do x/0x11 */
101 : #define RND_BY_0x11(x) (((x+8)*241)>>12)
102 :
103 0 : static void _GXDraw_FindVisual(GXDisplay *gdisp) {
104 : /* In the old days before 24bit color was common, a 32 bit visual was */
105 : /* the standard way to go (extra 8 bits were ignored). Then came the */
106 : /* composite extension which supported alpha channels in images, and */
107 : /* we had to be careful what went into the extra byte, 0 doesn't work */
108 : static int oldvsearch[][2] = {{ 32, TrueColor },
109 : { 24, TrueColor },
110 : { 16, TrueColor },
111 : { 15, TrueColor },
112 : { 12, TrueColor },
113 : {0}};
114 : static int newvsearch[][2] = {{ 24, TrueColor },
115 : { 16, TrueColor },
116 : { 15, TrueColor },
117 : { 12, TrueColor },
118 : {0}};
119 : static int v2search[][2] = {{ 8, PseudoColor },
120 : { 8, GrayScale },
121 : { 1, GrayScale },
122 : { 1, StaticGray }};
123 0 : int (*vsearch)[2] = gdisp->supports_alpha_images || gdisp->supports_alpha_windows
124 0 : ? newvsearch : oldvsearch;
125 0 : Display *display = gdisp->display;
126 : XVisualInfo vinf, *ret;
127 : int pixel_size, vc, i, j, first;
128 : ScreenFormat *sf;
129 0 : int user=false, cnt;
130 :
131 0 : if ( gdisp->desired_depth!=-1 || gdisp->desired_vc!=-1 ) {
132 0 : vinf.depth = gdisp->desired_depth;
133 0 : vinf.class = gdisp->desired_vc;
134 0 : ret = XGetVisualInfo(display,
135 0 : (gdisp->desired_depth==-1?0:VisualDepthMask )|
136 0 : (gdisp->desired_vc==-1?0:VisualClassMask ),
137 : &vinf, &cnt);
138 0 : if ( cnt>0 ) {
139 0 : for ( i=0; i<cnt; ++i )
140 0 : if ( ret[i].visual==DefaultVisual(display,gdisp->screen))
141 0 : break;
142 0 : if ( i==cnt )
143 0 : i=0;
144 0 : gdisp->visual = ret[i].visual;
145 0 : gdisp->depth = ret[i].depth;
146 0 : user = true;
147 0 : XFree(ret);
148 : } else
149 0 : fprintf( stderr, "Failed to find your desired visual structure\n" );
150 : }
151 :
152 : /* I'd like TrueColor if I can get it */
153 0 : if ( gdisp->visual == NULL ) {
154 0 : for ( i=0; vsearch[i][0]!=0 ; ++i ) {
155 0 : vinf.depth = vsearch[i][0];
156 0 : vinf.class = vsearch[i][1];
157 0 : ret = XGetVisualInfo(display,
158 0 : (gdisp->desired_depth==-1?0:VisualDepthMask )|
159 0 : (gdisp->desired_vc==-1?0:VisualClassMask ),
160 : &vinf, &cnt);
161 0 : if ( cnt>0 ) {
162 0 : for ( j=0; j<cnt; ++j )
163 0 : if ( ret[j].visual==DefaultVisual(display,gdisp->screen))
164 0 : break;
165 0 : if ( j==cnt )
166 0 : j=0;
167 0 : gdisp->visual = ret[j].visual;
168 0 : gdisp->depth = ret[j].depth;
169 0 : user = true;
170 0 : XFree(ret);
171 0 : break;
172 : }
173 : }
174 : }
175 0 : if ( gdisp->visual == NULL ) {
176 0 : gdisp->visual = DefaultVisual(display,gdisp->screen);
177 0 : gdisp->depth = DefaultDepth(display,gdisp->screen);
178 : }
179 : /* Failing TrueColor I'd like PseudoColor on color displays, and GreyScale*/
180 : /* on monochrom displays */
181 0 : if ( !user ) {
182 0 : if ( gdisp->visual->class==DirectColor || gdisp->visual->class==StaticColor ) {
183 0 : if ( XMatchVisualInfo(display,gdisp->screen,8,PseudoColor,&vinf)) {
184 0 : gdisp->visual = vinf.visual;
185 0 : gdisp->depth = 8;
186 : }
187 0 : } else if ( gdisp->visual->class==GrayScale || gdisp->visual->class==StaticGray ) {
188 0 : if ( XMatchVisualInfo(display,gdisp->screen,8,GrayScale,&vinf)) {
189 0 : gdisp->visual = vinf.visual;
190 0 : gdisp->depth = 8;
191 : }
192 : }
193 : }
194 :
195 0 : for ( first = true; ; ) {
196 : /* I want not only the number of meaningful bits in a pixel (which is the */
197 : /* depth) but also the number of bits in pixel when writing an image */
198 : /* I wish I knew how to do this without diving into hidden X structures */
199 0 : gdisp->bitmap_pad = gdisp->pixel_size = gdisp->depth;
200 0 : for ( i=0; i<((_XPrivDisplay) display)->nformats; ++i ) {
201 0 : sf = &((_XPrivDisplay) display)->pixmap_format[i];
202 0 : if ( sf->depth == gdisp->depth ) {
203 0 : gdisp->pixel_size = sf->bits_per_pixel;
204 0 : gdisp->bitmap_pad = sf->scanline_pad;
205 0 : break;
206 : }
207 : }
208 :
209 0 : if ( gdisp->pixel_size==1 || gdisp->pixel_size==8 || gdisp->pixel_size==16 ||
210 0 : gdisp->pixel_size==24 || gdisp->pixel_size==32 )
211 : break; /* We like it */
212 0 : else if ( first ) {
213 : /* If I still don't have something I can work with, try for black&white */
214 0 : for ( i=0; i<sizeof(v2search)/(2*sizeof(int)); ++i ) {
215 0 : if ( XMatchVisualInfo(display,gdisp->screen,v2search[i][0],v2search[i][1],&vinf)) {
216 0 : gdisp->visual = vinf.visual;
217 0 : gdisp->depth = vinf.depth;
218 0 : break;
219 : }
220 : }
221 0 : first = false;
222 : } else
223 0 : break;
224 0 : }
225 :
226 0 : pixel_size = gdisp->pixel_size; vc = gdisp->visual->class;
227 0 : if ( pixel_size==1 || pixel_size==8 ||
228 0 : ((pixel_size==16 || pixel_size==24 || pixel_size==32) && vc==TrueColor))
229 : /* We can deal with it */;
230 0 : else if ( vc==TrueColor || ( vc==PseudoColor && pixel_size<8)) {
231 0 : fprintf( stderr, "%s will not work well with this visual. Colored images will be displayed as bitmaps\n", GResourceProgramName );
232 : } else {
233 0 : fprintf( stderr, "%s will not work with this visual. Restart your X server with a TrueColor\n", GResourceProgramName );
234 0 : fprintf( stderr, " visual (You do this on an SGI by adding an argument \"-class TrueColor\" to\n" );
235 0 : fprintf( stderr, " the command which starts up X, which is probably in /var/X11/xdm/Xservers.\n" );
236 0 : fprintf( stderr, " On a sun you add \"-cc 4\" to the server start line, probably found in\n" );
237 0 : fprintf( stderr, " /usr/lib/X11/xdm/Xservers).\n" );
238 0 : exit(1);
239 : }
240 :
241 0 : if ( gdisp->visual == DefaultVisual(display,gdisp->screen)) {
242 0 : gdisp->cmap = DefaultColormap(display,gdisp->screen);
243 0 : gdisp->default_visual = true;
244 : } else {
245 0 : gdisp->cmap = XCreateColormap(display,gdisp->root,gdisp->visual,
246 : AllocNone);
247 0 : XInstallColormap(display,gdisp->cmap);
248 : }
249 0 : }
250 :
251 0 : static int _GXDraw_AllocColors(GXDisplay *gdisp,XColor *x_colors) {
252 : /* Try to insure that the standard colours we expect to use are available */
253 : /* in the default colormap */
254 0 : Display *display = gdisp->display;
255 : XColor *acolour;
256 : static unsigned short rgb[][3]={
257 : {0x8000,0x8000,0x8000}, {0x4000,0x4000,0x4000},
258 : {0xc000,0xc000,0xc000},
259 : {0x1100,0x1100,0x1100}, {0x2200,0x2200,0x2200},
260 : /*{0x3300,0x3300,0x3300},*/ {0x5500,0x5500,0x5500},
261 : /*{0x6600,0x6600,0x6600},*/ {0x7700,0x7700,0x7700},
262 : {0xaa00,0xaa00,0xaa00}, {0xbb00,0xbb00,0xbb00},
263 : {0xdd00,0xdd00,0xdd00}, {0xee00,0xee00,0xee00},
264 : };
265 : int i, r,g,b;
266 : static int cube[] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
267 :
268 0 : acolour = x_colors;
269 :
270 0 : for(r = 5; r >= 0; --r) {
271 0 : for(g = 5; g >= 0; --g) {
272 0 : for(b = 5; b >= 0; --b) {
273 0 : acolour->red = (cube[r]<<8)|cube[r];
274 0 : acolour->green = (cube[g]<<8)|cube[g];
275 0 : acolour->blue = (cube[b]<<8)|cube[b];
276 0 : acolour->pixel = 0;
277 0 : acolour->flags = 7;
278 0 : if ( XAllocColor(display,gdisp->cmap,acolour))
279 0 : ++acolour;
280 : }}}
281 :
282 0 : for ( i=0; i<sizeof(rgb)/sizeof(rgb[0]); ++i ) {
283 0 : acolour->red = rgb[i][0];
284 0 : acolour->green = rgb[i][1];
285 0 : acolour->blue = rgb[i][2];
286 0 : if ( XAllocColor(display,gdisp->cmap,acolour))
287 0 : ++acolour;
288 : }
289 0 : return( acolour-x_colors );
290 : }
291 :
292 0 : static void _GXDraw_AllocGreys(GXDisplay *gdisp) {
293 0 : Display *display = gdisp->display;
294 : XColor xcolour;
295 0 : int step = 255/((1<<gdisp->depth)-1), r;
296 :
297 0 : for(r = 0; r < 256; r+=step ) {
298 0 : xcolour.red = r<<8;
299 0 : xcolour.green = r<<8;
300 0 : xcolour.blue = r<<8;
301 0 : XAllocColor(display,gdisp->cmap,&xcolour);
302 : }
303 0 : }
304 :
305 0 : static int _GXDraw_CopyColors(GXDisplay *gdisp, XColor *x_colors, Colormap new) {
306 : int i;
307 :
308 0 : for ( i=0; i<(1<<gdisp->depth); ++i )
309 0 : x_colors[i].pixel = i;
310 0 : XQueryColors(gdisp->display,gdisp->cmap,x_colors,1<<gdisp->depth);
311 0 : XStoreColors(gdisp->display,new,x_colors,1<<gdisp->depth);
312 0 : gdisp->cmap = new;
313 0 : return( 1<<gdisp->depth );
314 : }
315 :
316 0 : static int FindAllColors(GXDisplay *gdisp, XColor *x_colors) {
317 : int i;
318 :
319 0 : for ( i=0; i<(1<<gdisp->depth); ++i )
320 0 : x_colors[i].pixel = i;
321 0 : XQueryColors(gdisp->display,gdisp->cmap,x_colors,1<<gdisp->depth);
322 0 : return( 1<<gdisp->depth );
323 : }
324 :
325 0 : static void InitTrueColor(GXDisplay *gdisp) {
326 0 : Visual *vis = gdisp->visual;
327 : int red_shift, green_shift, blue_shift;
328 : int red_bits_shift, blue_bits_shift, green_bits_shift;
329 :
330 : /* The SGI display is not RGB but BGR. X says TrueColor maps are increasing */
331 0 : for ( red_shift=0; red_shift<24 && !(vis->red_mask&(1<<red_shift)); ++red_shift );
332 0 : for ( green_shift=0; green_shift<24 && !(vis->green_mask&(1<<green_shift)); ++green_shift );
333 0 : for ( blue_shift=0; blue_shift<24 && !(vis->blue_mask&(1<<blue_shift)); ++blue_shift );
334 0 : gdisp->cs.red_shift = red_shift;
335 0 : gdisp->cs.green_shift = green_shift;
336 0 : gdisp->cs.blue_shift = blue_shift;
337 :
338 0 : gdisp->cs.red_bits_mask = vis->red_mask>>red_shift;
339 0 : gdisp->cs.green_bits_mask = vis->green_mask>>green_shift;
340 0 : gdisp->cs.blue_bits_mask = vis->blue_mask>>blue_shift;
341 0 : for ( red_bits_shift=0; gdisp->cs.red_bits_mask&(1<<red_bits_shift) ;
342 0 : ++red_bits_shift );
343 0 : for ( green_bits_shift=0; gdisp->cs.green_bits_mask&(1<<green_bits_shift) ;
344 0 : ++green_bits_shift );
345 0 : for ( blue_bits_shift=0; gdisp->cs.blue_bits_mask&(1<<blue_bits_shift) ;
346 0 : ++blue_bits_shift );
347 0 : gdisp->cs.red_bits_shift = 24-red_bits_shift;
348 0 : gdisp->cs.green_bits_shift = 16-green_bits_shift;
349 0 : gdisp->cs.blue_bits_shift = 8-blue_bits_shift;
350 :
351 0 : gdisp->cs.alpha_bits = 0xffffffff&~(vis->red_mask|vis->green_mask|vis->blue_mask);
352 0 : }
353 :
354 0 : static void _GXDraw_InitCols(GXDisplay *gdisp) {
355 : int i;
356 : XColor x_colors[256];
357 : GClut clut;
358 : int x_color_max;
359 : int vclass, depth;
360 0 : int n=0;
361 0 : char **extlist = XListExtensions(gdisp->display,&n);
362 :
363 0 : for ( i=0; i<n; ++i ) {
364 0 : if ( strcasecmp(extlist[i],"Composite")==0 ) { /* "Render"??? */
365 : /* Silly me. I had assumed that writing an alpha channel image to a window*/
366 : /* would do overlay composition on what was in the window. Instead it */
367 : /* overwrites the window, and retains the alpha channel so that the */
368 : /* window becomes translucent, rather than the image. */
369 : /* In otherwords, it is totally useless to me */
370 : /* gdisp->supports_alpha_images = true; */
371 0 : gdisp->supports_alpha_windows = true;
372 0 : break;
373 : }
374 : }
375 0 : if ( extlist!=NULL )
376 0 : XFreeExtensionList(extlist);
377 :
378 0 : _GXDraw_FindVisual(gdisp);
379 0 : if ( gdisp->depth!=32 && gdisp->supports_alpha_images )
380 0 : gdisp->supports_alpha_images = false;
381 :
382 0 : vclass = gdisp->visual->class;
383 0 : depth = gdisp->depth;
384 :
385 0 : if ( depth<=8 ) {
386 0 : memset(&clut,'\0',sizeof(clut));
387 0 : if ( vclass==StaticGray || vclass == GrayScale ) {
388 0 : _GXDraw_AllocGreys(gdisp);
389 0 : gdisp->cs.is_grey = clut.is_grey = true;
390 0 : x_color_max = FindAllColors(gdisp,x_colors);
391 0 : } else if ( gdisp->desired_cm==cmt_private ) {
392 0 : gdisp->cmap = XCreateColormap(gdisp->display,gdisp->root,
393 : gdisp->visual,AllocNone);
394 0 : XInstallColormap(gdisp->display,gdisp->cmap);
395 0 : x_color_max = _GXDraw_AllocColors(gdisp,x_colors);
396 : } else {
397 0 : x_color_max = _GXDraw_AllocColors(gdisp,x_colors);
398 0 : if (( gdisp->desired_cm==cmt_default && x_color_max<30 ) ||
399 0 : gdisp->desired_cm==cmt_copy ) {
400 0 : x_color_max = _GXDraw_CopyColors(gdisp,x_colors,
401 : XCreateColormap(gdisp->display,gdisp->root,
402 : gdisp->visual,AllocAll));
403 0 : XInstallColormap(gdisp->display,gdisp->cmap);
404 : }
405 : }
406 0 : clut.clut_len = x_color_max;
407 0 : for ( i=0; i<x_color_max; ++i )
408 0 : clut.clut[x_colors[i].pixel] = COLOR_CREATE(x_colors[i].red>>8,x_colors[i].green>>8,x_colors[i].blue>>8);
409 0 : gdisp->cs.rev = GClutReverse(&clut,8);
410 0 : } else if ( vclass==TrueColor )
411 0 : InitTrueColor(gdisp);
412 0 : }
413 :
414 0 : unsigned long _GXDraw_GetScreenPixel(GXDisplay *gdisp, Color col) {
415 :
416 0 : if ( gdisp->depth==24 )
417 0 : return( Pixel24(gdisp,col) );
418 0 : else if ( gdisp->depth==32 )
419 0 : return( Pixel32(gdisp,col) );
420 0 : else if ( gdisp->depth>8 )
421 0 : return( Pixel16(gdisp,col));
422 :
423 0 : return( _GImage_GetIndexedPixel/*Precise*/(col, gdisp->cs.rev)->pixel );
424 : }
425 :
426 : /* ****************************** Error Handler ***************************** */
427 :
428 : static char *XProtocolCodes[] = {
429 : "X_Undefined_0",
430 : "X_CreateWindow",
431 : "X_ChangeWindowAttributes",
432 : "X_GetWindowAttributes",
433 : "X_DestroyWindow",
434 : "X_DestroySubwindows",
435 : "X_ChangeSaveSet",
436 : "X_ReparentWindow",
437 : "X_MapWindow",
438 : "X_MapSubwindows",
439 : "X_UnmapWindow",
440 : "X_UnmapSubwindows",
441 : "X_ConfigureWindow",
442 : "X_CirculateWindow",
443 : "X_GetGeometry",
444 : "X_QueryTree",
445 : "X_InternAtom",
446 : "X_GetAtomName",
447 : "X_ChangeProperty",
448 : "X_DeleteProperty",
449 : "X_GetProperty",
450 : "X_ListProperties",
451 : "X_SetSelectionOwner",
452 : "X_GetSelectionOwner",
453 : "X_ConvertSelection",
454 : "X_SendEvent",
455 : "X_GrabPointer",
456 : "X_UngrabPointer",
457 : "X_GrabButton",
458 : "X_UngrabButton",
459 : "X_ChangeActivePointerGrab",
460 : "X_GrabKeyboard",
461 : "X_UngrabKeyboard",
462 : "X_GrabKey",
463 : "X_UngrabKey",
464 : "X_AllowEvents",
465 : "X_GrabServer",
466 : "X_UngrabServer",
467 : "X_QueryPointer",
468 : "X_GetMotionEvents",
469 : "X_TranslateCoords",
470 : "X_WarpPointer",
471 : "X_SetInputFocus",
472 : "X_GetInputFocus",
473 : "X_QueryKeymap",
474 : "X_OpenFont",
475 : "X_CloseFont",
476 : "X_QueryFont",
477 : "X_QueryTextExtents",
478 : "X_ListFonts",
479 : "X_ListFontsWithInfo",
480 : "X_SetFontPath",
481 : "X_GetFontPath",
482 : "X_CreatePixmap",
483 : "X_FreePixmap",
484 : "X_CreateGC",
485 : "X_ChangeGC",
486 : "X_CopyGC",
487 : "X_SetDashes",
488 : "X_SetClipRectangles",
489 : "X_FreeGC",
490 : "X_ClearArea",
491 : "X_CopyArea",
492 : "X_CopyPlane",
493 : "X_PolyPoint",
494 : "X_PolyLine",
495 : "X_PolySegment",
496 : "X_PolyRectangle",
497 : "X_PolyArc",
498 : "X_FillPoly",
499 : "X_PolyFillRectangle",
500 : "X_PolyFillArc",
501 : "X_PutImage",
502 : "X_GetImage",
503 : "X_PolyText8",
504 : "X_PolyText16",
505 : "X_ImageText8",
506 : "X_ImageText16",
507 : "X_CreateColormap",
508 : "X_FreeColormap",
509 : "X_CopyColormapAndFree",
510 : "X_InstallColormap",
511 : "X_UninstallColormap",
512 : "X_ListInstalledColormaps",
513 : "X_AllocColor",
514 : "X_AllocNamedColor",
515 : "X_AllocColorCells",
516 : "X_AllocColorPlanes",
517 : "X_FreeColors",
518 : "X_StoreColors",
519 : "X_StoreNamedColor",
520 : "X_QueryColors",
521 : "X_LookupColor",
522 : "X_CreateCursor",
523 : "X_CreateGlyphCursor",
524 : "X_FreeCursor",
525 : "X_RecolorCursor",
526 : "X_QueryBestSize",
527 : "X_QueryExtension",
528 : "X_ListExtensions",
529 : "X_ChangeKeyboardMapping",
530 : "X_GetKeyboardMapping",
531 : "X_ChangeKeyboardControl",
532 : "X_GetKeyboardControl",
533 : "X_Bell",
534 : "X_ChangePointerControl",
535 : "X_GetPointerControl",
536 : "X_SetScreenSaver",
537 : "X_GetScreenSaver",
538 : "X_ChangeHosts",
539 : "X_ListHosts",
540 : "X_SetAccessControl",
541 : "X_SetCloseDownMode",
542 : "X_KillClient",
543 : "X_RotateProperties",
544 : "X_ForceScreenSaver",
545 : "X_SetPointerMapping",
546 : "X_GetPointerMapping",
547 : "X_SetModifierMapping",
548 : "X_GetModifierMapping",
549 : "X_Undefined_120",
550 : "X_Undefined_121",
551 : "X_Undefined_122",
552 : "X_Undefined_123",
553 : "X_Undefined_124",
554 : "X_Undefined_125",
555 : "X_Undefined_126",
556 : "X_NoOperation"
557 : };
558 :
559 : static char *lastfontrequest;
560 :
561 0 : static int myerrorhandler(Display *disp, XErrorEvent *err) {
562 : /* Under twm I get a bad match, under kde a bad window? */
563 : char buffer[200], *majorcode;
564 :
565 0 : if (err->request_code>0 && err->request_code<128)
566 0 : majorcode = XProtocolCodes[err->request_code];
567 : else
568 0 : majorcode = "";
569 0 : if ( err->request_code==45 && lastfontrequest!=NULL )
570 0 : fprintf( stderr, "Error attempting to load font:\n %s\nThe X Server claimed the font existed, but when I asked for it,\nI got this error instead:\n\n", lastfontrequest );
571 0 : XGetErrorText(disp,err->error_code,buffer,sizeof(buffer));
572 0 : fprintf( stderr, "X Error of failed request: %s\n", buffer );
573 0 : fprintf( stderr, " Major opcode of failed request: %d.%d (%s)\n",
574 0 : err->request_code, err->minor_code, majorcode );
575 0 : fprintf( stderr, " Serial number of failed request: %ld\n", (long) err->serial );
576 0 : fprintf( stderr, " Failed resource ID: %x\n", (unsigned int) err->resourceid );
577 0 : raise(SIGABRT); /* I want something that alerts the debugger, not a semi-successful exit */
578 0 : return( 1 );
579 : }
580 :
581 : /* ************************************************************************** */
582 :
583 0 : static void _GXDraw_InitAtoms( GXDisplay *gdisp) {
584 0 : Display *display = gdisp->display;
585 0 : gdisp->atoms.wm_del_window = XInternAtom(display,"WM_DELETE_WINDOW",False);
586 0 : gdisp->atoms.wm_protocols = XInternAtom(display,"WM_PROTOCOLS",False);
587 0 : gdisp->atoms.drag_and_drop = XInternAtom(display,"DRAG_AND_DROP",False);
588 0 : }
589 :
590 : static Cursor StdCursor[ct_user] = { 0 };
591 : static int cursor_map[ct_user] = { 0,
592 : XC_left_ptr, /* pointer */
593 : XC_right_ptr, /* backpointer */
594 : XC_hand2, /* hand */
595 : XC_question_arrow, /* question */
596 : XC_tcross, /* cross */
597 : XC_fleur, /* 4way */
598 : XC_xterm, /* text */
599 : XC_watch, /* watch */
600 : XC_right_ptr }; /* drag and drop */
601 :
602 0 : static Cursor _GXDraw_GetCursor( GXDisplay *gdisp, enum cursor_types ct ) {
603 0 : Display *display = gdisp->display;
604 :
605 0 : if ( ct>=ct_user )
606 0 : return( ct-ct_user );
607 0 : else if ( ct==ct_default )
608 0 : return( CopyFromParent );
609 0 : if ( StdCursor[ct]==0 ) {
610 : XColor fb[2];
611 0 : fb[0].red = COLOR_RED(gdisp->def_foreground)*0x101; fb[0].green = COLOR_GREEN(gdisp->def_foreground)*0x101; fb[0].blue = COLOR_BLUE(gdisp->def_foreground)*0x101;
612 0 : fb[1].red = COLOR_RED(gdisp->def_background)*0x101; fb[1].green = COLOR_GREEN(gdisp->def_background)*0x101; fb[1].blue = COLOR_BLUE(gdisp->def_background)*0x101;
613 0 : if ( ct==ct_invisible ) {
614 : static short zeros[16]={0};
615 0 : Pixmap temp = XCreatePixmapFromBitmapData(display,gdisp->root,
616 : (char *) zeros,16,16,1,0,1);
617 0 : StdCursor[ct] = XCreatePixmapCursor(display,temp,temp,&fb[0],&fb[1],0,0);
618 0 : XFreePixmap(display,temp);
619 : } else {
620 0 : StdCursor[ct] = XCreateFontCursor(display,cursor_map[ct]);
621 : /*XRecolorCursor(display,StdCursor[ct],&fb[0],&fb[1]);*/
622 : }
623 : }
624 0 : return( StdCursor[ct]);
625 : }
626 :
627 : /* ************************************************************************** */
628 : /* ************************** Utility Routines ****************************** */
629 : /* ************************************************************************** */
630 :
631 0 : static void initParentissimus(GXDisplay *gdisp, Window wind) {
632 0 : Display *display = gdisp->display;
633 : Window par, *children, root;
634 : unsigned int junk,width,height; int sjunk;
635 :
636 : while (1) {
637 0 : XQueryTree(display,wind,&root,&par,&children,&junk);
638 0 : XFree(children);
639 0 : if ( par==root )
640 0 : break;
641 0 : wind = par;
642 0 : }
643 0 : XGetGeometry(display,wind,&root,&sjunk,&sjunk,&width,&height,
644 : &junk,&junk);
645 0 : if (( width>DisplayWidth(display,gdisp->screen) &&
646 0 : height>=DisplayHeight(display,gdisp->screen)) ||
647 0 : ( width>=DisplayWidth(display,gdisp->screen) &&
648 0 : height>DisplayHeight(display,gdisp->screen)) )
649 0 : gdisp->virtualRoot = wind;
650 : else
651 0 : gdisp->virtualRoot = root;
652 0 : }
653 :
654 0 : static int qterror(Display *disp, XErrorEvent *err) {
655 : /* under kde a bad window? */
656 0 : if ( err->error_code == BadMatch || err->error_code == BadWindow ) {
657 : } else {
658 0 : myerrorhandler(disp,err);
659 : }
660 0 : return( 1 );
661 : }
662 :
663 0 : static Window GetParentissimus(GXWindow gw) {
664 0 : GXDisplay *gdisp = gw->display;
665 0 : Display *display = gdisp->display;
666 0 : Window par, *children, root, wind = gw->w;
667 : unsigned int junk;
668 : fd_set junkset;
669 : struct timeval tenthsec;
670 :
671 0 : if ( gw->parentissimus )
672 0 : return( gw->parentissimus );
673 0 : if ( gdisp->virtualRoot==BadAlloc ) /* Check for vtwm */
674 0 : initParentissimus(gdisp,wind);
675 :
676 : /* For reasons quite obscure to me, XQueryTree gives a BadWindow error */
677 : /* under kde and gnome if there is no pause in the loop. XQueryTree */
678 : /* isn't even documented to fail, so it's all very strange */
679 0 : FD_ZERO(&junkset);
680 0 : tenthsec.tv_sec = 0;
681 0 : tenthsec.tv_usec = 100000;
682 :
683 0 : XSync(gdisp->display,false);
684 0 : GDrawProcessPendingEvents((GDisplay *) gdisp);
685 0 : XSetErrorHandler(/*gdisp->display,*/qterror);
686 :
687 : /* Find the top window, some window managers will add two layers of */
688 : /* decoration windows, (some might add none), some will have a virtualRoot*/
689 : while (1) {
690 0 : if ( XQueryTree(display,wind,&root,&par,&children,&junk)==0 ) {
691 0 : XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
692 0 : return( gw->w ); /* How can it fail? It does though */
693 : }
694 0 : if (children)
695 0 : XFree(children);
696 0 : if ( par==root || par==gdisp->virtualRoot ) {
697 0 : gw->parentissimus = wind;
698 0 : XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
699 0 : return(wind);
700 : }
701 0 : wind = par;
702 0 : select(0,&junkset,&junkset,&junkset,&tenthsec);
703 0 : }
704 : }
705 :
706 : /* ************************************************************************** */
707 : /* ************************** Control Routines ****************************** */
708 : /* ************************************************************************** */
709 :
710 0 : static void GXDrawInit(GDisplay *gdisp) {
711 0 : _GXDraw_InitCols( (GXDisplay *) gdisp);
712 0 : _GXDraw_InitAtoms( (GXDisplay *) gdisp);
713 0 : _GXDraw_InitFonts((GXDisplay *) gdisp);
714 0 : }
715 :
716 0 : static void GXDrawTerm(GDisplay *gdisp) {
717 0 : }
718 :
719 0 : static void *GXDrawNativeDisplay(GDisplay *gdisp) {
720 0 : return( ((GXDisplay *) gdisp)->display );
721 : }
722 :
723 0 : static GGC *_GXDraw_NewGGC() {
724 0 : GGC *ggc = calloc(1,sizeof(GGC));
725 0 : ggc->clip.width = ggc->clip.height = 0x7fff;
726 0 : ggc->fg = 0;
727 0 : ggc->bg = 0xffffff;
728 0 : return( ggc );
729 : }
730 :
731 0 : static void GXDrawSetDefaultIcon(GWindow icon) {
732 0 : GXDisplay *gdisp = (GXDisplay *) (icon->display);
733 :
734 0 : gdisp->default_icon = (GXWindow) icon;
735 0 : }
736 :
737 0 : static Window MakeIconWindow(GXDisplay *gdisp, GXWindow pixmap) {
738 : XSetWindowAttributes attrs;
739 0 : unsigned long wmask = 0;
740 :
741 0 : if ( !gdisp->default_visual ) {
742 0 : attrs.colormap = gdisp->cmap;
743 0 : wmask |= CWColormap;
744 : }
745 0 : wmask |= CWBackPixmap;
746 0 : attrs.background_pixmap = pixmap->w;
747 0 : return( XCreateWindow(gdisp->display, gdisp->root,
748 0 : 0, 0, pixmap->pos.width, pixmap->pos.height,
749 : 0,
750 0 : gdisp->depth, InputOutput, gdisp->visual, wmask, &attrs));
751 : }
752 :
753 : #if 0
754 : static void _GXDraw_DestroyWindow(GXDisplay *gdisp, GWindow input) {
755 : // TODO: Reconcile differences between this function (written from _GXDraw_CreateWindow)
756 : // with the actual function GXDrawDestroyWindow below.
757 : GXWindow inputc = (GXWindow)input;
758 : if (inputc->w != NULL) {
759 : if (inputc->is_pixmap) {
760 : XFreePixmap(gdisp->display, inputc->w);
761 : } else {
762 : XDestroyWindow(gdisp->display, inputc->w);
763 : }
764 : inputc->w = NULL;
765 : }
766 : if (inputc->gc != NULL) { XFreeGC(gdisp->display, inputc->gc); inputc->gc = NULL; }
767 : free(input);
768 : }
769 : #endif // 0
770 :
771 0 : static GWindow _GXDraw_CreateWindow(GXDisplay *gdisp, GXWindow gw, GRect *pos,
772 : int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
773 : Window parent;
774 0 : Display *display = gdisp->display;
775 0 : GXWindow nw = calloc(1,sizeof(struct gxwindow));
776 : XSetWindowAttributes attrs;
777 : static GWindowAttrs temp = GWINDOWATTRS_EMPTY;
778 0 : unsigned long wmask = 0;
779 : XClassHint ch;
780 : char *pt;
781 :
782 0 : if ( gw==NULL )
783 0 : gw = gdisp->groot;
784 0 : parent = gw->w;
785 0 : if ( wattrs==NULL ) wattrs = &temp;
786 0 : if ( nw==NULL )
787 0 : return( NULL );
788 0 : nw->ggc = _GXDraw_NewGGC();
789 0 : if ( nw->ggc==NULL ) {
790 0 : free(nw);
791 0 : return( NULL );
792 : }
793 0 : nw->display = gdisp;
794 0 : nw->eh = eh;
795 0 : nw->parent = gw;
796 0 : nw->pos = *pos;
797 0 : nw->user_data = user_data;
798 :
799 0 : attrs.bit_gravity = NorthWestGravity;
800 0 : wmask |= CWBitGravity;
801 0 : if ( (wattrs->mask&wam_bordcol) && wattrs->border_color!=COLOR_UNKNOWN ) {
802 0 : attrs.border_pixel = _GXDraw_GetScreenPixel(gdisp,wattrs->border_color);
803 0 : wmask |= CWBorderPixel;
804 : }
805 0 : if ( !(wattrs->mask&wam_backcol) || wattrs->background_color==COLOR_DEFAULT )
806 0 : wattrs->background_color = gdisp->def_background;
807 0 : if ( wattrs->background_color != COLOR_UNKNOWN ) {
808 0 : attrs.background_pixel = _GXDraw_GetScreenPixel(gdisp,wattrs->background_color);
809 0 : wmask |= CWBackPixel;
810 : }
811 0 : nw->ggc->bg = wattrs->background_color;
812 0 : if ( (wattrs->mask&wam_cursor) && wattrs->cursor!=0 ) {
813 0 : attrs.cursor = _GXDraw_GetCursor(gdisp,wattrs->cursor);
814 0 : wmask |= CWCursor;
815 : }
816 0 : if ( (wattrs->mask&wam_nodecor) && wattrs->nodecoration ) {
817 0 : attrs.override_redirect = true;
818 0 : wmask |= CWOverrideRedirect;
819 0 : nw->is_popup = true;
820 0 : nw->is_dlg = true;
821 0 : nw->not_restricted = true;
822 : }
823 0 : if ( (wattrs->mask&wam_isdlg) && wattrs->is_dlg ) {
824 0 : nw->is_dlg = true;
825 : }
826 0 : if ( (wattrs->mask&wam_notrestricted) && wattrs->not_restricted ) {
827 0 : nw->not_restricted = true;
828 : }
829 0 : if ( !gdisp->default_visual ) {
830 0 : attrs.colormap = gdisp->cmap;
831 0 : wmask |= CWColormap|CWBackPixel|CWBorderPixel;
832 : /* CopyFromParent doesn't work if we've got different visuals!!!! */
833 : }
834 0 : wmask |= CWEventMask;
835 0 : attrs.event_mask = ExposureMask|StructureNotifyMask/*|PropertyChangeMask*/;
836 0 : if ( gw==gdisp->groot )
837 0 : attrs.event_mask |= FocusChangeMask|EnterWindowMask|LeaveWindowMask;
838 0 : if ( wattrs->mask&wam_events ) {
839 0 : if ( wattrs->event_masks&(1<<et_char) )
840 0 : attrs.event_mask |= KeyPressMask;
841 0 : if ( wattrs->event_masks&(1<<et_charup) )
842 0 : attrs.event_mask |= KeyReleaseMask;
843 0 : if ( wattrs->event_masks&(1<<et_mousemove) )
844 0 : attrs.event_mask |= PointerMotionMask;
845 0 : if ( wattrs->event_masks&(1<<et_mousedown) )
846 0 : attrs.event_mask |= ButtonPressMask;
847 0 : if ( wattrs->event_masks&(1<<et_mouseup) )
848 0 : attrs.event_mask |= ButtonReleaseMask;
849 0 : if ( (wattrs->event_masks&(1<<et_mouseup)) && (wattrs->event_masks&(1<<et_mousedown)) )
850 0 : attrs.event_mask |= OwnerGrabButtonMask;
851 0 : if ( wattrs->event_masks&(1<<et_visibility) )
852 0 : attrs.event_mask |= VisibilityChangeMask;
853 : }
854 :
855 : /* Only put the new dlgs underneath the cursor if focusfollows mouse, where */
856 : /* they need to be there... */
857 0 : if ( gw == gdisp->groot &&
858 0 : ( ((wattrs->mask&wam_centered) && wattrs->centered) ||
859 0 : ((wattrs->mask&wam_undercursor) && wattrs->undercursor && !gdisp->focusfollowsmouse)) ) {
860 0 : pos->x = (gdisp->groot->pos.width-pos->width)/2;
861 0 : pos->y = (gdisp->groot->pos.height-pos->height)/2;
862 0 : if ( wattrs->centered==2 )
863 0 : pos->y = (gdisp->groot->pos.height-pos->height)/3;
864 0 : nw->pos = *pos;
865 0 : } else if ( (wattrs->mask&wam_undercursor) && wattrs->undercursor && gw == gdisp->groot) {
866 : int junk;
867 : Window wjunk;
868 : int x, y; unsigned int state;
869 :
870 0 : XQueryPointer(display,gw->w,&wjunk,&wjunk,&junk,&junk,&x,&y,&state);
871 0 : pos->x = x-pos->width/2;
872 0 : pos->y = y-pos->height/2-(!gdisp->top_offsets_set?20:gdisp->off_y);
873 0 : if ( pos->x+pos->width>gdisp->groot->pos.width ) pos->x = gdisp->groot->pos.width-pos->width;
874 0 : if ( pos->x<0 ) pos->x = 0;
875 0 : if ( pos->y+pos->height>gdisp->groot->pos.height ) pos->y = gdisp->groot->pos.height-pos->height;
876 0 : if ( pos->y<0 ) pos->y = 0;
877 0 : nw->pos = *pos;
878 : }
879 0 : nw->w = XCreateWindow(display, parent,
880 0 : pos->x, pos->y, pos->width, pos->height,
881 0 : (wattrs->mask&wam_bordwidth)?wattrs->border_width:0,
882 0 : gdisp->depth, InputOutput, gdisp->visual, wmask, &attrs);
883 0 : if ( gdisp->gcstate[0].gc==NULL ) {
884 : XGCValues vals;
885 0 : gdisp->gcstate[0].gc = XCreateGC(display,nw->w,0,&vals);
886 : }
887 :
888 0 : if ( gw == gdisp->groot ) {
889 : XWMHints wm_hints;
890 : XSizeHints s_h;
891 0 : wm_hints.flags = InputHint | StateHint;
892 0 : wm_hints.input = True;
893 0 : wm_hints.initial_state = NormalState;
894 0 : if ( ((wattrs->mask&wam_icon) && wattrs->icon!=NULL ) ||
895 0 : ( !(wattrs->mask&wam_icon) && gdisp->default_icon!=NULL )) {
896 0 : GXWindow icon = (wattrs->mask&wam_icon)? (GXWindow) (wattrs->icon) : gdisp->default_icon;
897 0 : wm_hints.icon_pixmap = icon->w;
898 0 : wm_hints.flags |= IconPixmapHint;
899 0 : if ( !icon->ggc->bitmap_col && gdisp->depth!=1 ) {
900 : /* X Icons are bitmaps. If we want a pixmap we create a dummy */
901 : /* window with the pixmap as background */
902 0 : wm_hints.icon_window = MakeIconWindow(gdisp,icon);
903 0 : wm_hints.flags |= IconWindowHint;
904 : }
905 : }
906 0 : XSetWMHints(display,nw->w,&wm_hints);
907 0 : if ( (wattrs->mask&wam_wtitle) && wattrs->window_title!=NULL ) {
908 0 : XmbSetWMProperties(display,nw->w,(pt = u2def_copy(wattrs->window_title)),NULL,NULL,0,NULL,NULL,NULL);
909 0 : free(pt);
910 : }
911 0 : if ( (wattrs->mask&wam_ititle) && wattrs->icon_title!=NULL ) {
912 0 : XmbSetWMProperties(display,nw->w,NULL,(pt = u2def_copy(wattrs->icon_title)),NULL,0,NULL,NULL,NULL);
913 0 : free(pt);
914 : }
915 0 : if ( (wattrs->mask&wam_utf8_wtitle) && wattrs->utf8_window_title!=NULL ) {
916 : #ifdef X_HAVE_UTF8_STRING
917 0 : Xutf8SetWMProperties(display, nw->w, wattrs->utf8_window_title, NULL, NULL, 0, NULL, NULL, NULL);
918 : #else
919 : unichar_t *tit = utf82u_copy(wattrs->utf8_window_title);
920 : XmbSetWMProperties(display,nw->w,(pt = u2def_copy(tit)),NULL,NULL,0,NULL,NULL,NULL);
921 : free(pt); free(tit);
922 : #endif
923 : }
924 0 : if ( (wattrs->mask&wam_utf8_ititle) && wattrs->utf8_icon_title!=NULL ) {
925 : #ifdef X_HAVE_UTF8_STRING
926 0 : Xutf8SetWMProperties(display, nw->w, NULL, wattrs->utf8_icon_title, NULL, 0, NULL, NULL, NULL);
927 : #else
928 : unichar_t *tit = utf82u_copy(wattrs->utf8_icon_title);
929 : XmbSetWMProperties(display,nw->w,NULL,(pt = u2def_copy(tit)),NULL,0,NULL,NULL,NULL);
930 : free(pt); free(tit);
931 : #endif
932 : }
933 0 : s_h.x = pos->x; s_h.y = pos->y;
934 0 : s_h.base_width = s_h.width = pos->width; s_h.base_height = s_h.height = pos->height;
935 0 : s_h.min_width = s_h.max_width = s_h.width;
936 0 : s_h.min_height = s_h.max_height = s_h.height;
937 0 : s_h.flags = PPosition | PSize | PBaseSize;
938 0 : if (( (wattrs->mask&wam_positioned) && wattrs->positioned ) ||
939 0 : ((wattrs->mask&wam_centered) && wattrs->centered ) ||
940 0 : ((wattrs->mask&wam_undercursor) && wattrs->undercursor )) {
941 0 : s_h.flags = USPosition | USSize | PBaseSize;
942 0 : nw->was_positioned = true;
943 : }
944 0 : if ( (wattrs->mask&wam_noresize) && wattrs->noresize )
945 0 : s_h.flags |= PMinSize | PMaxSize;
946 0 : XSetNormalHints(display,nw->w,&s_h);
947 0 : XSetWMProtocols(display,nw->w,&gdisp->atoms.wm_del_window,1);
948 0 : if ( wattrs->mask&wam_restrict )
949 0 : nw->restrict_input_to_me = wattrs->restrict_input_to_me;
950 0 : if ( wattrs->mask&wam_redirect ) {
951 0 : nw->redirect_chars_to_me = wattrs->redirect_chars_to_me;
952 0 : nw->redirect_from = wattrs->redirect_from;
953 : }
954 0 : if ( (wattrs->mask&wam_transient) && wattrs->transient!=NULL ) {
955 0 : XSetTransientForHint(display,nw->w,((GXWindow) (wattrs->transient))->w);
956 0 : nw->istransient = true;
957 0 : nw->transient_owner = ((GXWindow) (wattrs->transient))->w;
958 0 : nw->is_dlg = true;
959 0 : } else if ( !nw->is_dlg )
960 0 : ++gdisp->top_window_count;
961 0 : else if ( nw->restrict_input_to_me && gdisp->last_nontransient_window!=0 ) {
962 0 : XSetTransientForHint(display,nw->w,gdisp->last_nontransient_window);
963 0 : nw->transient_owner = gdisp->last_nontransient_window;
964 0 : nw->istransient = true;
965 : }
966 0 : nw->isverytransient = (wattrs->mask&wam_verytransient)?1:0;
967 0 : nw->is_toplevel = true;
968 0 : XChangeProperty(display,nw->w,gdisp->atoms.wm_protocols,XA_ATOM,32,
969 0 : PropModeReplace,(unsigned char *) &gdisp->atoms.wm_del_window, 1);
970 : }
971 0 : ch.res_class = GResourceProgramName;
972 0 : ch.res_name = GResourceProgramName;
973 0 : XSetClassHint(display,nw->w,&ch);
974 0 : XSaveContext(display,nw->w,gdisp->mycontext,(void *) nw);
975 0 : if ( eh!=NULL ) {
976 : GEvent e;
977 0 : memset(&e,0,sizeof(e));
978 0 : e.type = et_create;
979 0 : e.w = (GWindow) nw;
980 0 : e.native_window = (void *) (intpt) nw->w;
981 0 : (eh)((GWindow) nw,&e);
982 : }
983 : #ifndef _NO_LIBCAIRO
984 : /* Only do sub-pixel/anti-alias stuff if we've got truecolor */
985 0 : if ( gdisp->visual->class==TrueColor && !(wattrs->mask&wam_nocairo) &&_GXCDraw_hasCairo() )
986 0 : _GXCDraw_NewWindow(nw);
987 : #endif
988 : /* Must come after the cairo init so pango will know to use cairo or xft */
989 : /* I think we will always want to use pango, so it isn't conditional on a wam */
990 0 : _GXPDraw_NewWindow(nw);
991 0 : return( (GWindow) nw );
992 : }
993 :
994 0 : static GWindow GXDrawCreateTopWindow(GDisplay *gdisp, GRect *pos,
995 : int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
996 0 : return( _GXDraw_CreateWindow((GXDisplay *) gdisp,NULL,pos,eh,user_data, wattrs));
997 : }
998 :
999 0 : static GWindow GXDrawCreateSubWindow(GWindow w, GRect *pos,
1000 : int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
1001 0 : return( _GXDraw_CreateWindow(((GXWindow) w)->display,(GXWindow) w,pos,eh,user_data, wattrs));
1002 : }
1003 :
1004 0 : static void GXDrawSetZoom(GWindow w, GRect *pos, enum gzoom_flags flags) {
1005 : XSizeHints zoom, normal;
1006 0 : Display *display = ((GXWindow) w)->display->display;
1007 : long supplied_return;
1008 :
1009 0 : memset(&zoom,0,sizeof(zoom));
1010 0 : if ( flags&gzf_pos ) {
1011 0 : zoom.x = pos->x;
1012 0 : zoom.y = pos->y;
1013 0 : zoom.flags = PPosition;
1014 : }
1015 0 : if ( flags&gzf_size ) {
1016 0 : zoom.width = zoom.base_width = zoom.max_width = pos->width;
1017 0 : zoom.height = zoom.base_height = zoom.max_height = pos->height;
1018 0 : zoom.flags |= PSize | PBaseSize | PMaxSize;
1019 0 : XGetWMNormalHints(display,((GXWindow) w)->w,&normal,&supplied_return);
1020 0 : normal.flags |= PMaxSize;
1021 0 : normal.max_width = pos->width;
1022 0 : normal.max_height = pos->height;
1023 0 : XSetWMNormalHints(display,((GXWindow) w)->w,&normal);
1024 : }
1025 0 : XSetWMSizeHints(display,((GXWindow) w)->w,&zoom,XA_WM_ZOOM_HINTS);
1026 0 : }
1027 :
1028 0 : static GWindow GXDrawCreatePixmap(GDisplay *gdisp, uint16 width, uint16 height) {
1029 0 : GXWindow gw = calloc(1,sizeof(struct gxwindow));
1030 0 : int wamcairo = false;
1031 :
1032 0 : if ( gw==NULL )
1033 0 : return( NULL );
1034 0 : gw->ggc = _GXDraw_NewGGC();
1035 0 : gw->ggc->bg = ((GXDisplay *) gdisp)->def_background;
1036 0 : if ( gw->ggc==NULL ) {
1037 0 : free(gw);
1038 0 : return( NULL );
1039 : }
1040 0 : if ( width&0x8000 ) {
1041 0 : width &= 0x7fff;
1042 0 : wamcairo = true;
1043 : }
1044 : // icon windows.
1045 0 : if ( width == 48 ) {
1046 0 : wamcairo = true;
1047 : }
1048 :
1049 0 : gw->display = (GXDisplay *) gdisp;
1050 0 : gw->is_pixmap = 1;
1051 0 : gw->parent = NULL;
1052 0 : gw->pos.x = gw->pos.y = 0;
1053 0 : gw->pos.width = width; gw->pos.height = height;
1054 0 : gw->w = XCreatePixmap(gw->display->display, gw->display->root, width, height, gw->display->depth);
1055 : #ifndef _NO_LIBCAIRO
1056 : /* Only do sub-pixel/anti-alias stuff if we've got truecolor */
1057 0 : if ( ((GXDisplay *) gdisp)->visual->class==TrueColor && wamcairo &&
1058 0 : _GXCDraw_hasCairo() )
1059 0 : _GXCDraw_NewWindow(gw);
1060 : #endif
1061 : /* Must come after the cairo init so pango will know to use cairo or xft */
1062 : /* I think we will always want to use pango, so it isn't conditional */
1063 0 : _GXPDraw_NewWindow(gw);
1064 0 : return( (GWindow) gw );
1065 : }
1066 :
1067 0 : static GWindow GXDrawCreateBitmap(GDisplay *disp, uint16 width, uint16 height, uint8 *data) {
1068 0 : GXDisplay *gdisp = (GXDisplay *) disp;
1069 0 : GXWindow gw = calloc(1,sizeof(struct gxwindow));
1070 :
1071 0 : if ( gw==NULL )
1072 0 : return( NULL );
1073 0 : gw->ggc = _GXDraw_NewGGC();
1074 0 : if ( gw->ggc==NULL ) {
1075 0 : free(gw);
1076 0 : return( NULL );
1077 : }
1078 0 : gw->ggc->bitmap_col = true;
1079 0 : gw->display = (GXDisplay *) gdisp;
1080 0 : gw->is_pixmap = 1;
1081 0 : gw->parent = NULL;
1082 0 : gw->pos.x = gw->pos.y = 0;
1083 0 : gw->pos.width = width; gw->pos.height = height;
1084 0 : if ( data==NULL )
1085 0 : gw->w = XCreatePixmap(gdisp->display, gw->display->root, width, height, 1);
1086 : else
1087 0 : gw->w = XCreateBitmapFromData(gdisp->display, gw->display->root,
1088 : (char *) data, width, height );
1089 0 : if ( gdisp->gcstate[1].gc==NULL ) {
1090 : XGCValues vals;
1091 0 : gdisp->gcstate[1].gc = XCreateGC(gdisp->display,gw->w,0,&vals);
1092 : }
1093 0 : return( (GWindow) gw );
1094 : }
1095 :
1096 0 : static GCursor GXDrawCreateCursor(GWindow src,GWindow mask,Color fg,Color bg,
1097 : int16 x, int16 y ) {
1098 0 : GXDisplay *gdisp = (GXDisplay *) (src->display);
1099 0 : Display *display = gdisp->display;
1100 : XColor fgc, bgc;
1101 : /* The XServer shipping with redhat 7.1 seems to suffer a protocol change */
1102 : /* with the red and blue members of XColor structure reversed */
1103 : /* The XServer runing on Mac OS/X can only handle 16x16 cursors */
1104 :
1105 0 : fgc.red = COLOR_RED(fg)*0x101; fgc.green = COLOR_GREEN(fg)*0x101; fgc.blue = COLOR_BLUE(fg)*0x101;
1106 0 : bgc.red = COLOR_RED(bg)*0x101; bgc.green = COLOR_GREEN(bg)*0x101; bgc.blue = COLOR_BLUE(bg)*0x101;
1107 0 : fgc.pixel = _GXDraw_GetScreenPixel(gdisp,fg); fgc.flags = -1;
1108 0 : bgc.pixel = _GXDraw_GetScreenPixel(gdisp,bg); bgc.flags = -1;
1109 0 : return( ct_user + XCreatePixmapCursor(display,((GXWindow) src)->w, ((GXWindow) mask)->w,
1110 : &fgc,&bgc, x,y));
1111 : }
1112 :
1113 : static void GTimerRemoveWindowTimers(GXWindow gw);
1114 :
1115 0 : static void GXDrawDestroyWindow(GWindow w) {
1116 0 : GXWindow gw = (GXWindow) w;
1117 :
1118 : #ifndef _NO_LIBCAIRO
1119 0 : if ( gw->usecairo )
1120 0 : _GXCDraw_DestroyWindow(gw);
1121 : #endif
1122 0 : _GXPDraw_DestroyWindow(gw);
1123 :
1124 0 : if ( gw->is_pixmap ) {
1125 0 : XFreePixmap(gw->display->display,gw->w);
1126 0 : free(gw->ggc);
1127 0 : free(gw);
1128 : } else {
1129 : /*GTimerRemoveWindowTimers(gw);*/ /* Moved to _GXDraw_CleanUpWindow, not all windows are actively destroyed */
1130 0 : gw->is_dying = true;
1131 0 : if ( gw->display->grab_window==w ) gw->display->grab_window = NULL;
1132 0 : XDestroyWindow(gw->display->display,gw->w);
1133 : /* Windows should be freed when we get the destroy event */
1134 : }
1135 0 : }
1136 :
1137 0 : static void GXDestroyCursor(GDisplay *gdisp,GCursor ct) {
1138 0 : XFreeCursor(((GXDisplay *) gdisp)->display, ct-ct_user);
1139 0 : }
1140 :
1141 0 : static int GXNativeWindowExists(GDisplay *gdisp,void *native) {
1142 : void *ret;
1143 :
1144 0 : if ( XFindContext(((GXDisplay *) gdisp)->display,(Window) (intpt) native,((GXDisplay *) gdisp)->mycontext,(void *) &ret)==0 &&
1145 0 : ret!=NULL )
1146 0 : return( true );
1147 :
1148 0 : return( false );
1149 : }
1150 :
1151 0 : static void GXDrawSetWindowBorder(GWindow w,int width,Color col) {
1152 0 : GXWindow gw = (GXWindow) w;
1153 :
1154 0 : if ( width>=0 )
1155 0 : XSetWindowBorderWidth(gw->display->display,gw->w,width);
1156 0 : if ( col!=COLOR_DEFAULT )
1157 0 : XSetWindowBorder(gw->display->display,gw->w,
1158 0 : _GXDraw_GetScreenPixel(gw->display,col));
1159 0 : }
1160 :
1161 0 : static void GXDrawSetWindowBackground(GWindow w,Color col) {
1162 0 : GXWindow gw = (GXWindow) w;
1163 :
1164 0 : if ( col!=COLOR_DEFAULT )
1165 0 : XSetWindowBackground(gw->display->display,gw->w,
1166 0 : _GXDraw_GetScreenPixel(gw->display,col));
1167 0 : }
1168 :
1169 0 : static int GXSetDither(GDisplay *gdisp,int dither) {
1170 0 : int old = ((GXDisplay *) gdisp)->do_dithering;
1171 0 : ((GXDisplay *) gdisp)->do_dithering = dither;
1172 0 : return( old );
1173 : }
1174 :
1175 0 : static void _GXDraw_RemoveRedirects(GXDisplay *gdisp,GXWindow gw) {
1176 0 : if ( gdisp->input!=NULL ) {
1177 0 : struct inputRedirect *next=gdisp->input, *test;
1178 0 : if ( next->cur_dlg == (GWindow) gw ) {
1179 0 : gdisp->input = next->prev;
1180 0 : free(next);
1181 0 : } else for ( test=next->prev; test!=NULL; test=test->prev ) {
1182 0 : if ( test->cur_dlg == (GWindow) gw ) {
1183 0 : next->prev = test->prev;
1184 0 : free( test );
1185 0 : break;
1186 : }
1187 : }
1188 : }
1189 0 : }
1190 :
1191 0 : static void _GXDraw_CleanUpWindow( GWindow w ) {
1192 0 : GXWindow gw = (GXWindow) w;
1193 0 : GXDisplay *gdisp = gw->display;
1194 : int i;
1195 : struct gxinput_context *gic, *next;
1196 :
1197 0 : XSaveContext(gdisp->display,gw->w,gdisp->mycontext,NULL);
1198 0 : if ( gdisp->grab_window==w ) gdisp->grab_window = NULL;
1199 0 : if ( gdisp->last_dd.gw==w ) {
1200 0 : gdisp->last_dd.gw = NULL;
1201 0 : gdisp->last_dd.w = None;
1202 : }
1203 :
1204 0 : GTimerRemoveWindowTimers(gw);
1205 0 : _GXDraw_RemoveRedirects(gdisp,gw);
1206 0 : if ( gdisp->groot == gw->parent && !gw->is_dlg )
1207 0 : --gdisp->top_window_count;
1208 :
1209 : /* If the window owns any selection it just lost them, cleanup our data */
1210 : /* structures... */
1211 0 : for ( i = 0; i<sn_max; ++i ) {
1212 0 : if ( gdisp->selinfo[i].owner == gw ) {
1213 0 : GXDrawClearSelData(gdisp,i);
1214 0 : gdisp->selinfo[i].owner = NULL;
1215 : }
1216 : }
1217 :
1218 : /* Does the window have any input contexts? If so get rid of them all */
1219 0 : for ( gic = gw->all; gic!=NULL; gic = next ) {
1220 0 : next = gic->next;
1221 0 : XDestroyIC(gic->ic);
1222 0 : free(gic);
1223 : }
1224 :
1225 0 : free(gw->ggc);
1226 0 : memset(gw,'\0',sizeof(*gw));
1227 0 : free(gw);
1228 0 : }
1229 :
1230 0 : static void GXDrawReparentWindow(GWindow child,GWindow newparent, int x,int y) {
1231 0 : GXWindow gchild = (GXWindow) child, gpar = (GXWindow) newparent;
1232 0 : GXDisplay *gdisp = gchild->display;
1233 : /* Gnome won't let me reparent a top level window */
1234 : /* It only pays attention to override-redirect if the window hasn't been mapped */
1235 0 : XReparentWindow(gdisp->display,gchild->w,gpar->w,x,y);
1236 0 : }
1237 :
1238 0 : static void GXDrawSetVisible(GWindow w, int visible) {
1239 0 : GXWindow gw = (GXWindow) w;
1240 0 : GXDisplay *gdisp = gw->display;
1241 :
1242 0 : if( cmdlinearg_forceUIHidden )
1243 0 : visible = false;
1244 :
1245 0 : gw->visible_request = visible;
1246 0 : if ( visible ) {
1247 0 : XMapWindow(gdisp->display,gw->w);
1248 0 : if ( gw->restrict_input_to_me || gw->redirect_chars_to_me ||
1249 0 : gw->redirect_from!=NULL ) {
1250 0 : struct inputRedirect *ir = calloc(1,sizeof(struct inputRedirect));
1251 0 : if ( ir!=NULL ) {
1252 0 : ir->prev = gdisp->input;
1253 0 : gdisp->input = ir;
1254 0 : ir->cur_dlg = (GWindow) gw;
1255 0 : if ( gw->redirect_from!=NULL ) {
1256 0 : ir->it = it_targetted;
1257 0 : ir->inactive = gw->redirect_from;
1258 0 : } else if ( gw->redirect_chars_to_me )
1259 0 : ir->it = it_redirected;
1260 : else
1261 0 : ir->it = it_restricted;
1262 : }
1263 : }
1264 0 : } else if ( !visible ) {
1265 0 : if ( gw->is_toplevel && gw->is_visible ) {
1266 : /* Save the current position in the size hints. Otherwise some */
1267 : /* window managers will pop it up where originally positioned */
1268 : /* or if unpositioned ask user to position it. Ug */
1269 : XSizeHints s_h;
1270 0 : s_h.flags = USPosition;
1271 0 : s_h.x = gw->pos.x + gdisp->off_x;
1272 0 : s_h.y = gw->pos.y + gdisp->off_y;
1273 0 : XSetNormalHints(gdisp->display,gw->w,&s_h);
1274 : }
1275 0 : if (gw->is_toplevel)
1276 0 : XWithdrawWindow(gdisp->display,gw->w,gdisp->screen);
1277 : else
1278 0 : XUnmapWindow(gdisp->display,gw->w);
1279 0 : _GXDraw_RemoveRedirects(gdisp,gw);
1280 : }
1281 0 : }
1282 :
1283 0 : static void GXDrawMove(GWindow w, int32 x, int32 y) {
1284 0 : GXWindow gw = (GXWindow) w;
1285 :
1286 0 : if ( gw->is_toplevel ) {
1287 : /* Save the current position in the size hints. Otherwise some */
1288 : /* (if unmapped) window managers will pop it up where originally */
1289 : /* positioned or if unpositioned ask user to position it. Ug */
1290 : XSizeHints s_h;
1291 0 : s_h.flags = USPosition;
1292 0 : s_h.x = x;
1293 0 : s_h.y = y;
1294 0 : XSetNormalHints(gw->display->display,gw->w,&s_h);
1295 : }
1296 0 : XMoveWindow(gw->display->display,gw->w,x,y);
1297 0 : }
1298 :
1299 0 : static void GXDrawTrueMove(GWindow w, int32 x, int32 y) {
1300 0 : GXWindow gw = (GXWindow) w;
1301 :
1302 0 : if ( gw->is_toplevel && !gw->is_popup && !gw->istransient ) {
1303 0 : x -= gw->display->off_x;
1304 0 : y -= gw->display->off_y;
1305 : }
1306 0 : GXDrawMove(w,x,y);
1307 0 : }
1308 :
1309 0 : static void GXDrawResize(GWindow w, int32 width, int32 height) {
1310 0 : GXWindow gw = (GXWindow) w;
1311 :
1312 0 : XResizeWindow(gw->display->display,gw->w,width,height);
1313 0 : if ( gw->is_toplevel ) {
1314 : XSizeHints s_h;
1315 : /* for some reason the USPosition bit gets unset if I just set the width */
1316 0 : s_h.flags = -1; /* I don't know if this is needed, but let's be paranoid */
1317 0 : XGetNormalHints(gw->display->display,gw->w,&s_h);
1318 0 : s_h.flags |= USSize;
1319 0 : s_h.width = width;
1320 0 : s_h.height = height;
1321 0 : XSetNormalHints(gw->display->display,gw->w,&s_h);
1322 : }
1323 0 : }
1324 :
1325 0 : static void GXDrawMoveResize(GWindow w, int32 x, int32 y, int32 width, int32 height) {
1326 0 : GXWindow gw = (GXWindow) w;
1327 :
1328 0 : if ( gw->is_toplevel ) {
1329 : /* Save the current position in the size hints. Otherwise some */
1330 : /* window managers will pop it up where originally positioned */
1331 : /* or if unpositioned ask user to position it. Ug */
1332 : /* Might as well do the size too... */
1333 : XSizeHints s_h;
1334 0 : s_h.flags = USPosition|USSize;
1335 0 : s_h.x = x;
1336 0 : s_h.y = y;
1337 0 : s_h.width = width;
1338 0 : s_h.height = height;
1339 0 : XSetNormalHints(gw->display->display,gw->w,&s_h);
1340 : }
1341 0 : XMoveResizeWindow(gw->display->display,gw->w,x,y,width,height);
1342 0 : }
1343 :
1344 0 : static void GXDrawRaise(GWindow w) {
1345 0 : GXWindow gw = (GXWindow) w;
1346 :
1347 0 : XRaiseWindow(gw->display->display,gw->w);
1348 0 : }
1349 :
1350 : static GXDisplay *edisp;
1351 0 : static int error(Display *disp, XErrorEvent *err) {
1352 : /* Under twm I get a bad match, under kde a bad window? */
1353 0 : if ( err->error_code == BadMatch || err->error_code == BadWindow ) {
1354 0 : if ( edisp!=NULL ) edisp->wm_breaks_raiseabove = true;
1355 : } else {
1356 0 : myerrorhandler(disp,err);
1357 : }
1358 0 : return( 1 );
1359 : }
1360 :
1361 0 : static void GXDrawRaiseAbove(GWindow w,GWindow below) {
1362 0 : GXWindow gw = (GXWindow) w, gbelow = (GXWindow) below;
1363 0 : Window gxw = gw->w, gxbelow = gbelow->w;
1364 0 : GXDisplay *gdisp = gw->display;
1365 : XWindowChanges ch;
1366 :
1367 : /* Sometimes we get a BadWindow error here for no good reason */
1368 0 : XSync(gdisp->display,false);
1369 0 : GDrawProcessPendingEvents((GDisplay *) gdisp);
1370 0 : XSetErrorHandler(/*gdisp->display,*/error);
1371 0 : if ( !gdisp->wm_raiseabove_tested ) {
1372 0 : edisp = gdisp;
1373 : } else
1374 0 : edisp = NULL;
1375 : retry:
1376 0 : if ( gdisp->wm_breaks_raiseabove ) {
1377 : /* If we do this code in gnome it breaks things */
1378 : /* if we don't do it in twm it breaks things. Sigh */
1379 0 : if ( gw->is_toplevel )
1380 0 : gxw = GetParentissimus(gw);
1381 0 : if ( gbelow->is_toplevel )
1382 0 : gxbelow = GetParentissimus(gbelow);
1383 : }
1384 0 : ch.sibling = gxbelow;
1385 0 : ch.stack_mode = Above;
1386 0 : XConfigureWindow(gdisp->display,gxw,CWSibling|CWStackMode,&ch);
1387 0 : XSync(gdisp->display,false);
1388 0 : GDrawProcessPendingEvents((GDisplay *) gdisp);
1389 0 : if ( !gdisp->wm_raiseabove_tested ) {
1390 0 : gdisp->wm_raiseabove_tested = true;
1391 0 : if ( gdisp->wm_breaks_raiseabove )
1392 0 : goto retry;
1393 : }
1394 0 : XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
1395 0 : }
1396 :
1397 0 : static int GXDrawIsAbove(GWindow w,GWindow other) {
1398 0 : GXWindow gw = (GXWindow) w, gother = (GXWindow) other;
1399 0 : Window gxw = gw->w, gxother = gother->w, parent;
1400 0 : GXDisplay *gdisp = (GXDisplay *) (gw->display);
1401 : Window par, *children, root;
1402 : unsigned int nkids; int i;
1403 :
1404 0 : if ( gw->is_toplevel && gother->is_toplevel ) {
1405 0 : gxw = GetParentissimus(gw);
1406 0 : gxother = GetParentissimus(gother);
1407 0 : parent = gdisp->root;
1408 0 : } else if ( gw->parent!=gother->parent )
1409 0 : return( -1 ); /* Incommensurate */
1410 : else
1411 0 : parent = gw->parent->w;
1412 :
1413 0 : XQueryTree(gdisp->display,parent,&root,&par,&children,&nkids);
1414 : /* bottom-most child is children[0], topmost is children[nkids-1] */
1415 0 : for ( i=nkids-1; i>=0; --i ) {
1416 0 : if ( children[i] == gxw )
1417 0 : return( true );
1418 0 : if ( children[i] == gxother )
1419 0 : return( false );
1420 : }
1421 0 : if ( children )
1422 0 : XFree(children);
1423 0 : return( -1 );
1424 : }
1425 :
1426 0 : static void GXDrawLower(GWindow w) {
1427 0 : GXWindow gw = (GXWindow) w;
1428 :
1429 0 : XLowerWindow(gw->display->display,gw->w);
1430 0 : }
1431 :
1432 0 : static void GXDrawSetWindowTitles(GWindow w, const unichar_t *title, const unichar_t *icontit) {
1433 0 : GXWindow gw = (GXWindow) w;
1434 0 : Display *display = gw->display->display;
1435 : char *ipt, *tpt;
1436 :
1437 0 : XmbSetWMProperties(display,gw->w,(tpt = u2def_copy(title)),
1438 : (ipt = u2def_copy(icontit)),
1439 : NULL,0,NULL,NULL,NULL);
1440 0 : free(ipt); free(tpt);
1441 0 : }
1442 :
1443 0 : static void GXDrawSetWindowTitles8(GWindow w, const char *title, const char *icontit) {
1444 0 : GXWindow gw = (GXWindow) w;
1445 0 : Display *display = gw->display->display;
1446 : #ifdef X_HAVE_UTF8_STRING
1447 0 : Xutf8SetWMProperties(display, gw->w, title, icontit, NULL, 0, NULL, NULL, NULL);
1448 : #else
1449 : unichar_t *tit = utf82u_copy(title), *itit = utf82u_copy(icontit);
1450 : char *ipt, *tpt;
1451 :
1452 : XmbSetWMProperties(display,gw->w,(tpt = u2def_copy(tit)),
1453 : (ipt = u2def_copy(itit)),
1454 : NULL,0,NULL,NULL,NULL);
1455 : free(tit); free(tpt);
1456 : free(itit); free(ipt);
1457 : #endif
1458 0 : }
1459 :
1460 0 : static void GXDrawSetTransientFor(GWindow transient, GWindow owner) {
1461 0 : GXWindow gw = (GXWindow) transient;
1462 0 : GXDisplay *gdisp = gw->display;
1463 0 : Display *display = gdisp->display;
1464 : Window ow;
1465 :
1466 0 : if ( owner==(GWindow) -1 )
1467 0 : ow = gdisp->last_nontransient_window;
1468 0 : else if ( owner==NULL )
1469 0 : ow = 0;
1470 : else
1471 0 : ow = ((GXWindow) owner)->w;
1472 0 : XSetTransientForHint(display,gw->w, ow );
1473 0 : gw->transient_owner = ow;
1474 0 : gw->istransient = ow!=0;
1475 0 : }
1476 :
1477 0 : static void GXDrawSetCursor(GWindow w, GCursor ct) {
1478 0 : GXWindow gw = (GXWindow) w;
1479 0 : GXDisplay *gdisp = gw->display;
1480 0 : Cursor cur = _GXDraw_GetCursor(gdisp,ct);
1481 :
1482 0 : XDefineCursor(gdisp->display,gw->w,cur);
1483 0 : gw->cursor = ct;
1484 0 : }
1485 :
1486 0 : static GCursor GXDrawGetCursor(GWindow w) {
1487 0 : GXWindow gw = (GXWindow) w;
1488 :
1489 0 : return( gw->cursor );
1490 : }
1491 :
1492 0 : static GWindow GXDrawGetRedirectWindow(GDisplay *gd) {
1493 0 : GXDisplay *gdisp = (GXDisplay *) gd;
1494 :
1495 0 : if ( gdisp->input==NULL )
1496 0 : return( NULL );
1497 :
1498 0 : return( gdisp->input->cur_dlg );
1499 : }
1500 :
1501 0 : static void GXDrawGetPointerPosition(GWindow w, GEvent *ret) {
1502 0 : GXWindow gw = (GXWindow) w;
1503 0 : Display *display = gw->display->display;
1504 : int junk;
1505 : Window wjunk;
1506 : int x, y; unsigned int state;
1507 :
1508 0 : XQueryPointer(display,gw->w,&wjunk,&wjunk,&junk,&junk,&x,&y,&state);
1509 0 : ret->u.mouse.state = state;
1510 0 : ret->u.mouse.x = x;
1511 0 : ret->u.mouse.y = y;
1512 0 : }
1513 :
1514 0 : static Window _GXDrawGetPointerWindow(GWindow w) {
1515 0 : GXWindow gw = (GXWindow) w;
1516 0 : Display *display = gw->display->display;
1517 : int junk;
1518 : Window parent, child, wjunk;
1519 : int x, y; unsigned int state;
1520 :
1521 0 : parent = gw->display->groot->w;
1522 : for (;;) {
1523 0 : child = None;
1524 0 : if ( !XQueryPointer(display,parent,&wjunk,&child,&junk,&junk,&x,&y,&state))
1525 0 : break;
1526 0 : if ( child==None )
1527 0 : break;
1528 0 : parent = child;
1529 0 : }
1530 0 : return( parent );
1531 : }
1532 :
1533 0 : static GWindow GXDrawGetPointerWindow(GWindow w) {
1534 0 : GXWindow gw = (GXWindow) w;
1535 0 : Display *display = gw->display->display;
1536 : void *ret;
1537 : Window parent;
1538 :
1539 0 : parent = _GXDrawGetPointerWindow(w);
1540 0 : if ( (gw->w&0xfff00000) == (parent&0xfff00000)) {
1541 : /* It is one of our windows, so it is safe to look for it */
1542 0 : if ( XFindContext(display,parent,gw->display->mycontext,(void *) &ret)==0 )
1543 0 : return( (GWindow) ret );
1544 : }
1545 0 : return( NULL );
1546 : }
1547 :
1548 : static char *GXDrawGetWindowTitle8(GWindow w);
1549 :
1550 0 : static unichar_t *GXDrawGetWindowTitle(GWindow w) {
1551 : #if X_HAVE_UTF8_STRING
1552 0 : char *ret1 = GXDrawGetWindowTitle8(w);
1553 0 : unichar_t *ret = utf82u_copy(ret1);
1554 :
1555 0 : free(ret1);
1556 0 : return( ret );
1557 : #else
1558 : GXWindow gw = (GXWindow) w;
1559 : Display *display = gw->display->display;
1560 : char *pt;
1561 : unichar_t *ret;
1562 :
1563 : XFetchName(display,gw->w,&pt);
1564 : ret = def2u_copy(pt);
1565 : XFree(pt);
1566 : return( ret );
1567 : #endif
1568 : }
1569 :
1570 0 : static char *GXDrawGetWindowTitle8(GWindow w) {
1571 : #if X_HAVE_UTF8_STRING
1572 0 : GXWindow gw = (GXWindow) w;
1573 0 : Display *display = gw->display->display;
1574 : XTextProperty prop;
1575 : char **propret;
1576 : int cnt, i, len;
1577 : char *ret;
1578 :
1579 0 : memset(&prop,0,sizeof(prop));
1580 0 : XGetTextProperty(display,gw->w, &prop, XA_WM_NAME );
1581 0 : if ( prop.value == NULL )
1582 0 : return( NULL );
1583 0 : Xutf8TextPropertyToTextList(display,&prop,&propret,&cnt);
1584 0 : XFree(prop.value);
1585 0 : for ( i=len=0; i<cnt; ++i )
1586 0 : len += strlen( propret[i]);
1587 0 : ret = malloc(len+1);
1588 0 : for ( i=len=0; i<cnt; ++i ) {
1589 0 : strcpy(ret+len,propret[i]);
1590 0 : len += strlen( propret[i]);
1591 : }
1592 0 : XFreeStringList( propret );
1593 0 : return( ret );
1594 : #else
1595 : unichar_t *ret1 = GXDrawGetWindowTitle(w);
1596 : char *ret = u2utf8_copy(ret1);
1597 :
1598 : free(ret1);
1599 : return( ret );
1600 : #endif
1601 : }
1602 :
1603 0 : static void GXDrawTranslateCoordinates(GWindow _from,GWindow _to, GPoint *pt) {
1604 0 : GXDisplay *gd = (GXDisplay *) ((_from!=NULL)?_from->display:_to->display);
1605 0 : Window from = (_from==NULL)?gd->root:((GXWindow) _from)->w;
1606 0 : Window to = (_to==NULL)?gd->root:((GXWindow) _to)->w;
1607 : int x,y;
1608 : Window child;
1609 :
1610 0 : XTranslateCoordinates(gd->display,from,to,pt->x,pt->y,&x,&y,&child);
1611 0 : pt->x = x; pt->y = y;
1612 0 : }
1613 :
1614 0 : static void GXDrawBeep(GDisplay *gdisp) {
1615 0 : XBell(((GXDisplay *) gdisp)->display,80);
1616 0 : }
1617 :
1618 0 : static void GXDrawFlush(GDisplay *gdisp) {
1619 0 : XFlush(((GXDisplay *) gdisp)->display);
1620 0 : }
1621 : /* ************************************************************************** */
1622 : /* **************************** Draw Routines ******************************* */
1623 : /* ************************************************************************** */
1624 :
1625 0 : void _GXDraw_SetClipFunc(GXDisplay *gdisp, GGC *mine) {
1626 : XRectangle clip;
1627 : XGCValues vals;
1628 0 : long mask=0;
1629 0 : GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
1630 :
1631 0 : if ( mine->clip.x!=gcs->clip.x ||
1632 0 : mine->clip.width!=gcs->clip.width ||
1633 0 : mine->clip.y!=gcs->clip.y ||
1634 0 : mine->clip.height!=gcs->clip.height ) {
1635 0 : clip.x = mine->clip.x; clip.y = mine->clip.y;
1636 0 : clip.width = mine->clip.width;
1637 0 : clip.height = mine->clip.height;
1638 0 : XSetClipRectangles(gdisp->display,gcs->gc,0,0,&clip,1,YXBanded);
1639 0 : gcs->clip = mine->clip;
1640 : }
1641 0 : if ( mine->func!=gcs->func ) {
1642 0 : vals.function = mine->func==df_copy?GXcopy:GXxor;
1643 0 : mask |= GCFunction;
1644 0 : gcs->func = mine->func;
1645 : }
1646 0 : if ( mine->copy_through_sub_windows != gcs->copy_through_sub_windows ) {
1647 0 : vals.subwindow_mode = mine->copy_through_sub_windows?IncludeInferiors:ClipByChildren;
1648 0 : mask |= GCSubwindowMode;
1649 0 : gcs->copy_through_sub_windows = mine->copy_through_sub_windows;
1650 : }
1651 0 : if ( mask!=0 )
1652 0 : XChangeGC(gdisp->display,gcs->gc,mask,&vals);
1653 0 : }
1654 :
1655 0 : static int GXDrawSetcolfunc(GXDisplay *gdisp, GGC *mine) {
1656 : XGCValues vals;
1657 0 : long mask=0;
1658 0 : GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
1659 :
1660 0 : _GXDraw_SetClipFunc(gdisp,mine);
1661 0 : if ( mine->fg!=gcs->fore_col || mine->func!=gcs->func || mine->func==df_xor ) {
1662 0 : if ( mine->bitmap_col ) {
1663 0 : vals.foreground = mine->fg;
1664 : } else {
1665 0 : vals.foreground = _GXDraw_GetScreenPixel(gdisp,mine->fg);
1666 : }
1667 0 : gcs->fore_col = mine->fg;
1668 0 : if ( mine->func==df_xor ) {
1669 0 : vals.foreground ^= _GXDraw_GetScreenPixel(gdisp,mine->xor_base);
1670 0 : gcs->fore_col = COLOR_UNKNOWN;
1671 : }
1672 0 : mask |= GCForeground;
1673 : }
1674 0 : if ( mine->bg!=gcs->back_col ) {
1675 0 : vals.background = _GXDraw_GetScreenPixel(gdisp,mine->bg);
1676 0 : mask |= GCBackground;
1677 0 : gcs->back_col = mine->bg;
1678 : }
1679 0 : if ( mine->ts != gcs->ts || mine->ts != 0 ||
1680 0 : mine->ts_xoff != gcs->ts_xoff ||
1681 0 : mine->ts_yoff != gcs->ts_yoff ) {
1682 0 : if ( mine->ts!=0 ) {
1683 0 : vals.stipple = mine->ts==1?gdisp->grey_stipple: gdisp->fence_stipple;
1684 0 : mask |= GCStipple;
1685 : }
1686 0 : vals.fill_style = (mine->ts?FillStippled:FillSolid);
1687 0 : vals.ts_x_origin = mine->ts_xoff;
1688 0 : vals.ts_y_origin = mine->ts_yoff;
1689 0 : mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle;
1690 0 : gcs->ts = mine->ts;
1691 0 : gcs->ts_xoff = mine->ts_xoff;
1692 0 : gcs->ts_yoff = mine->ts_yoff;
1693 : }
1694 0 : if ( mask!=0 )
1695 0 : XChangeGC(gdisp->display,gcs->gc,mask,&vals);
1696 0 : return( true );
1697 : }
1698 :
1699 0 : static int GXDrawSetline(GXDisplay *gdisp, GGC *mine) {
1700 : XGCValues vals;
1701 0 : long mask=0;
1702 0 : GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
1703 :
1704 0 : _GXDraw_SetClipFunc(gdisp,mine);
1705 0 : if ( mine->fg!=gcs->fore_col || mine->func!=gcs->func || mine->func==df_xor ) {
1706 0 : if ( mine->bitmap_col ) {
1707 0 : vals.foreground = mine->fg;
1708 : } else {
1709 0 : vals.foreground = _GXDraw_GetScreenPixel(gdisp,mine->fg);
1710 : }
1711 0 : gcs->fore_col = mine->fg;
1712 0 : if ( mine->func==df_xor ) {
1713 0 : vals.foreground ^= _GXDraw_GetScreenPixel(gdisp,mine->xor_base);
1714 0 : gcs->fore_col = COLOR_UNKNOWN;
1715 : }
1716 0 : mask |= GCForeground;
1717 : }
1718 0 : if ( mine->line_width==1 ) mine->line_width = 0;
1719 0 : if ( mine->line_width!=gcs->line_width ) {
1720 0 : vals.line_width = mine->line_width;
1721 0 : mask |= GCLineWidth;
1722 0 : gcs->line_width = mine->line_width;
1723 : }
1724 0 : if ( mine->dash_len != gcs->dash_len || mine->skip_len != gcs->skip_len ||
1725 0 : mine->dash_offset != gcs->dash_offset ) {
1726 0 : vals.line_style = mine->dash_len==0?LineSolid:LineOnOffDash;
1727 0 : mask |= GCLineStyle;
1728 0 : if ( vals.line_style!=LineSolid ) {
1729 0 : if ( mine->dash_len==mine->skip_len ) {
1730 0 : vals.dash_offset = mine->dash_offset;
1731 0 : vals.dashes = mine->dash_len;
1732 0 : mask |= GCDashOffset|GCDashList;
1733 : } else {
1734 : char dashes[2];
1735 0 : dashes[0] = mine->dash_len; dashes[1] = mine->skip_len;
1736 0 : XSetDashes(gdisp->display,gcs->gc,mine->dash_offset,dashes,2);
1737 : }
1738 : }
1739 0 : gcs->dash_offset = mine->dash_offset;
1740 0 : gcs->dash_len = mine->dash_len;
1741 0 : gcs->skip_len = mine->skip_len;
1742 : }
1743 0 : if ( mine->ts != gcs->ts ||
1744 0 : mine->ts_xoff != gcs->ts_xoff ||
1745 0 : mine->ts_yoff != gcs->ts_yoff ) {
1746 0 : if ( mine->ts!=0 ) {
1747 0 : vals.stipple = mine->ts==1 ? gdisp->grey_stipple : gdisp->fence_stipple;
1748 0 : mask |= GCStipple;
1749 0 : if ( !mine->bitmap_col ) {
1750 : /* For reasons inexplicable to me, X sometimes draws with OpaqueStippled */
1751 0 : vals.background = _GXDraw_GetScreenPixel(gdisp,gcs->back_col);
1752 0 : mask |= GCBackground;
1753 : }
1754 : }
1755 0 : vals.fill_style = (mine->ts?FillStippled:FillSolid);
1756 0 : vals.ts_x_origin = mine->ts_xoff;
1757 0 : vals.ts_y_origin = mine->ts_yoff;
1758 0 : mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle;
1759 0 : gcs->ts = mine->ts;
1760 0 : gcs->ts_xoff = mine->ts_xoff;
1761 0 : gcs->ts_yoff = mine->ts_yoff;
1762 : }
1763 0 : if ( mask!=0 )
1764 0 : XChangeGC(gdisp->display,gcs->gc,mask,&vals);
1765 0 : return( true );
1766 : }
1767 :
1768 0 : static void GXDrawPushClipOnly(GWindow w)
1769 : {
1770 : #ifndef _NO_LIBCAIRO
1771 0 : if ( ((GXWindow) w)->usecairo )
1772 0 : _GXCDraw_PushClipOnly((GXWindow) w);
1773 : #endif
1774 0 : }
1775 :
1776 0 : static void GXDrawClipPreserve(GWindow w)
1777 : {
1778 : #ifndef _NO_LIBCAIRO
1779 0 : if ( ((GXWindow) w)->usecairo )
1780 0 : _GXCDraw_ClipPreserve((GXWindow) w);
1781 : #endif
1782 0 : }
1783 :
1784 :
1785 0 : static void GXDrawPushClip(GWindow w, GRect *rct, GRect *old) {
1786 : /* return the current clip, and intersect the current clip with the desired */
1787 : /* clip to get the new */
1788 0 : *old = w->ggc->clip;
1789 0 : w->ggc->clip = *rct;
1790 0 : if ( w->ggc->clip.x+w->ggc->clip.width>old->x+old->width )
1791 0 : w->ggc->clip.width = old->x+old->width-w->ggc->clip.x;
1792 0 : if ( w->ggc->clip.y+w->ggc->clip.height>old->y+old->height )
1793 0 : w->ggc->clip.height = old->y+old->height-w->ggc->clip.y;
1794 0 : if ( w->ggc->clip.x<old->x ) {
1795 0 : if ( w->ggc->clip.width > (old->x-w->ggc->clip.x))
1796 0 : w->ggc->clip.width -= (old->x-w->ggc->clip.x);
1797 : else
1798 0 : w->ggc->clip.width = 0;
1799 0 : w->ggc->clip.x = old->x;
1800 : }
1801 0 : if ( w->ggc->clip.y<old->y ) {
1802 0 : if ( w->ggc->clip.height > (old->y-w->ggc->clip.y))
1803 0 : w->ggc->clip.height -= (old->y-w->ggc->clip.y);
1804 : else
1805 0 : w->ggc->clip.height = 0;
1806 0 : w->ggc->clip.y = old->y;
1807 : }
1808 0 : if ( w->ggc->clip.height<0 || w->ggc->clip.width<0 ) {
1809 : /* Negative values mean large positive values, so if we want to clip */
1810 : /* to nothing force clip outside window */
1811 0 : w->ggc->clip.x = w->ggc->clip.y = -100;
1812 0 : w->ggc->clip.height = w->ggc->clip.width = 1;
1813 : }
1814 : #ifndef _NO_LIBCAIRO
1815 0 : if ( ((GXWindow) w)->usecairo )
1816 0 : _GXCDraw_PushClip((GXWindow) w);
1817 : #endif
1818 0 : }
1819 :
1820 0 : static void GXDrawPopClip(GWindow w, GRect *old) {
1821 0 : w->ggc->clip = *old;
1822 : #ifndef _NO_LIBCAIRO
1823 0 : if ( ((GXWindow) w)->usecairo )
1824 0 : _GXCDraw_PopClip((GXWindow) w);
1825 : #endif
1826 0 : }
1827 :
1828 :
1829 :
1830 0 : static void GXDrawClear(GWindow gw, GRect *rect) {
1831 0 : GXWindow gxw = (GXWindow) gw;
1832 : #ifndef _NO_LIBCAIRO
1833 0 : if ( gxw->usecairo )
1834 0 : _GXCDraw_Clear(gxw,rect);
1835 : else
1836 : #endif
1837 : {
1838 0 : GXDisplay *display = (GXDisplay *) (gw->display);
1839 :
1840 0 : if ( rect==NULL )
1841 0 : XClearWindow(display->display,gxw->w);
1842 : else
1843 0 : XClearArea(display->display,gxw->w,
1844 0 : rect->x,rect->y,rect->width,rect->height, false );
1845 : }
1846 0 : }
1847 :
1848 0 : static void GXDrawDrawLine(GWindow w, int32 x,int32 y, int32 xend,int32 yend, Color col) {
1849 0 : w->ggc->fg = col;
1850 :
1851 : #ifndef _NO_LIBCAIRO
1852 0 : if ( ((GXWindow) w)->usecairo && w->ggc->func==df_copy ) {
1853 0 : _GXCDraw_DrawLine((GXWindow) w,x,y,xend,yend);
1854 : } else {
1855 0 : if (((GXWindow) w)->usecairo )
1856 0 : _GXCDraw_Flush((GXWindow) w);
1857 : #endif
1858 : {
1859 0 : GXDisplay *display = (GXDisplay *) (w->display);
1860 0 : GXDrawSetline(display,w->ggc);
1861 0 : XDrawLine(display->display,((GXWindow) w)->w,display->gcstate[w->ggc->bitmap_col].gc,x,y,xend,yend);
1862 : }
1863 : #ifndef _NO_LIBCAIRO
1864 0 : if (((GXWindow) w)->usecairo ) {
1865 0 : if ( xend<x ) { int temp = x; x = xend; xend=temp;}
1866 0 : if ( yend<y ) { int temp = y; y = yend; yend=temp;}
1867 0 : _GXCDraw_DirtyRect((GXWindow) w,x,y,xend-x+1,yend-y+1);
1868 : }
1869 : }
1870 : #endif
1871 0 : }
1872 :
1873 0 : static void _DrawArrow(GXWindow gxw, int32 x, int32 y, int32 xother, int32 yother ) {
1874 0 : GXDisplay *display = gxw->display;
1875 : XPoint points[3];
1876 : double a;
1877 : int off1, off2;
1878 : double len;
1879 :
1880 0 : if ( x==xother && y==yother )
1881 0 : return;
1882 0 : a = atan2(y-yother,x-xother);
1883 0 : len = sqrt((double) (x-xother)*(x-xother)+(y-yother)*(y-yother));
1884 0 : if ( len>20 ) len = 10; else len = 2*len/3;
1885 0 : if ( len<2 )
1886 0 : return;
1887 :
1888 0 : points[0].x = x; points[0].y = y;
1889 0 : off1 = len*sin(a+3.1415926535897932/8)+.5; off2 = len*cos(a+3.1415926535897932/8)+.5;
1890 0 : points[1].x = x-off2; points[1].y = y-off1;
1891 0 : off1 = len*sin(a-3.1415926535897932/8)+.5; off2 = len*cos(a-3.1415926535897932/8)+.5;
1892 0 : points[2].x = x-off2; points[2].y = y-off1;
1893 0 : XFillPolygon(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,points,3,Complex,CoordModeOrigin);
1894 0 : XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,points,3,CoordModeOrigin);
1895 : }
1896 :
1897 0 : static void GXDrawDrawArrow(GWindow gw, int32 x,int32 y, int32 xend,int32 yend, int16 arrows, Color col) {
1898 0 : GXWindow gxw = (GXWindow) gw;
1899 0 : GXDisplay *display = gxw->display;
1900 :
1901 : #ifndef _NO_LIBCAIRO
1902 0 : if ( gxw->usecairo )
1903 0 : GDrawIError("DrawArrow not supported");
1904 : #endif
1905 0 : gxw->ggc->fg = col;
1906 0 : GXDrawSetline(display,gxw->ggc);
1907 0 : XDrawLine(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,x,y,xend,yend);
1908 0 : if ( arrows&1 )
1909 0 : _DrawArrow(gxw,x,y,xend,yend);
1910 0 : if ( arrows&2 )
1911 0 : _DrawArrow(gxw,xend,yend,x,y);
1912 0 : }
1913 :
1914 0 : static void GXDrawDrawRect(GWindow gw, GRect *rect, Color col) {
1915 0 : GXWindow gxw = (GXWindow) gw;
1916 :
1917 0 : gxw->ggc->fg = col;
1918 : #ifndef _NO_LIBCAIRO
1919 0 : if ( gxw->usecairo && gw->ggc->func==df_copy ) {
1920 0 : _GXCDraw_DrawRect(gxw,rect);
1921 : } else {
1922 0 : if ( gxw->usecairo )
1923 0 : _GXCDraw_Flush(gxw);
1924 : #endif
1925 : {
1926 0 : GXDisplay *display = gxw->display;
1927 :
1928 0 : GXDrawSetline(display,gxw->ggc);
1929 0 : XDrawRectangle(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
1930 0 : rect->width,rect->height);
1931 : }
1932 : #ifndef _NO_LIBCAIRO
1933 0 : if ( gxw->usecairo )
1934 0 : _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
1935 : }
1936 : #endif
1937 0 : }
1938 :
1939 0 : static void GXDrawFillRect(GWindow gw, GRect *rect, Color col) {
1940 0 : GXWindow gxw = (GXWindow) gw;
1941 :
1942 0 : gxw->ggc->fg = col;
1943 : #ifndef _NO_LIBCAIRO
1944 0 : if ( gxw->usecairo && gw->ggc->func==df_copy ) {
1945 0 : _GXCDraw_FillRect( gxw,rect);
1946 0 : return;
1947 : } else {
1948 0 : if (gxw->usecairo )
1949 0 : _GXCDraw_Flush(gxw);
1950 : #endif
1951 : {
1952 0 : GXDisplay *display = gxw->display;
1953 :
1954 0 : GXDrawSetcolfunc(display,gxw->ggc);
1955 0 : XFillRectangle(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
1956 0 : rect->width,rect->height);
1957 : }
1958 : #ifndef _NO_LIBCAIRO
1959 0 : if (gxw->usecairo )
1960 0 : _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
1961 : }
1962 : #endif
1963 : }
1964 :
1965 0 : static void GXDrawFillRoundRect(GWindow gw, GRect *rect, int radius, Color col) {
1966 0 : GXWindow gxw = (GXWindow) gw;
1967 0 : int rr = radius <= (rect->height+1)/2 ? (radius > 0 ? radius : 0) : (rect->height+1)/2;
1968 :
1969 0 : gxw->ggc->fg = col;
1970 : #ifndef _NO_LIBCAIRO
1971 0 : if ( gxw->usecairo && gw->ggc->func==df_copy ) {
1972 0 : _GXCDraw_FillRoundRect( gxw,rect,rr );
1973 0 : return;
1974 : } else {
1975 0 : if (gxw->usecairo )
1976 0 : _GXCDraw_Flush(gxw);
1977 : #endif
1978 : {
1979 0 : GRect middle = {rect->x, rect->y + radius, rect->width, rect->height - 2 * radius};
1980 0 : int xend = rect->x + rect->width - 1;
1981 0 : int yend = rect->y + rect->height - 1;
1982 0 : int precalc = rr * 2 - 1;
1983 : int i, xoff;
1984 :
1985 0 : for (i = 0; i < rr; i++) {
1986 0 : xoff = rr - lrint(sqrt( (double)(i * (precalc - i)) ));
1987 0 : GXDrawDrawLine(gw, rect->x + xoff, rect->y + i, xend - xoff, rect->y + i, col);
1988 0 : GXDrawDrawLine(gw, rect->x + xoff, yend - i, xend - xoff, yend - i, col);
1989 : }
1990 0 : GXDrawFillRect(gw, &middle, col);
1991 : }
1992 : #ifndef _NO_LIBCAIRO
1993 0 : if (gxw->usecairo )
1994 0 : _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
1995 : }
1996 : #endif
1997 : }
1998 :
1999 0 : static void GXDrawDrawElipse(GWindow gw, GRect *rect, Color col) {
2000 0 : GXWindow gxw = (GXWindow) gw;
2001 :
2002 0 : gxw->ggc->fg = col;
2003 : #ifndef _NO_LIBCAIRO
2004 0 : if ( gxw->usecairo ) {
2005 0 : _GXCDraw_DrawEllipse( gxw,rect);
2006 : } else
2007 : #endif
2008 : {
2009 0 : GXDisplay *display = gxw->display;
2010 :
2011 0 : GXDrawSetline(display,gxw->ggc);
2012 0 : XDrawArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
2013 0 : rect->width,rect->height,0,360*64);
2014 : }
2015 0 : }
2016 :
2017 0 : static void GXDrawDrawArc(GWindow gw, GRect *rect, int32 sangle, int32 tangle, Color col) {
2018 0 : GXWindow gxw = (GXWindow) gw;
2019 0 : GXDisplay *display = gxw->display;
2020 0 : gxw->ggc->fg = col;
2021 0 : GXDrawSetline(display,gxw->ggc);
2022 0 : XDrawArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
2023 0 : rect->width,rect->height,
2024 : sangle,tangle );
2025 0 : }
2026 :
2027 0 : static void GXDrawFillElipse(GWindow gw, GRect *rect, Color col) {
2028 0 : GXWindow gxw = (GXWindow) gw;
2029 0 : GXDisplay *display = gxw->display;
2030 :
2031 0 : gxw->ggc->fg = col;
2032 : #ifndef _NO_LIBCAIRO
2033 0 : if ( gxw->usecairo ) {
2034 0 : _GXCDraw_FillEllipse( gxw,rect);
2035 : } else
2036 : #endif
2037 : {
2038 0 : GXDrawSetcolfunc(display,gxw->ggc);
2039 0 : XFillArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
2040 0 : rect->width,rect->height,0,360*64);
2041 : }
2042 0 : }
2043 :
2044 0 : static void GXDrawDrawPoly(GWindow gw, GPoint *pts, int16 cnt, Color col) {
2045 0 : GXWindow gxw = (GXWindow) gw;
2046 0 : GXDisplay *display = gxw->display;
2047 :
2048 0 : gxw->ggc->fg = col;
2049 : #ifndef _NO_LIBCAIRO
2050 0 : if ( gxw->usecairo ) {
2051 0 : _GXCDraw_DrawPoly( gxw,pts,cnt);
2052 : } else
2053 : #endif
2054 : {
2055 0 : GXDrawSetline(display,gxw->ggc);
2056 0 : XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,CoordModeOrigin);
2057 : }
2058 0 : }
2059 :
2060 0 : static void GXDrawFillPoly(GWindow gw, GPoint *pts, int16 cnt, Color col) {
2061 0 : GXWindow gxw = (GXWindow) gw;
2062 0 : GXDisplay *display = gxw->display;
2063 :
2064 0 : gxw->ggc->fg = col;
2065 : #ifndef _NO_LIBCAIRO
2066 0 : if ( gxw->usecairo ) {
2067 0 : _GXCDraw_FillPoly( gxw,pts,cnt);
2068 : } else
2069 : #endif
2070 : {
2071 0 : GXDrawSetline(display,gxw->ggc); /* Polygons draw their borders too! so we need the line mode */
2072 0 : GXDrawSetcolfunc(display,gxw->ggc);
2073 0 : XFillPolygon(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,Complex,CoordModeOrigin);
2074 0 : XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,CoordModeOrigin);
2075 : }
2076 0 : }
2077 :
2078 : #ifndef _NO_LIBCAIRO
2079 0 : static enum gcairo_flags GXDrawHasCairo(GWindow w) {
2080 0 : if ( ((GXWindow) w)->usecairo )
2081 0 : return( _GXCDraw_CairoCapabilities( (GXWindow) w));
2082 :
2083 0 : return( gc_xor );
2084 : }
2085 :
2086 0 : static void GXDrawPathStartNew(GWindow w) {
2087 0 : if ( !((GXWindow) w)->usecairo )
2088 0 : return;
2089 0 : _GXCDraw_PathStartNew(w);
2090 : }
2091 :
2092 0 : static void GXDrawPathStartSubNew(GWindow w) {
2093 0 : if ( !((GXWindow) w)->usecairo )
2094 0 : return;
2095 0 : _GXCDraw_PathStartSubNew(w);
2096 : }
2097 :
2098 0 : static int GXDrawFillRuleSetWinding(GWindow w) {
2099 0 : if ( !((GXWindow) w)->usecairo )
2100 0 : return 0;
2101 0 : return _GXCDraw_FillRuleSetWinding(w);
2102 : }
2103 :
2104 0 : static void GXDrawPathClose(GWindow w) {
2105 0 : if ( !((GXWindow) w)->usecairo )
2106 0 : return;
2107 0 : _GXCDraw_PathClose(w);
2108 : }
2109 :
2110 0 : static void GXDrawPathMoveTo(GWindow w,double x, double y) {
2111 0 : if ( !((GXWindow) w)->usecairo )
2112 0 : return;
2113 0 : _GXCDraw_PathMoveTo(w,x,y);
2114 : }
2115 :
2116 0 : static void GXDrawPathLineTo(GWindow w,double x, double y) {
2117 0 : if ( !((GXWindow) w)->usecairo )
2118 0 : return;
2119 0 : _GXCDraw_PathLineTo(w,x,y);
2120 : }
2121 :
2122 0 : static void GXDrawPathCurveTo(GWindow w,
2123 : double cx1, double cy1,
2124 : double cx2, double cy2,
2125 : double x, double y) {
2126 0 : if ( !((GXWindow) w)->usecairo )
2127 0 : return;
2128 0 : _GXCDraw_PathCurveTo(w,cx1,cy1,cx2,cy2,x,y);
2129 : }
2130 :
2131 0 : static void GXDrawPathStroke(GWindow w,Color col) {
2132 0 : if ( !((GXWindow) w)->usecairo )
2133 0 : return;
2134 0 : _GXCDraw_PathStroke(w,col);
2135 : }
2136 :
2137 0 : static void GXDrawPathFill(GWindow w,Color col) {
2138 0 : if ( !((GXWindow) w)->usecairo )
2139 0 : return;
2140 0 : _GXCDraw_PathFill(w,col);
2141 : }
2142 :
2143 0 : static void GXDrawPathFillAndStroke(GWindow w,Color fillcol, Color strokecol) {
2144 0 : if ( !((GXWindow) w)->usecairo )
2145 0 : return;
2146 0 : _GXCDraw_PathFillAndStroke(w,fillcol,strokecol);
2147 : }
2148 :
2149 : #else
2150 : static enum gcairo_flags GXDrawHasCairo(GWindow w) {
2151 : return( gc_xor );
2152 : }
2153 :
2154 : static void GXDrawPathStartNew(GWindow w) {
2155 : }
2156 :
2157 : static void GXDrawPathStartSubNew(GWindow w) {
2158 : }
2159 :
2160 : static int GXDrawFillRuleSetWinding(GWindow w) {
2161 : return 0;
2162 : }
2163 :
2164 : static void GXDrawPathClose(GWindow w) {
2165 : }
2166 :
2167 : static void GXDrawPathMoveTo(GWindow w,double x, double y) {
2168 : }
2169 :
2170 : static void GXDrawPathLineTo(GWindow w,double x, double y) {
2171 : }
2172 :
2173 : static void GXDrawPathCurveTo(GWindow w,
2174 : double cx1, double cy1,
2175 : double cx2, double cy2,
2176 : double x, double y) {
2177 : }
2178 :
2179 : static void GXDrawPathStroke(GWindow w,Color col) {
2180 : }
2181 :
2182 : static void GXDrawPathFill(GWindow w,Color col) {
2183 : }
2184 :
2185 : static void GXDrawPathFillAndStroke(GWindow w,Color fillcol, Color strokecol) {
2186 : }
2187 :
2188 : #endif
2189 :
2190 0 : static void GXDrawLayoutInit(GWindow w, char *text, int cnt, GFont *fi) {
2191 0 : _GXPDraw_LayoutInit(w,text,cnt,fi);
2192 0 : }
2193 :
2194 0 : static void GXDraw_LayoutDraw(GWindow w, int32 x, int32 y, Color fg) {
2195 0 : _GXPDraw_LayoutDraw(w,x,y,fg);
2196 0 : }
2197 :
2198 0 : static void GXDraw_LayoutIndexToPos(GWindow w, int index, GRect *pos) {
2199 0 : _GXPDraw_LayoutIndexToPos(w,index,pos);
2200 0 : }
2201 :
2202 0 : static int GXDraw_LayoutXYToIndex(GWindow w, int x, int y) {
2203 0 : return( _GXPDraw_LayoutXYToIndex(w,x,y));
2204 : }
2205 :
2206 0 : static void GXDraw_LayoutExtents(GWindow w, GRect *size) {
2207 0 : _GXPDraw_LayoutExtents(w,size);
2208 0 : }
2209 :
2210 0 : static void GXDraw_LayoutSetWidth(GWindow w, int width) {
2211 0 : _GXPDraw_LayoutSetWidth(w,width);
2212 0 : }
2213 :
2214 0 : static int GXDraw_LayoutLineCount(GWindow w) {
2215 0 : return( _GXPDraw_LayoutLineCount(w));
2216 : }
2217 :
2218 0 : static int GXDraw_LayoutLineStart(GWindow w, int l) {
2219 0 : return( _GXPDraw_LayoutLineStart(w, l));
2220 : }
2221 :
2222 0 : static void GXDrawSendExpose(GXWindow gw, int x,int y,int wid,int hei ) {
2223 0 : if ( gw->eh!=NULL ) {
2224 : struct gevent event;
2225 0 : memset(&event,0,sizeof(event));
2226 0 : event.type = et_expose;
2227 0 : if ( x<0 ) { wid += x; x = 0; }
2228 0 : if ( y<0 ) { hei += y; y = 0; }
2229 0 : event.u.expose.rect.x = x;
2230 0 : event.u.expose.rect.y = y;
2231 0 : if ( x+wid>gw->pos.width ) wid = gw->pos.width-x;
2232 0 : if ( y+hei>gw->pos.height ) hei = gw->pos.height-y;
2233 0 : if ( wid<0 || hei<0 )
2234 0 : return;
2235 0 : event.u.expose.rect.width = wid;
2236 0 : event.u.expose.rect.height = hei;
2237 0 : event.w = (GWindow) gw;
2238 0 : event.native_window = ((GWindow) gw)->native_window;
2239 0 : (gw->eh)((GWindow ) gw,&event);
2240 : }
2241 : }
2242 :
2243 0 : static void GXDrawScroll(GWindow _w, GRect *rect, int32 hor, int32 vert) {
2244 0 : GXWindow gw = (GXWindow) _w;
2245 0 : GXDisplay *gdisp = gw->display;
2246 : GRect temp, old;
2247 :
2248 0 : vert = -vert;
2249 :
2250 0 : if ( rect == NULL ) {
2251 0 : temp.x = temp.y = 0; temp.width = gw->pos.width; temp.height = gw->pos.height;
2252 0 : rect = &temp;
2253 : }
2254 :
2255 : /*GDrawForceUpdate((GWindow) gw); */ /* need to make sure the screen holds what it should */
2256 : /* but user has to do it, it's probably too late here */
2257 0 : GDrawPushClip(_w,rect,&old);
2258 : #ifdef _COMPOSITE_BROKEN
2259 : GXDrawSendExpose(gw,0,0,gw->pos.width,gw->pos.height);
2260 : #else
2261 0 : _GXDraw_SetClipFunc(gdisp,gw->ggc);
2262 : #ifndef _NO_LIBCAIRO
2263 0 : if ( gw->usecairo ) {
2264 : /* Cairo can happily scroll the window -- except it doesn't know about*/
2265 : /* child windows, and so we don't get the requisit events to redraw */
2266 : /* areas covered by children. Rats. */
2267 0 : GXDrawSendExpose(gw,rect->x,rect->y,rect->x+rect->width,rect->y+rect->height);
2268 0 : GXDrawPopClip(_w,&old);
2269 0 : return;
2270 : /* _GXCDraw_CopyArea(gw,gw,rect,rect->x+hor,rect->y+vert); */
2271 : } else
2272 : #endif
2273 0 : XCopyArea(gdisp->display,gw->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
2274 0 : rect->x,rect->y, rect->width,rect->height,
2275 0 : rect->x+hor,rect->y+vert);
2276 0 : if ( hor>0 )
2277 0 : GXDrawSendExpose(gw,rect->x,rect->y, hor,rect->height);
2278 0 : else if ( hor<0 )
2279 0 : GXDrawSendExpose(gw,rect->x+rect->width+hor,rect->y,-hor,rect->height);
2280 0 : if ( vert>0 )
2281 0 : GXDrawSendExpose(gw,rect->x,rect->y,rect->width,vert);
2282 0 : else if ( vert<0 )
2283 0 : GXDrawSendExpose(gw,rect->x,rect->y+rect->height+vert,rect->width,-vert);
2284 : #endif
2285 0 : GXDrawPopClip(_w,&old);
2286 : }
2287 :
2288 0 : static void _GXDraw_Pixmap( GWindow _w, GWindow _pixmap, GRect *src, int32 x, int32 y) {
2289 0 : GXWindow gw = (GXWindow) _w, pixmap = (GXWindow) _pixmap;
2290 0 : GXDisplay *gdisp = gw->display;
2291 :
2292 0 : if ( pixmap->ggc->bitmap_col ) {
2293 0 : GXDrawSetcolfunc(gdisp,gw->ggc);
2294 0 : XCopyPlane(gdisp->display,pixmap->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
2295 0 : src->x,src->y, src->width,src->height,
2296 : x,y,1);
2297 : } else {
2298 0 : _GXDraw_SetClipFunc(gdisp,gw->ggc);
2299 : #ifndef _NO_LIBCAIRO
2300 : /* FIXME: _GXCDraw_CopyArea makes the glyph dissabear in the class kern
2301 : * dialog */
2302 : if ( 0 && gw->usecairo )
2303 : _GXCDraw_CopyArea(pixmap,gw,src,x,y);
2304 : else
2305 : #endif
2306 0 : XCopyArea(gdisp->display,pixmap->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
2307 0 : src->x,src->y, src->width,src->height,
2308 : x,y);
2309 : }
2310 0 : }
2311 :
2312 0 : static void _GXDraw_TilePixmap( GWindow _w, GWindow _pixmap, GRect *src, int32 x, int32 y) {
2313 0 : GXWindow gw = (GXWindow) _w, pixmap = (GXWindow) _pixmap;
2314 0 : GXDisplay *gdisp = gw->display;
2315 : GRect old;
2316 : int i,j;
2317 :
2318 0 : GDrawPushClip(_w,src,&old);
2319 0 : GXDrawSetcolfunc(gdisp,gw->ggc);
2320 0 : for ( i=y; i<gw->ggc->clip.y+gw->ggc->clip.height; i+=pixmap->pos.height ) {
2321 0 : if ( i+pixmap->pos.height<gw->ggc->clip.y )
2322 0 : continue;
2323 0 : for ( j=x; j<gw->ggc->clip.x+gw->ggc->clip.width; j+=pixmap->pos.width ) {
2324 0 : if ( j+pixmap->pos.width<gw->ggc->clip.x )
2325 0 : continue;
2326 0 : if ( pixmap->ggc->bitmap_col ) {
2327 0 : XCopyPlane(gdisp->display,((GXWindow) pixmap)->w,gw->w,gdisp->gcstate[1].gc,
2328 0 : 0,0, pixmap->pos.width, pixmap->pos.height,
2329 : j,i,1);
2330 : #ifndef _NO_LIBCAIRO
2331 0 : } else if ( gw->usecairo ) {
2332 0 : _GXCDraw_CopyArea(pixmap,gw,&pixmap->pos,j,i);
2333 : #endif
2334 : } else {
2335 0 : XCopyArea(gdisp->display,((GXWindow) pixmap)->w,gw->w,gdisp->gcstate[0].gc,
2336 0 : 0,0, pixmap->pos.width, pixmap->pos.height,
2337 : j,i);
2338 : }
2339 : }
2340 : }
2341 0 : GDrawPopClip(_w,&old);
2342 0 : }
2343 :
2344 0 : static void GXDrawFontMetrics( GWindow w,GFont *fi,int *as, int *ds, int *ld) {
2345 0 : _GXPDraw_FontMetrics(w, fi, as, ds, ld);
2346 0 : }
2347 :
2348 :
2349 0 : static GIC *GXDrawCreateInputContext(GWindow w,enum gic_style def_style) {
2350 : static int styles[] = { XIMPreeditNone | XIMStatusNone,
2351 : XIMPreeditNothing | XIMStatusNothing,
2352 : XIMPreeditPosition | XIMStatusNothing };
2353 : int i;
2354 0 : XIC ic = 0;
2355 : struct gxinput_context *gic;
2356 0 : GXDisplay *gdisp = (GXDisplay *) (w->display);
2357 : unsigned long fevent;
2358 : XWindowAttributes win_attrs;
2359 : XVaNestedList listp, lists;
2360 :
2361 0 : if ( gdisp->im==NULL )
2362 0 : return( NULL );
2363 :
2364 0 : gic = calloc(1,sizeof(struct gxinput_context));
2365 0 : gic->w = w;
2366 0 : gic->ploc.y = 20; gic->sloc.y = 40;
2367 0 : listp = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
2368 : XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
2369 : XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
2370 : XNSpotLocation, &gic->ploc, NULL);
2371 0 : lists = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
2372 : XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
2373 : XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
2374 : XNSpotLocation, &gic->sloc, NULL);
2375 0 : for ( i=(def_style&gic_type); i>=gic_hidden; --i ) {
2376 0 : ic = XCreateIC(gdisp->im,XNInputStyle,styles[i],
2377 : XNClientWindow, ((GXWindow) w)->w,
2378 : XNFocusWindow, ((GXWindow) w)->w,
2379 : XNPreeditAttributes, listp,
2380 : XNStatusAttributes, lists,
2381 : NULL );
2382 0 : if ( ic!=0 )
2383 0 : break;
2384 0 : if ( !(def_style&gic_orlesser) )
2385 0 : break;
2386 : }
2387 0 : XFree(lists); XFree(listp);
2388 0 : if ( ic==0 ) {
2389 0 : free(gic);
2390 0 : return( NULL );
2391 : }
2392 :
2393 0 : gic->style = i;
2394 0 : gic->w = w;
2395 0 : gic->ic = ic;
2396 0 : gic->next = ((GXWindow) w)->all;
2397 0 : ((GXWindow) w)->all = gic;
2398 :
2399 : /* Now make sure we get all the events the IC needs */
2400 0 : XGetWindowAttributes(gdisp->display, ((GXWindow) w)->w, &win_attrs);
2401 0 : XGetICValues(ic, XNFilterEvents, &fevent, NULL);
2402 0 : XSelectInput(gdisp->display, ((GXWindow) w)->w, fevent|win_attrs.your_event_mask);
2403 :
2404 0 : return( (GIC *) gic );
2405 : }
2406 :
2407 0 : static void GXDrawSetGIC(GWindow w, GIC *_gic, int x, int y) {
2408 0 : struct gxinput_context *gic = (struct gxinput_context *) _gic;
2409 : XVaNestedList listp, lists;
2410 0 : GXDisplay *gdisp = (GXDisplay *) (w->display);
2411 :
2412 0 : if ( x==10000 && y==x && gic!=NULL ) {
2413 0 : XUnsetICFocus(gic->ic);
2414 0 : } else if ( gic!=NULL ) {
2415 0 : gic->ploc.x = x;
2416 0 : gic->ploc.y = y;
2417 0 : gic->sloc.x = x;
2418 0 : gic->sloc.y = y+20;
2419 0 : XSetICFocus(gic->ic);
2420 0 : if ( gic->style==gic_overspot ) {
2421 0 : listp = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
2422 : XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
2423 : XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
2424 : XNSpotLocation, &gic->ploc, NULL);
2425 0 : lists = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
2426 : XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
2427 : XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
2428 : XNSpotLocation, &gic->sloc, NULL);
2429 0 : XSetICValues(gic->ic,
2430 : XNPreeditAttributes, listp,
2431 : XNStatusAttributes, lists,
2432 : NULL );
2433 0 : XFree(listp); XFree(lists);
2434 : }
2435 : }
2436 0 : ((GXWindow) w)->gic = gic;
2437 0 : }
2438 :
2439 0 : int _GXDraw_WindowOrParentsDying(GXWindow gw) {
2440 0 : while ( gw!=NULL ) {
2441 0 : if ( gw->is_dying )
2442 0 : return( true );
2443 0 : if ( gw->is_toplevel )
2444 0 : return( false );
2445 0 : gw = gw->parent;
2446 : }
2447 0 : return( false );
2448 : }
2449 :
2450 0 : static void GXDrawRequestExpose(GWindow gw, GRect *rect,int doclear) {
2451 0 : GXWindow gxw = (GXWindow) gw;
2452 0 : GXDisplay *display = (GXDisplay *) (gw->display);
2453 : GRect temp;
2454 :
2455 0 : if ( !gw->is_visible || _GXDraw_WindowOrParentsDying(gxw) )
2456 0 : return;
2457 0 : if ( rect==NULL ) {
2458 0 : temp.x = temp.y = 0;
2459 0 : temp.width = gxw->pos.width; temp.height = gxw->pos.height;
2460 0 : rect = &temp;
2461 0 : } else if ( rect->x<0 || rect->y<0 || rect->x+rect->width>gw->pos.width ||
2462 0 : rect->y+rect->height>gw->pos.height ) {
2463 0 : temp = *rect;
2464 0 : if ( temp.x < 0 ) { temp.width += temp.x; temp.x = 0; }
2465 0 : if ( temp.y < 0 ) { temp.height += temp.y; temp.y = 0; }
2466 0 : if ( temp.x+temp.width>gw->pos.width )
2467 0 : temp.width = gw->pos.width - temp.x;
2468 0 : if ( temp.y+temp.height>gw->pos.height )
2469 0 : temp.height = gw->pos.height - temp.y;
2470 0 : if ( temp.height<=0 || temp.width <= 0 )
2471 0 : return;
2472 0 : rect = &temp;
2473 : }
2474 : /* Don't simply XClearArea with exposures == True, flicker is noticeable */
2475 0 : if ( doclear )
2476 0 : XClearArea(display->display,gxw->w,rect->x,rect->y,rect->width,rect->height, false );
2477 0 : if ( gw->eh!=NULL ) {
2478 : struct gevent event;
2479 0 : memset(&event,0,sizeof(event));
2480 0 : event.type = et_expose;
2481 0 : event.u.expose.rect = *rect;
2482 0 : event.w = gw;
2483 0 : event.native_window = gw->native_window;
2484 0 : (gw->eh)(gw,&event);
2485 : }
2486 : }
2487 :
2488 0 : static void GTimerSetNext(GTimer *timer,int32 time_from_now) {
2489 : struct timeval tv;
2490 :
2491 0 : gettimeofday(&tv,NULL);
2492 0 : timer->time_sec = tv.tv_sec +time_from_now/1000;
2493 0 : timer->time_usec = tv.tv_usec+(time_from_now%1000)*1000;
2494 0 : if ( timer->time_usec>=1000000 ) {
2495 0 : ++timer->time_sec;
2496 0 : timer->time_usec-=1000000;
2497 : }
2498 0 : }
2499 :
2500 0 : static void GTimerInsertOrdered(GXDisplay *gdisp,GTimer *timer) {
2501 : GTimer *prev, *test;
2502 :
2503 0 : if ( gdisp->timers==NULL ) {
2504 0 : gdisp->timers = timer;
2505 0 : timer->next = NULL;
2506 0 : } else if ( gdisp->timers->time_sec>timer->time_sec ||
2507 0 : ( gdisp->timers->time_sec==timer->time_sec && gdisp->timers->time_usec>timer->time_usec )) {
2508 0 : timer->next = gdisp->timers;
2509 0 : gdisp->timers = timer;
2510 : } else {
2511 0 : prev = gdisp->timers;
2512 0 : for ( test = prev->next; test!=NULL; prev=test, test=test->next )
2513 0 : if ( test->time_sec>timer->time_sec ||
2514 0 : ( test->time_sec==timer->time_sec && test->time_usec>timer->time_usec ))
2515 : break;
2516 0 : timer->next = test;
2517 0 : prev->next = timer;
2518 : }
2519 0 : }
2520 :
2521 0 : static int GTimerRemove(GXDisplay *gdisp,GTimer *timer) {
2522 : GTimer *prev, *test;
2523 :
2524 0 : if ( gdisp->timers==timer )
2525 0 : gdisp->timers = timer->next;
2526 : else {
2527 0 : prev = gdisp->timers;
2528 0 : if ( prev==NULL )
2529 0 : return( false );
2530 0 : for ( test = prev->next; test!=NULL && test!=timer; prev=test, test=test->next );
2531 0 : if ( test==NULL ) /* Wasn't in the list, oh well */
2532 0 : return(false);
2533 0 : prev->next = timer->next;
2534 : }
2535 0 : return( true );
2536 : }
2537 :
2538 0 : static void GTimerRemoveWindowTimers(GXWindow gw) {
2539 : GTimer *prev, *test, *next;
2540 0 : GXDisplay *gdisp = gw->display;
2541 :
2542 0 : while ( gdisp->timers && gdisp->timers->owner==(GWindow) gw )
2543 0 : gdisp->timers = gdisp->timers->next;
2544 0 : prev = gdisp->timers;
2545 0 : if ( prev==NULL )
2546 0 : return;
2547 0 : for ( test = prev->next; test!=NULL; ) {
2548 0 : next = test->next;
2549 0 : if ( test->owner==(GWindow) gw ) {
2550 0 : prev->next = next;
2551 0 : free(test);
2552 : } else
2553 0 : prev = test;
2554 0 : test = next;
2555 : }
2556 : }
2557 :
2558 0 : static int GTimerInList(GXDisplay *gdisp,GTimer *timer) {
2559 : GTimer *test;
2560 :
2561 0 : for ( test=gdisp->timers; test!=NULL; test = test->next )
2562 0 : if ( test==timer )
2563 0 : return( true );
2564 :
2565 0 : return( false );
2566 : }
2567 :
2568 0 : static void GTimerReinstall(GXDisplay *gdisp,GTimer *timer) {
2569 :
2570 0 : GTimerRemove(gdisp,timer);
2571 0 : if ( timer->repeat_time!=0 ) {
2572 0 : GTimerSetNext(timer,timer->repeat_time);
2573 0 : GTimerInsertOrdered(gdisp,timer);
2574 : } else
2575 0 : free(timer);
2576 0 : }
2577 :
2578 0 : static GTimer *GXDrawRequestTimer(GWindow w,int32 time_from_now,int32 frequency,
2579 : void *userdata) {
2580 0 : GTimer *timer = calloc(1,sizeof(GTimer));
2581 :
2582 0 : GTimerSetNext(timer,time_from_now);
2583 :
2584 0 : timer->owner = w;
2585 0 : timer->repeat_time = frequency;
2586 0 : timer->userdata = userdata;
2587 0 : timer->active = false;
2588 0 : GTimerInsertOrdered(((GXWindow) w)->display,timer);
2589 0 : return( timer );
2590 : }
2591 :
2592 0 : static void GXDrawCancelTimer(GTimer *timer) {
2593 0 : GXDisplay *gdisp = ((GXWindow) (timer->owner))->display;
2594 :
2595 0 : if ( GTimerRemove(gdisp,timer))
2596 0 : free(timer);
2597 0 : }
2598 :
2599 0 : static void GXDrawSyncThread(GDisplay *gd, void (*func)(void *), void *data) {
2600 : #ifdef HAVE_PTHREAD_H
2601 0 : GXDisplay *gdisp = (GXDisplay *) gd;
2602 : struct things_to_do *ttd;
2603 :
2604 0 : pthread_mutex_lock(&gdisp->xthread.sync_mutex);
2605 0 : if ( gdisp->xthread.sync_sock==-1 ) {
2606 : #if !defined(__MINGW32__)
2607 : int sv[2];
2608 0 : socketpair(PF_UNIX,SOCK_DGRAM,0,sv);
2609 0 : gdisp->xthread.sync_sock = sv[0];
2610 0 : gdisp->xthread.send_sock = sv[1];
2611 : #endif
2612 : }
2613 0 : if ( func==NULL ) {
2614 : /* what's the point in calling this routine with no function? */
2615 : /* it sets things up so that the event loop is prepared to be */
2616 : /* stopped by the new socket. (otherwise it doesn't stop till */
2617 : /* it gets its next event. ie. if the eventloop is entered with */
2618 : /* sync_sock==-1 it won't wait on it, but next time it's entered*/
2619 : /* it won't be -1. This just allows us to make that condition */
2620 : /* true a little earlier */
2621 : } else {
2622 0 : for ( ttd=gdisp->xthread.things_to_do; ttd!=NULL &&
2623 0 : (ttd->func!=func || ttd->data!=data); ttd = ttd->next );
2624 0 : if ( ttd==NULL ) {
2625 0 : ttd = malloc(sizeof(struct things_to_do));
2626 0 : if ( gdisp->xthread.things_to_do==NULL )
2627 0 : send(gdisp->xthread.send_sock," ",1,0);
2628 0 : ttd->func = func;
2629 0 : ttd->data = data;
2630 0 : ttd->next = gdisp->xthread.things_to_do;
2631 0 : gdisp->xthread.things_to_do = ttd;
2632 : }
2633 : }
2634 0 : pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
2635 : #else
2636 : (func)(data);
2637 : #endif
2638 0 : }
2639 :
2640 0 : static int GXDrawProcessTimerEvent(GXDisplay *gdisp,GTimer *timer) {
2641 : struct gevent gevent;
2642 : GWindow o;
2643 0 : int ret = false;
2644 :
2645 0 : if ( timer->active )
2646 0 : return( false );
2647 0 : timer->active = true;
2648 0 : for ( o = timer->owner; o!=NULL && !o->is_dying; o=o->parent );
2649 0 : if ( timer->owner!=NULL && timer->owner->eh!=NULL && o==NULL ) {
2650 0 : memset(&gevent,0,sizeof(gevent));
2651 0 : gevent.type = et_timer;
2652 0 : gevent.w = timer->owner;
2653 0 : gevent.native_window = timer->owner->native_window;
2654 0 : gevent.u.timer.timer = timer;
2655 0 : gevent.u.timer.userdata = timer->userdata;
2656 0 : (timer->owner->eh)(timer->owner,&gevent);
2657 : /* If this routine calls something that checks events then */
2658 : /* without the active flag above we'd loop forever half-invoking*/
2659 : /* this timer */
2660 0 : ret = true;
2661 : }
2662 0 : if ( GTimerInList(gdisp,timer)) { /* carefull, they might have cancelled it */
2663 0 : timer->active = false;
2664 0 : if ( timer->repeat_time==0 )
2665 0 : GXDrawCancelTimer(timer);
2666 : else
2667 0 : GTimerReinstall(gdisp,timer);
2668 0 : ret = true;
2669 : }
2670 0 : return(ret);
2671 : }
2672 :
2673 0 : static void GXDrawCheckPendingTimers(GXDisplay *gdisp) {
2674 : struct timeval tv;
2675 : GTimer *timer, *next;
2676 :
2677 0 : gettimeofday(&tv,NULL);
2678 0 : for ( timer = gdisp->timers; timer!=NULL; timer=next ) {
2679 0 : next = timer->next;
2680 0 : if ( timer->time_sec>tv.tv_sec ||
2681 0 : (timer->time_sec == tv.tv_sec && timer->time_usec>tv.tv_usec ))
2682 : break;
2683 0 : if ( GXDrawProcessTimerEvent(gdisp,timer))
2684 0 : break;
2685 : }
2686 0 : }
2687 :
2688 : #ifdef HAVE_PTHREAD_H
2689 0 : static void GXDrawDoThings(GXDisplay *gdisp) {
2690 : char buffer[10];
2691 : /* we enter and leave with the mutex locked */
2692 :
2693 0 : while ( gdisp->xthread.things_to_do!=NULL ) {
2694 : struct things_to_do *ttd, *next;
2695 0 : recv(gdisp->xthread.sync_sock,buffer,sizeof(buffer),0);
2696 0 : ttd = gdisp->xthread.things_to_do;
2697 0 : gdisp->xthread.things_to_do = NULL;
2698 0 : pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
2699 : /* Don't let the user do stuff with the mutex locked */
2700 0 : while ( ttd!=NULL ) {
2701 0 : next = ttd->next;
2702 0 : (ttd->func)(ttd->data);
2703 0 : free(ttd);
2704 0 : ttd = next;
2705 : }
2706 0 : pthread_mutex_lock(&gdisp->xthread.sync_mutex);
2707 : }
2708 0 : }
2709 : #endif
2710 :
2711 0 : static void GXDrawWaitForEvent(GXDisplay *gdisp) {
2712 : struct timeval tv;
2713 0 : Display *display = gdisp->display;
2714 : struct timeval offset, *timeout;
2715 : fd_set read, write, except;
2716 : int fd,ret;
2717 0 : int idx = 0;
2718 :
2719 : for (;;) {
2720 0 : gettimeofday(&tv,NULL);
2721 0 : GXDrawCheckPendingTimers(gdisp);
2722 :
2723 : #ifdef _WACOM_DRV_BROKEN
2724 : _GXDraw_Wacom_TestEvents(gdisp);
2725 : #endif
2726 :
2727 0 : if ( XEventsQueued(display,QueuedAfterFlush))
2728 0 : return;
2729 : #ifdef HAVE_PTHREAD_H
2730 0 : if ( gdisp->xthread.sync_sock!=-1 ) {
2731 0 : pthread_mutex_lock(&gdisp->xthread.sync_mutex);
2732 0 : if ( gdisp->xthread.things_to_do )
2733 0 : GXDrawDoThings(gdisp);
2734 0 : pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
2735 : }
2736 : #endif
2737 0 : if ( gdisp->timers==NULL )
2738 0 : timeout = NULL;
2739 : else {
2740 0 : offset.tv_sec = gdisp->timers->time_sec - tv.tv_sec;
2741 0 : if (( offset.tv_usec= gdisp->timers->time_usec- tv.tv_usec)<0 ) {
2742 0 : offset.tv_usec += 1000000;
2743 0 : --offset.tv_sec;
2744 : }
2745 0 : if ( offset.tv_sec<0 || (offset.tv_sec==0 && offset.tv_usec==0))
2746 0 : continue;
2747 0 : timeout = &offset;
2748 : }
2749 0 : fd = XConnectionNumber(display);
2750 : // printf("gxdraw.... x connection number:%d\n", fd );
2751 0 : FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except);
2752 0 : FD_SET(fd,&read);
2753 0 : FD_SET(fd,&except);
2754 0 : if ( gdisp->xthread.sync_sock!=-1 ) {
2755 0 : FD_SET(gdisp->xthread.sync_sock,&read);
2756 0 : if ( gdisp->xthread.sync_sock>fd )
2757 0 : fd = gdisp->xthread.sync_sock;
2758 : }
2759 : #ifdef _WACOM_DRV_BROKEN
2760 : if ( gdisp->wacom_fd!=-1 ) {
2761 : FD_SET(gdisp->wacom_fd,&read);
2762 : if ( gdisp->wacom_fd>fd )
2763 : fd = gdisp->wacom_fd;
2764 : }
2765 : #endif
2766 :
2767 0 : for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
2768 : {
2769 0 : fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
2770 0 : FD_SET( cb->fd, &read );
2771 0 : fd = MAX( fd, cb->fd );
2772 : }
2773 :
2774 0 : ret = select(fd+1,&read,&write,&except,timeout);
2775 :
2776 0 : for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
2777 : {
2778 0 : fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
2779 0 : if( FD_ISSET(cb->fd,&read))
2780 0 : cb->callback( cb->fd, cb->udata );
2781 : }
2782 0 : }
2783 : }
2784 :
2785 0 : static void GXDrawPointerUngrab(GDisplay *gdisp) {
2786 0 : GXDisplay *gd = (GXDisplay *) gdisp;
2787 0 : XUngrabPointer(gd->display,gd->last_event_time);
2788 0 : gd->grab_window = NULL;
2789 0 : }
2790 :
2791 0 : static void GXDrawPointerGrab(GWindow gw) {
2792 0 : GXDisplay *gd = (GXDisplay *) (gw->display);
2793 0 : GXWindow w = (GXWindow) gw;
2794 0 : XGrabPointer(gd->display,w->w,false,
2795 : PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
2796 : GrabModeAsync, GrabModeAsync,None,None,gd->last_event_time);
2797 0 : gd->grab_window = gw;
2798 0 : }
2799 :
2800 :
2801 : /* Any input within the current dlg is ok */
2802 : /* if input is restricted to that dlg then nothing else is permitted */
2803 : /* if input is redirected then return the redirection to the current dlg */
2804 : /* if input is within an inactive window, then return the current dlg */
2805 : /* if there are any previous redirections outstanding then test them too */
2806 : /* (ie. if we are a dlg called from another dlg) */
2807 : /* Now it's possible that the return tries to redirect something to the */
2808 : /* current inactive window, and if so we should redirect that to the */
2809 : /* current dlg. Indeed this is likely in a dlg produced by a dlg */
2810 0 : static GWindow InputRedirection(struct inputRedirect *input,GWindow gw) {
2811 : GWindow ret;
2812 :
2813 0 : if ( input==NULL || input->cur_dlg->is_dying )
2814 0 : return( NULL );
2815 0 : if ( gw->is_toplevel && ((GXWindow) gw)->not_restricted )
2816 0 : return( NULL ); /* Popup windows (menus, pulldown lists) count as part of their effective parents */
2817 0 : if ( GDrawWindowIsAncestor(input->cur_dlg,gw))
2818 0 : return( NULL );
2819 0 : if ( input->it == it_restricted || input->it == it_redirected ) {
2820 0 : if ( input->it == it_redirected )
2821 0 : return( input->cur_dlg );
2822 : else
2823 0 : return( (GWindow) -1 );
2824 : }
2825 0 : if ( GDrawWindowIsAncestor(input->inactive,gw))
2826 0 : return( input->cur_dlg );
2827 0 : ret = NULL;
2828 0 : if ( input->prev!=NULL )
2829 0 : ret = InputRedirection(input->prev,gw);
2830 0 : if ( ret==NULL || ret==(GWindow) (-1) )
2831 0 : return( ret );
2832 0 : if ( GDrawWindowIsAncestor(input->inactive,ret))
2833 0 : return( input->cur_dlg );
2834 :
2835 0 : return( ret );
2836 : }
2837 :
2838 0 : static void dispatchEvent(GXDisplay *gdisp, XEvent *event) {
2839 : struct gevent gevent;
2840 0 : GWindow gw=NULL, redirect;
2841 : void *ret;
2842 : char charbuf[80], *pt;
2843 : Status status;
2844 : KeySym keysym; int len;
2845 : GPoint p;
2846 0 : int expecting_core = gdisp->expecting_core_event;
2847 : XEvent subevent;
2848 :
2849 0 : if ( XFilterEvent(event,None)) /* Make sure this happens before anything else */
2850 0 : return;
2851 :
2852 0 : gdisp->expecting_core_event = false;
2853 :
2854 0 : if ( XFindContext(gdisp->display,event->xany.window,gdisp->mycontext,(void *) &ret)==0 )
2855 0 : gw = (GWindow) ret;
2856 0 : if ( gw==NULL || (_GXDraw_WindowOrParentsDying((GXWindow) gw) && event->type!=DestroyNotify ))
2857 0 : return;
2858 0 : memset(&gevent,0,sizeof(gevent));
2859 0 : gevent.w = gw;
2860 0 : gevent.native_window = (void *) event->xany.window;
2861 0 : gevent.type = -1;
2862 0 : if ( event->type==KeyPress || event->type==ButtonPress || event->type == ButtonRelease ) {
2863 0 : if ( ((GXWindow ) gw)->transient_owner!=0 && ((GXWindow ) gw)->isverytransient )
2864 0 : gdisp->last_nontransient_window = ((GXWindow ) gw)->transient_owner;
2865 : else
2866 0 : gdisp->last_nontransient_window = ((GXWindow ) gw)->w;
2867 : }
2868 0 : switch(event->type) {
2869 : case KeyPress: case KeyRelease:
2870 0 : gdisp->last_event_time = event->xkey.time;
2871 0 : gevent.type = event->type==KeyPress?et_char:et_charup;
2872 0 : gevent.u.chr.time = event->xkey.time;
2873 0 : gevent.u.chr.state = event->xkey.state;
2874 0 : gevent.u.chr.autorepeat = 0;
2875 : // printf("event->xkey.state:%d\n", event->xkey.state );
2876 : /*#ifdef __Mac*/
2877 : /* On mac os x, map the command key to the control key. So Comand-Q=>^Q=>Quit */
2878 : /* No... don't. Let the user have access to the command key as distinct from control */
2879 : /* I don't think it hurts to leave this enabled... */
2880 : /* if ( (event->xkey.state&ksm_cmdmacosx) && gdisp->macosx_cmd ) gevent.u.chr.state |= ksm_control; */
2881 : /* Under 10.4 the option key generates the meta mask already */
2882 : /* Under 10.6 it does not (change may have happened in 10.5.8) */
2883 0 : if ( (event->xkey.state&ksm_option) && gdisp->macosx_cmd ) gevent.u.chr.state |= ksm_meta;
2884 : /*#endif*/
2885 0 : gevent.u.chr.x = event->xkey.x;
2886 0 : gevent.u.chr.y = event->xkey.y;
2887 0 : if ((redirect = InputRedirection(gdisp->input,gw))== (GWindow)(-1) ) {
2888 0 : len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
2889 0 : if ( event->type==KeyPress && len!=0 )
2890 0 : GXDrawBeep((GDisplay *) gdisp);
2891 0 : return;
2892 0 : } else if ( redirect!=NULL ) {
2893 : GPoint pt;
2894 0 : gevent.w = redirect;
2895 0 : pt.x = event->xkey.x; pt.y = event->xkey.y;
2896 0 : GXDrawTranslateCoordinates(gw,redirect,&pt);
2897 0 : gevent.u.chr.x = pt.x;
2898 0 : gevent.u.chr.y = pt.y;
2899 0 : gw = redirect;
2900 : }
2901 0 : if ( gevent.type==et_char ) {
2902 : /* The state may be modified in the gevent where a mac command key*/
2903 : /* entry gets converted to control, etc. */
2904 0 : if ( ((GXWindow) gw)->gic==NULL ) {
2905 0 : len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
2906 0 : charbuf[len] = '\0';
2907 0 : gevent.u.chr.keysym = keysym;
2908 0 : def2u_strncpy(gevent.u.chr.chars,charbuf,
2909 : sizeof(gevent.u.chr.chars)/sizeof(gevent.u.chr.chars[0]));
2910 : } else {
2911 : #ifdef X_HAVE_UTF8_STRING
2912 : /* I think there's a bug in SCIM. If I leave the meta(alt/option) modifier */
2913 : /* bit set, then scim returns no keysym and no characters. On the other hand,*/
2914 : /* if I don't leave that bit set, then the default input method on the mac */
2915 : /* will not do the Option key transformations properly. What I pass should */
2916 : /* be IM independent. So I don't think I should have to do the next line */
2917 0 : event->xkey.state &= ~Mod2Mask;
2918 : /* But I do */
2919 0 : len = Xutf8LookupString(((GXWindow) gw)->gic->ic,(XKeyPressedEvent*)event,
2920 : charbuf, sizeof(charbuf), &keysym, &status);
2921 0 : pt = charbuf;
2922 0 : if ( status==XBufferOverflow ) {
2923 0 : pt = malloc(len+1);
2924 0 : len = Xutf8LookupString(((GXWindow) gw)->gic->ic,(XKeyPressedEvent*)&event,
2925 : pt, len, &keysym, &status);
2926 : }
2927 0 : if ( status!=XLookupChars && status!=XLookupBoth )
2928 0 : len = 0;
2929 0 : if ( status!=XLookupKeySym && status!=XLookupBoth )
2930 0 : keysym = 0;
2931 0 : pt[len] = '\0';
2932 0 : gevent.u.chr.keysym = keysym;
2933 0 : utf82u_strncpy(gevent.u.chr.chars,pt,
2934 : sizeof(gevent.u.chr.chars)/sizeof(gevent.u.chr.chars[0]));
2935 0 : if ( pt!=charbuf )
2936 0 : free(pt);
2937 : #else
2938 : gevent.u.chr.keysym = keysym = 0;
2939 : gevent.u.chr.chars[0] = 0;
2940 : #endif
2941 : }
2942 : /* Convert X11 keysym values to unicode */
2943 0 : if ( keysym>=XKeysym_Mask )
2944 0 : keysym -= XKeysym_Mask;
2945 0 : else if ( keysym<=XKEYSYM_TOP && keysym>=0 )
2946 0 : keysym = gdraw_xkeysym_2_unicode[keysym];
2947 0 : gevent.u.chr.keysym = keysym;
2948 0 : if ( keysym==gdisp->mykey_keysym &&
2949 0 : (event->xkey.state&(ControlMask|Mod1Mask))==gdisp->mykey_mask ) {
2950 0 : gdisp->mykeybuild = !gdisp->mykeybuild;
2951 0 : gdisp->mykey_state = 0;
2952 0 : gevent.u.chr.chars[0] = '\0';
2953 0 : gevent.u.chr.keysym = '\0';
2954 0 : if ( !gdisp->mykeybuild && _GDraw_BuildCharHook!=NULL )
2955 0 : (_GDraw_BuildCharHook)((GDisplay *) gdisp);
2956 0 : } else if ( gdisp->mykeybuild )
2957 0 : _GDraw_ComposeChars((GDisplay *) gdisp,&gevent);
2958 : } else {
2959 : /* XLookupKeysym doesn't do shifts for us (or I don't know how to use the index arg to make it) */
2960 0 : len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
2961 0 : gevent.u.chr.keysym = keysym;
2962 0 : gevent.u.chr.chars[0] = '\0';
2963 : }
2964 :
2965 : /*
2966 : * If we are a charup, but the very next XEvent is a chardown
2967 : * on the same key, then we are just an autorepeat XEvent which
2968 : * other code might like to ignore
2969 : */
2970 0 : if ( gevent.type==et_charup && XEventsQueued(gdisp->display, QueuedAfterReading)) {
2971 : XEvent nev;
2972 0 : XPeekEvent(gdisp->display, &nev);
2973 0 : if (nev.type == KeyPress && nev.xkey.time == event->xkey.time &&
2974 0 : nev.xkey.keycode == event->xkey.keycode)
2975 : {
2976 0 : gevent.u.chr.autorepeat = 1;
2977 : }
2978 : }
2979 0 : break;
2980 : case ButtonPress: case ButtonRelease: case MotionNotify:
2981 0 : if ( expecting_core && gdisp->last_event_time==event->xbutton.time )
2982 0 : break; /* core event is a duplicate of device event */
2983 : /* (only it's not quite a duplicate, often it's a few pixels */
2984 : /* off from the device location */
2985 0 : if ( event->type==ButtonPress )
2986 0 : gdisp->grab_window = gw;
2987 0 : else if ( gdisp->grab_window!=NULL ) {
2988 0 : if ( gw!=gdisp->grab_window ) {
2989 : Window wjunk;
2990 0 : gevent.w = gw = gdisp->grab_window;
2991 0 : XTranslateCoordinates(gdisp->display,
2992 0 : event->xbutton.window,((GXWindow) gw)->w,
2993 0 : event->xbutton.x, event->xbutton.y,
2994 0 : &event->xbutton.x, &event->xbutton.y,
2995 : &wjunk);
2996 : }
2997 0 : if ( event->type==ButtonRelease )
2998 0 : gdisp->grab_window = NULL;
2999 : }
3000 :
3001 0 : gdisp->last_event_time = event->xbutton.time;
3002 0 : gevent.u.mouse.time = event->xbutton.time;
3003 0 : if ( event->type==MotionNotify && gdisp->grab_window==NULL )
3004 : /* Allow simple motion events to go through */;
3005 0 : else if ((redirect = InputRedirection(gdisp->input,gw))!=NULL ) {
3006 0 : if ( event->type==ButtonPress )
3007 0 : GXDrawBeep((GDisplay *) gdisp);
3008 0 : return;
3009 : }
3010 0 : gevent.u.mouse.state = event->xbutton.state;
3011 0 : gevent.u.mouse.x = event->xbutton.x;
3012 0 : gevent.u.mouse.y = event->xbutton.y;
3013 0 : gevent.u.mouse.button = event->xbutton.button;
3014 0 : gevent.u.mouse.device = NULL;
3015 0 : gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
3016 0 : if ( (event->xbutton.state&0x40) && gdisp->twobmouse_win )
3017 0 : gevent.u.mouse.button = 2;
3018 0 : if ( event->type == MotionNotify ) {
3019 : #if defined (__MINGW32__) || __CygWin
3020 : //For some reason, a mouse move event is triggered even if it hasn't moved.
3021 : if(gdisp->mousemove_last_x == event->xbutton.x &&
3022 : gdisp->mousemove_last_y == event->xbutton.y) {
3023 : return;
3024 : }
3025 : gdisp->mousemove_last_x = event->xbutton.x;
3026 : gdisp->mousemove_last_y = event->xbutton.y;
3027 : #endif
3028 0 : gevent.type = et_mousemove;
3029 0 : gevent.u.mouse.button = 0;
3030 0 : gevent.u.mouse.clicks = 0;
3031 0 : } else if ( event->type == ButtonPress ) {
3032 : int diff, temp;
3033 0 : gevent.type = et_mousedown;
3034 0 : if (( diff = event->xbutton.x-gdisp->bs.release_x )<0 ) diff= -diff;
3035 0 : if (( temp = event->xbutton.y-gdisp->bs.release_y )<0 ) temp= -temp;
3036 0 : if ( diff+temp<gdisp->bs.double_wiggle &&
3037 0 : event->xbutton.window == gdisp->bs.release_w &&
3038 0 : event->xbutton.button == gdisp->bs.release_button &&
3039 0 : event->xbutton.time-gdisp->bs.release_time < gdisp->bs.double_time &&
3040 0 : event->xbutton.time >= gdisp->bs.release_time ) /* Time can wrap */
3041 0 : ++ gdisp->bs.cur_click;
3042 : else
3043 0 : gdisp->bs.cur_click = 1;
3044 0 : gevent.u.mouse.clicks = gdisp->bs.cur_click;
3045 : } else {
3046 0 : gevent.type = et_mouseup;
3047 0 : gdisp->bs.release_time = event->xbutton.time;
3048 0 : gdisp->bs.release_w = event->xbutton.window;
3049 0 : gdisp->bs.release_x = event->xbutton.x;
3050 0 : gdisp->bs.release_y = event->xbutton.y;
3051 0 : gdisp->bs.release_button = event->xbutton.button;
3052 0 : gevent.u.mouse.clicks = gdisp->bs.cur_click;
3053 : }
3054 0 : break;
3055 : case Expose: case GraphicsExpose:
3056 0 : gevent.type = et_expose;
3057 0 : gevent.u.expose.rect.x = event->xexpose.x;
3058 0 : gevent.u.expose.rect.y = event->xexpose.y;
3059 0 : gevent.u.expose.rect.width = event->xexpose.width;
3060 0 : gevent.u.expose.rect.height = event->xexpose.height;
3061 : /* Slurp any pending exposes and merge into one big rectangle */
3062 0 : while ( XCheckTypedWindowEvent(gdisp->display,event->xany.window,event->type,
3063 : &subevent)) {
3064 0 : if ( subevent.xexpose.x+subevent.xexpose.width > gevent.u.expose.rect.x+gevent.u.expose.rect.width )
3065 0 : gevent.u.expose.rect.width = subevent.xexpose.x+subevent.xexpose.width - gevent.u.expose.rect.x;
3066 0 : if ( subevent.xexpose.x < gevent.u.expose.rect.x ) {
3067 0 : gevent.u.expose.rect.width += gevent.u.expose.rect.x - subevent.xexpose.x;
3068 0 : gevent.u.expose.rect.x = subevent.xexpose.x;
3069 : }
3070 0 : if ( subevent.xexpose.y+subevent.xexpose.height > gevent.u.expose.rect.y+gevent.u.expose.rect.height )
3071 0 : gevent.u.expose.rect.height = subevent.xexpose.y+subevent.xexpose.height - gevent.u.expose.rect.y;
3072 0 : if ( subevent.xexpose.y < gevent.u.expose.rect.y ) {
3073 0 : gevent.u.expose.rect.height += gevent.u.expose.rect.y - subevent.xexpose.y;
3074 0 : gevent.u.expose.rect.y = subevent.xexpose.y;
3075 : }
3076 : }
3077 : #ifndef _NO_LIBCAIRO
3078 0 : if ( ((GXWindow) gw)->usecairo ) /* X11 does this automatically. but cairo won't get the event */
3079 0 : GXDrawClear(gw,&gevent.u.expose.rect);
3080 : #endif
3081 0 : break;
3082 : case VisibilityNotify:
3083 0 : gevent.type = et_visibility;
3084 0 : gevent.u.visibility.state = event->xvisibility.state;
3085 0 : break;
3086 : case FocusIn: case FocusOut: /* Should only get this on top level */
3087 0 : gevent.type = et_focus;
3088 0 : gevent.u.focus.gained_focus = event->type==FocusIn;
3089 0 : gevent.u.focus.mnemonic_focus = false;
3090 0 : break;
3091 : case EnterNotify: case LeaveNotify: /* Should only get this on top level */
3092 0 : if ( event->xcrossing.detail == NotifyInferior )
3093 0 : break;
3094 0 : if ( gdisp->focusfollowsmouse && gw!=NULL && gw->eh!=NULL ) {
3095 0 : gevent.type = et_focus;
3096 0 : gevent.u.focus.gained_focus = event->type==EnterNotify;
3097 0 : gevent.u.focus.mnemonic_focus = false;
3098 0 : (gw->eh)((GWindow) gw, &gevent);
3099 : }
3100 0 : gevent.type = et_crossing;
3101 0 : gevent.u.crossing.x = event->xcrossing.x;
3102 0 : gevent.u.crossing.y = event->xcrossing.y;
3103 0 : gevent.u.crossing.state = event->xcrossing.state;
3104 0 : gevent.u.crossing.entered = event->type==EnterNotify;
3105 0 : gevent.u.crossing.device = NULL;
3106 0 : gevent.u.crossing.time = event->xcrossing.time;
3107 0 : break;
3108 : case ConfigureNotify:
3109 : /* Eat up multiple resize notifications in case the window manager */
3110 : /* does animated resizes */
3111 0 : while ( XCheckTypedWindowEvent(event->xconfigure.display,
3112 0 : event->xconfigure.window,ConfigureNotify,event));
3113 0 : gevent.type = et_resize;
3114 0 : gevent.u.resize.size.x = event->xconfigure.x;
3115 0 : gevent.u.resize.size.y = event->xconfigure.y;
3116 0 : gevent.u.resize.size.width = event->xconfigure.width;
3117 0 : gevent.u.resize.size.height = event->xconfigure.height;
3118 0 : if ( gw->is_toplevel ) {
3119 0 : p.x = 0; p.y = 0;
3120 0 : GXDrawTranslateCoordinates(gw,(GWindow) (gdisp->groot),&p);
3121 0 : gevent.u.resize.size.x = p.x;
3122 0 : gevent.u.resize.size.y = p.y;
3123 : }
3124 0 : gevent.u.resize.dx = gevent.u.resize.size.x-gw->pos.x;
3125 0 : gevent.u.resize.dy = gevent.u.resize.size.y-gw->pos.y;
3126 0 : gevent.u.resize.dwidth = gevent.u.resize.size.width-gw->pos.width;
3127 0 : gevent.u.resize.dheight = gevent.u.resize.size.height-gw->pos.height;
3128 0 : gevent.u.resize.moved = gevent.u.resize.sized = false;
3129 0 : if ( gevent.u.resize.dx!=0 || gevent.u.resize.dy!=0 )
3130 0 : gevent.u.resize.moved = true;
3131 0 : if ( gevent.u.resize.dwidth!=0 || gevent.u.resize.dheight!=0 ) {
3132 0 : gevent.u.resize.sized = true;
3133 : #ifndef _NO_LIBCAIRO
3134 0 : if ( ((GXWindow) gw)->usecairo )
3135 0 : _GXCDraw_ResizeWindow((GXWindow) gw, &gevent.u.resize.size);
3136 : #endif
3137 : }
3138 0 : gw->pos = gevent.u.resize.size;
3139 0 : if ( !gdisp->top_offsets_set && ((GXWindow) gw)->was_positioned &&
3140 0 : gw->is_toplevel && !((GXWindow) gw)->is_popup &&
3141 0 : !((GXWindow) gw)->istransient ) {
3142 : /* I don't know why I need a fudge factor here, but I do */
3143 0 : gdisp->off_x = gevent.u.resize.dx-2;
3144 0 : gdisp->off_y = gevent.u.resize.dy-1;
3145 0 : gdisp->top_offsets_set = true;
3146 : }
3147 0 : break;
3148 : case CreateNotify:
3149 : /* actually CreateNotify events only go to the window parent if */
3150 : /* substructureNotify is set. We aren't a window manager, so we */
3151 : /* shouldn't get any. Sigh. I simulate them instead */
3152 0 : gevent.type = et_create;
3153 0 : break;
3154 : case MapNotify:
3155 0 : gevent.type = et_map;
3156 0 : gevent.u.map.is_visible = true;
3157 0 : gw->is_visible = true;
3158 0 : break;
3159 : case UnmapNotify:
3160 0 : gevent.type = et_map;
3161 0 : gevent.u.map.is_visible = false;
3162 0 : gw->is_visible = false;
3163 0 : break;
3164 : case DestroyNotify:
3165 0 : gevent.type = et_destroy;
3166 0 : break;
3167 : case ClientMessage:
3168 0 : if ((redirect = InputRedirection(gdisp->input,gw))!=NULL ) {
3169 0 : GXDrawBeep((GDisplay *) gdisp);
3170 0 : return;
3171 : }
3172 0 : if ( event->xclient.message_type == gdisp->atoms.wm_protocols &&
3173 0 : event->xclient.data.l[0] == gdisp->atoms.wm_del_window )
3174 0 : gevent.type = et_close;
3175 0 : else if ( event->xclient.message_type == gdisp->atoms.drag_and_drop ) {
3176 0 : gevent.type = event->xclient.data.l[0];
3177 0 : gevent.u.drag_drop.x = event->xclient.data.l[1];
3178 0 : gevent.u.drag_drop.y = event->xclient.data.l[2];
3179 : }
3180 0 : break;
3181 : case SelectionClear: {
3182 : int i;
3183 0 : gdisp->last_event_time = event->xselectionclear.time;
3184 0 : gevent.type = et_selclear;
3185 0 : gevent.u.selclear.sel = sn_primary;
3186 0 : for ( i=0; i<sn_max; ++i ) {
3187 0 : if ( event->xselectionclear.selection==gdisp->selinfo[i].sel_atom ) {
3188 0 : gevent.u.selclear.sel = i;
3189 0 : break;
3190 : }
3191 : }
3192 0 : GXDrawClearSelData(gdisp,gevent.u.selclear.sel);
3193 0 : } break;
3194 : case SelectionRequest:
3195 0 : gdisp->last_event_time = event->xselectionrequest.time;
3196 0 : GXDrawTransmitSelection(gdisp,event);
3197 0 : break;
3198 : case SelectionNotify: /* !!!!! paste */
3199 : /*gdisp->last_event_time = event->xselection.time;*/ /* it's the request's time not the current? */
3200 0 : break;
3201 : case PropertyNotify:
3202 0 : gdisp->last_event_time = event->xproperty.time;
3203 0 : break;
3204 : case ReparentNotify:
3205 0 : if ( event->xreparent.parent==gdisp->root ) {
3206 0 : gw->parent = (GWindow) (gdisp->groot);
3207 0 : gw->is_toplevel = true;
3208 0 : } else if ( XFindContext(gdisp->display,event->xreparent.parent,gdisp->mycontext,(void *) &ret)==0 ) {
3209 0 : GWindow gparent = (GWindow) ret;
3210 0 : gw->parent = gparent;
3211 0 : gw->is_toplevel = (GXWindow) gparent==gdisp->groot;
3212 : }
3213 0 : break;
3214 : case MappingNotify:
3215 0 : XRefreshKeyboardMapping((XMappingEvent *) event);
3216 0 : break;
3217 : default:
3218 : #ifndef _NO_XKB
3219 0 : if ( event->type==gdisp->xkb.event ) {
3220 0 : switch ( ((XkbAnyEvent *) event)->xkb_type ) {
3221 : case XkbNewKeyboardNotify:
3222 : /* I don't think I need to do anything here. But I think I */
3223 : /* need to get the event since otherwise xkb restricts the */
3224 : /* keycodes it will send me */
3225 0 : break;
3226 : case XkbMapNotify:
3227 0 : XkbRefreshKeyboardMapping((XkbMapNotifyEvent *) event);
3228 0 : break;
3229 : }
3230 0 : break;
3231 : }
3232 : #endif
3233 : #ifndef _NO_XINPUT
3234 : if ( event->type>=LASTEvent ) { /* An XInput event */
3235 : int i,j;
3236 : static int types[5] = { et_mousemove, et_mousedown, et_mouseup, et_char, et_charup };
3237 : for ( i=0 ; i<gdisp->n_inputdevices; ++i ) {
3238 : if ( ((XDeviceButtonEvent *) event)->deviceid==gdisp->inputdevices[i].devid ) {
3239 : for ( j=0; j<5; ++j )
3240 : if ( event->type==gdisp->inputdevices[i].event_types[j] ) {
3241 : gevent.type = types[j];
3242 : goto found;
3243 : }
3244 : }
3245 : }
3246 : found: ;
3247 : if ( gevent.type != et_noevent ) {
3248 : gdisp->last_event_time = ((XDeviceButtonEvent *) event)->time;
3249 : gevent.u.mouse.time = ((XDeviceButtonEvent *) event)->time;
3250 : gevent.u.mouse.device = gdisp->inputdevices[i].name; /* Same place in key and mouse events */
3251 : if ( j>3 ) { /* Key event */
3252 : gevent.u.chr.state = ((XDeviceKeyEvent *) event)->device_state;
3253 : gevent.u.chr.x = ((XDeviceKeyEvent *) event)->x;
3254 : gevent.u.chr.y = ((XDeviceKeyEvent *) event)->y;
3255 : gevent.u.chr.keysym = ((XDeviceKeyEvent *) event)->keycode;
3256 : gevent.u.chr.chars[0] = 0;
3257 : if ( ((XDeviceKeyEvent *) event)->first_axis!=0 )
3258 : gevent.type = et_noevent; /* Repeat of previous event to add more axes */
3259 : } else {
3260 : /* Pass the buttons from the device, the key modifiers from the normal state */
3261 : gevent.u.mouse.state =
3262 : ( ((XDeviceButtonEvent *) event)->device_state & 0xffffff00) |
3263 : ( ((XDeviceButtonEvent *) event)->state & 0x000000ff);
3264 : gevent.u.mouse.x = ((XDeviceButtonEvent *) event)->x;
3265 : gevent.u.mouse.y = ((XDeviceButtonEvent *) event)->y;
3266 : gdisp->expecting_core_event = true;
3267 : if ( j!=0 ) {
3268 : gevent.u.mouse.button = ((XDeviceButtonEvent *) event)->button;
3269 : if ( ((XDeviceButtonEvent *) event)->first_axis!=0 )
3270 : gevent.type = et_noevent; /* Repeat of previous event to add more axes */
3271 : if ( ((XDeviceButtonEvent *) event)->axes_count==6 ) {
3272 : gevent.u.mouse.pressure = ((XDeviceButtonEvent *) event)->axis_data[2];
3273 : gevent.u.mouse.xtilt = ((XDeviceButtonEvent *) event)->axis_data[3];
3274 : gevent.u.mouse.ytilt = ((XDeviceButtonEvent *) event)->axis_data[4];
3275 : } else
3276 : gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
3277 : } else {
3278 : if ( ((XDeviceMotionEvent *) event)->first_axis!=0 )
3279 : gevent.type = et_noevent; /* Repeat of previous event to add more axes */
3280 : gevent.u.mouse.button = 0;
3281 : if ( ((XDeviceMotionEvent *) event)->axes_count==6 ) {
3282 : gevent.u.mouse.pressure = ((XDeviceMotionEvent *) event)->axis_data[2];
3283 : gevent.u.mouse.xtilt = ((XDeviceMotionEvent *) event)->axis_data[3];
3284 : gevent.u.mouse.ytilt = ((XDeviceMotionEvent *) event)->axis_data[4];
3285 : } else
3286 : gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
3287 : }
3288 : }
3289 : }
3290 : }
3291 : #endif
3292 0 : break;
3293 : }
3294 :
3295 0 : if ( gevent.type != et_noevent && gw!=NULL && gw->eh!=NULL )
3296 0 : (gw->eh)((GWindow) gw, &gevent);
3297 0 : if ( event->type==DestroyNotify && gw!=NULL )
3298 0 : _GXDraw_CleanUpWindow( gw );
3299 : }
3300 :
3301 0 : static void GXDrawForceUpdate(GWindow gw) {
3302 : XEvent event;
3303 0 : Window w=((GXWindow) gw)->w;
3304 0 : Display *display = ((GXDisplay *) (gw->display))->display;
3305 : /* Do NOT check for timer events here! we are only interested in Exposes */
3306 : /* I assume that GraphicsExposes are also caught by ExposureMask? */
3307 :
3308 0 : while ( XCheckWindowEvent(display,w,ExposureMask,&event))
3309 0 : dispatchEvent((GXDisplay *) (gw->display), &event);
3310 0 : }
3311 :
3312 : /* any event is good here */
3313 0 : static Bool allevents(Display *display, XEvent *event, char *arg) {
3314 0 : return( true );
3315 : }
3316 :
3317 0 : static Bool windowevents(Display *display, XEvent *event, char *arg) {
3318 0 : return( event->xany.window == (Window) arg );
3319 : }
3320 :
3321 0 : static void GXDrawProcessOneEvent(GDisplay *gdisp) {
3322 : XEvent event;
3323 0 : Display *display = ((GXDisplay *) gdisp)->display;
3324 : /* Handle one X event (actually we might also handle a bunch of timers too) */
3325 :
3326 0 : GXDrawWaitForEvent((GXDisplay *) gdisp);
3327 0 : XNextEvent(display,&event);
3328 0 : dispatchEvent((GXDisplay *) gdisp, &event);
3329 0 : }
3330 :
3331 : struct mmarg { Window w; int state; int stop; };
3332 :
3333 0 : static Bool mmpred(Display *d, XEvent *e, XPointer arg) {
3334 0 : struct mmarg *mmarg = (struct mmarg *) arg;
3335 :
3336 0 : if ( mmarg->stop )
3337 0 : return( False );
3338 0 : if ( e->type==MotionNotify ) {
3339 0 : if ( e->xmotion.window==mmarg->w && e->xmotion.state == mmarg->state )
3340 0 : return( True );
3341 0 : mmarg->stop = true;
3342 0 : } else if ( e->type == ButtonPress || e->type==ButtonRelease )
3343 0 : mmarg->stop = true;
3344 0 : return( False );
3345 : }
3346 :
3347 0 : static void GXDrawSkipMouseMoveEvents(GWindow w, GEvent *last) {
3348 : XEvent event;
3349 0 : GXWindow gw = (GXWindow) w;
3350 : struct mmarg arg;
3351 :
3352 0 : arg.w = gw->w; arg.state = last->u.mouse.state; arg.stop = false;
3353 0 : while ( XCheckIfEvent(gw->display->display,&event,mmpred,(XPointer) &arg) ) {
3354 0 : last->u.mouse.x = event.xmotion.x;
3355 0 : last->u.mouse.y = event.xmotion.y;
3356 : }
3357 0 : }
3358 :
3359 0 : static void GXDrawProcessPendingEvents(GDisplay *gdisp) {
3360 : XEvent event;
3361 0 : Display *display = ((GXDisplay *) gdisp)->display;
3362 : /* We don't wait for anything. Only stuff already in the queue */
3363 :
3364 0 : GXDrawCheckPendingTimers((GXDisplay *) gdisp);
3365 0 : while ( XCheckIfEvent(display,&event,allevents,NULL))
3366 0 : dispatchEvent((GXDisplay *) gdisp, &event);
3367 0 : }
3368 :
3369 0 : static void GXDrawProcessWindowEvents(GWindow w) {
3370 : XEvent event;
3371 0 : GXWindow gw = (GXWindow) w;
3372 0 : Display *display = gw->display->display;
3373 :
3374 0 : while ( XCheckIfEvent(display,&event,windowevents,(char *) (gw->w)))
3375 0 : dispatchEvent(gw->display, &event);
3376 0 : }
3377 :
3378 0 : static void GXDrawSync(GDisplay *gdisp) {
3379 0 : XSync(((GXDisplay *) gdisp)->display,false);
3380 0 : }
3381 :
3382 0 : void dispatchError(GDisplay *gdisp) {
3383 0 : if ((gdisp->err_flag) && (gdisp->err_report)) {
3384 0 : GDrawIErrorRun("%s",gdisp->err_report);
3385 : }
3386 0 : if (gdisp->err_report) {
3387 0 : free(gdisp->err_report); gdisp->err_report = NULL;
3388 : }
3389 0 : }
3390 :
3391 : /* Munch events until we no longer have any top level windows. That essentially*/
3392 : /* means no windows (even if they got reparented, we still think they are top)*/
3393 : /* At that point try very hard to clear out the event queue. It is conceivable*/
3394 : /* that doing so will create a new window. If no luck then return */
3395 0 : static void GXDrawEventLoop(GDisplay *gd) {
3396 : XEvent event;
3397 0 : GXDisplay *gdisp = (GXDisplay *) gd;
3398 0 : Display *display = gdisp->display;
3399 :
3400 : do {
3401 0 : while ( gdisp->top_window_count>0 ) {
3402 0 : GXDrawWaitForEvent(gdisp);
3403 0 : XNextEvent(display,&event);
3404 0 : dispatchEvent(gdisp, &event);
3405 0 : dispatchError(gd);
3406 : }
3407 0 : XSync(display,false);
3408 0 : GXDrawProcessPendingEvents(gd);
3409 0 : XSync(display,false);
3410 0 : } while ( gdisp->top_window_count>0 || XEventsQueued(display,QueuedAlready)>0 );
3411 0 : }
3412 :
3413 0 : static void GXDrawPostEvent(GEvent *e) {
3414 : /* Doesn't check event masks, not sure if that's desirable or not. It's easy though */
3415 0 : GXWindow gw = (GXWindow) (e->w);
3416 0 : e->native_window = ((GWindow) gw)->native_window;
3417 0 : (gw->eh)((GWindow) gw, e);
3418 0 : }
3419 :
3420 : /* Drag and drop works thusly:
3421 : the user drags a selection somewhere
3422 : as this happens we send out drag events to each window the cursor moves
3423 : over telling the window where the cursor is (to allow the window to do
3424 : feedback like showing a text cursor or something)
3425 : when we exit a window we send one last event (a dragout event) to let it
3426 : know it should clear its cursor
3427 : when the user drops the selection
3428 : the client grabs the DRAG_AND_DROP selection
3429 : fills it up with whatever types are appropriate
3430 : sends the window a drop event
3431 : the window looks at that event and extracts a (local to it) position of
3432 : the drop
3433 : it queries the selection to get the data
3434 : it performs the drop operation
3435 : */
3436 :
3437 0 : static void gxdrawSendDragOut(GXDisplay *gdisp) {
3438 :
3439 0 : if ( gdisp->last_dd.gw!=NULL ) {
3440 : GEvent e;
3441 0 : memset(&e,0,sizeof(e));
3442 0 : e.type = et_dragout;
3443 0 : e.u.drag_drop.x = gdisp->last_dd.rx;
3444 0 : e.u.drag_drop.y = gdisp->last_dd.ry;
3445 0 : e.native_window = NULL;
3446 0 : if ( gdisp->last_dd.gw->eh!=NULL )
3447 0 : (gdisp->last_dd.gw->eh)(gdisp->last_dd.gw,&e);
3448 : } else {
3449 : XEvent xe;
3450 0 : xe.type = ClientMessage;
3451 0 : xe.xclient.display = gdisp->display;
3452 0 : xe.xclient.window = gdisp->last_dd.w;
3453 0 : xe.xclient.message_type = gdisp->atoms.drag_and_drop;
3454 0 : xe.xclient.format = 32;
3455 0 : xe.xclient.data.l[0] = et_dragout;
3456 0 : xe.xclient.data.l[1] = gdisp->last_dd.rx;
3457 0 : xe.xclient.data.l[2] = gdisp->last_dd.ry;
3458 0 : XSendEvent(gdisp->display,gdisp->last_dd.w,False,0,&xe);
3459 : }
3460 0 : gdisp->last_dd.w = None;
3461 0 : gdisp->last_dd.gw = NULL;
3462 0 : }
3463 :
3464 0 : static void GXDrawPostDragEvent(GWindow w,GEvent *mouse,enum event_type et) {
3465 0 : GXWindow gw = (GXWindow) w;
3466 0 : GXDisplay *gdisp = gw->display;
3467 : GEvent e;
3468 : Window child, curwin;
3469 : int x,y;
3470 : void *vd;
3471 0 : GWindow destw = NULL;
3472 :
3473 : /* if the cursor hasn't moved much, don't bother to send a drag event */
3474 0 : if (( x = mouse->u.mouse.x-gdisp->last_dd.x )<0 ) x = -x;
3475 0 : if (( y = mouse->u.mouse.y-gdisp->last_dd.y )<0 ) y = -y;
3476 0 : if ( x+y < 4 && et==et_drag )
3477 0 : return;
3478 :
3479 0 : curwin = _GXDrawGetPointerWindow(w);
3480 :
3481 0 : if ( gdisp->last_dd.w!=None && gdisp->last_dd.w!=curwin )
3482 0 : gxdrawSendDragOut(gdisp);
3483 :
3484 0 : memset(&e,0,sizeof(e));
3485 :
3486 : /* Are we still within the original window? */
3487 0 : if ( curwin == gw->w ) {
3488 0 : e.type = et;
3489 0 : x = e.u.drag_drop.x = mouse->u.mouse.x;
3490 0 : y = e.u.drag_drop.y = mouse->u.mouse.y;
3491 0 : (gw->eh)(w, &e);
3492 : } else {
3493 0 : XTranslateCoordinates(gdisp->display,gw->w,curwin,
3494 0 : mouse->u.mouse.x,mouse->u.mouse.y,
3495 : &x,&y,&child);
3496 :
3497 0 : e.type = et;
3498 0 : e.u.drag_drop.x = x;
3499 0 : e.u.drag_drop.y = y;
3500 0 : e.native_window = (void *) curwin;
3501 :
3502 0 : if ( (curwin&0xfff00000)==(gw->w&0xfff00000) &&
3503 0 : XFindContext(gdisp->display,curwin,gdisp->mycontext,(void *) &vd)==0 ) {
3504 0 : destw = (GWindow) vd;
3505 : /* is it one of our windows? If so use our own event mechanism */
3506 0 : if ( destw->eh!=NULL )
3507 0 : (destw->eh)(destw,&e);
3508 0 : } else if ( curwin!=gdisp->root ) {
3509 : XEvent xe;
3510 0 : xe.type = ClientMessage;
3511 0 : xe.xclient.display = gdisp->display;
3512 0 : xe.xclient.window = curwin;
3513 0 : xe.xclient.message_type = gdisp->atoms.drag_and_drop;
3514 0 : xe.xclient.format = 32;
3515 0 : xe.xclient.data.l[0] = et;
3516 0 : xe.xclient.data.l[1] = x;
3517 0 : xe.xclient.data.l[2] = y;
3518 0 : XSendEvent(gdisp->display,curwin,False,0,&xe);
3519 : }
3520 : }
3521 0 : if ( et!=et_drop ) {
3522 0 : gdisp->last_dd.w = curwin;
3523 0 : gdisp->last_dd.gw = destw;
3524 0 : gdisp->last_dd.x = mouse->u.mouse.x;
3525 0 : gdisp->last_dd.y = mouse->u.mouse.y;
3526 0 : gdisp->last_dd.rx = x;
3527 0 : gdisp->last_dd.ry = y;
3528 : } else {
3529 0 : gdisp->last_dd.w = None;
3530 0 : gdisp->last_dd.gw = NULL;
3531 : }
3532 : }
3533 :
3534 : static int devopen_failed;
3535 : static char *device_name;
3536 :
3537 0 : static int devopenerror(Display *disp, XErrorEvent *err) {
3538 : /* Some ubuntu releases seem to give everybody wacom devices by default */
3539 : /* in their xorg.conf file. However if the user has no wacom tablet then */
3540 : /* an attempt to use one of those devices will cause X to return a */
3541 : /* BadDevice error */
3542 : /* Unfortunately there is no good way to test for BadDevice (at least */
3543 : /* not that I am aware of). It's an extension error, so its numeric value*/
3544 : /* varies from machine to machine. I could grab the error message as a */
3545 : /* string, but it could be localized, and might change too. */
3546 : /* So I just assume that any error in the extension error range is likely */
3547 : /* to be BadDevice */
3548 :
3549 0 : if ( err->error_code>=128 ) {
3550 0 : devopen_failed = true;
3551 0 : fprintf( stderr, "X11 claims there exists a device called \"%s\", but an attempt to open it fails.\n Rerun the program with the -dontopenxdevices argument.\n",
3552 : device_name );
3553 : } else {
3554 0 : myerrorhandler(disp,err);
3555 : }
3556 0 : return( 1 );
3557 : }
3558 :
3559 0 : static int GXDrawRequestDeviceEvents(GWindow w,int devcnt,struct gdeveventmask *de) {
3560 : #ifndef _NO_XINPUT
3561 : GXDisplay *gdisp = (GXDisplay *) (w->display);
3562 : int i,j,k,cnt,foo, availdevcnt;
3563 : XEventClass *classes;
3564 : GResStruct res[2];
3565 :
3566 : if ( !gdisp->devicesinit ) {
3567 : int ndevs=0;
3568 : XDeviceInfo *devs;
3569 : int dontopentemp = 0;
3570 :
3571 : memset(res,0,sizeof(res));
3572 : i=0;
3573 : res[i].resname = "DontOpenXDevices"; res[i].type = rt_bool; res[i].val = &dontopentemp; ++i;
3574 : res[i].resname = NULL;
3575 : GResourceFind(res,NULL);
3576 : if ( dontopentemp ) {
3577 : gdisp->devicesinit = true;
3578 : return( 0 );
3579 : }
3580 :
3581 : devs = XListInputDevices(gdisp->display,&ndevs);
3582 : gdisp->devicesinit = true;
3583 : if ( ndevs==0 )
3584 : return( 0 );
3585 : gdisp->inputdevices = calloc(ndevs+1,sizeof(struct inputdevices));
3586 : for ( i=0; i<ndevs; ++i ) {
3587 : gdisp->inputdevices[i].name = copy(devs[i].name);
3588 : gdisp->inputdevices[i].devid = devs[i].id;
3589 : }
3590 : gdisp->n_inputdevices = ndevs;
3591 : XFreeDeviceList(devs);
3592 : }
3593 : classes = NULL;
3594 : for ( k=0; k<2; ++k ) {
3595 : cnt=availdevcnt=0;
3596 : for ( j=0; de[j].device_name!=NULL; ++j ) {
3597 : for ( i=0; i<gdisp->n_inputdevices; ++i )
3598 : if ( strcmp(de[j].device_name,gdisp->inputdevices[i].name)==0 )
3599 : break;
3600 : if ( i<gdisp->n_inputdevices ) {
3601 : if ( gdisp->inputdevices[i].dev==NULL ) {
3602 : XSync(gdisp->display,false);
3603 : GDrawProcessPendingEvents((GDisplay *) gdisp);
3604 : XSetErrorHandler(/*gdisp->display,*/devopenerror);
3605 : devopen_failed = false;
3606 : device_name = gdisp->inputdevices[i].name;
3607 : gdisp->inputdevices[i].dev = XOpenDevice(gdisp->display,gdisp->inputdevices[i].devid);
3608 : XSync(gdisp->display,false);
3609 : GDrawProcessPendingEvents((GDisplay *) gdisp);
3610 : XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
3611 : if ( devopen_failed )
3612 : gdisp->inputdevices[i].dev = NULL;
3613 : }
3614 : if ( gdisp->inputdevices[i].dev!=NULL ) {
3615 : ++availdevcnt;
3616 : if ( de[j].event_mask & (1<<et_mousemove) ) {
3617 : if ( classes!=NULL )
3618 : DeviceMotionNotify(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[0],classes[cnt]);
3619 : ++cnt;
3620 : }
3621 : if ( de[j].event_mask & (1<<et_mousedown) ) {
3622 : if ( classes!=NULL )
3623 : DeviceButtonPress(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[1],classes[cnt]);
3624 : ++cnt;
3625 : }
3626 : if ( de[j].event_mask & (1<<et_mouseup) ) {
3627 : if ( classes!=NULL )
3628 : DeviceButtonRelease(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[2],classes[cnt]);
3629 : ++cnt;
3630 : }
3631 : if ( (de[j].event_mask & (1<<et_mousedown)) && (de[j].event_mask & (1<<et_mouseup)) ) {
3632 : if ( classes!=NULL )
3633 : DeviceButtonPressGrab(gdisp->inputdevices[i].dev,foo,classes[cnt]);
3634 : ++cnt;
3635 : }
3636 : if ( de[j].event_mask & (1<<et_char) ) {
3637 : if ( classes!=NULL )
3638 : DeviceKeyPress(gdisp->inputdevices[i].dev,foo,classes[cnt]);
3639 : ++cnt;
3640 : }
3641 : if ( de[j].event_mask & (1<<et_charup) ) {
3642 : if ( classes!=NULL )
3643 : DeviceKeyRelease(gdisp->inputdevices[i].dev,foo,classes[cnt]);
3644 : ++cnt;
3645 : }
3646 : }
3647 : }
3648 : }
3649 : if ( cnt==0 )
3650 : return(0);
3651 : if ( k==0 )
3652 : classes = malloc(cnt*sizeof(XEventClass));
3653 : }
3654 : XSelectExtensionEvent(gdisp->display,((GXWindow) w)->w,classes,cnt);
3655 : free(classes);
3656 : return( availdevcnt );
3657 : #else
3658 0 : return( 0 );
3659 : #endif
3660 : }
3661 :
3662 0 : static Bool exposeornotify(Display *d,XEvent *e,XPointer arg) {
3663 0 : if ( e->type == Expose || e->type == GraphicsExpose ||
3664 0 : e->type == CreateNotify || e->type == MapNotify ||
3665 0 : e->type == DestroyNotify || e->type == UnmapNotify ||
3666 0 : (e->type == SelectionNotify && e->xselection.requestor==(Window) arg) ||
3667 0 : e->type == SelectionClear || e->type == SelectionRequest )
3668 0 : return( true );
3669 :
3670 0 : return( false );
3671 : }
3672 :
3673 0 : static int GXDrawWaitForNotifyEvent(GXDisplay *gdisp,XEvent *event, Window w) {
3674 : struct timeval tv, giveup, timer, *which;
3675 0 : Display *display = gdisp->display;
3676 : struct timeval offset;
3677 : fd_set read, write, except;
3678 : int fd,ret;
3679 0 : int idx = 0;
3680 :
3681 0 : gettimeofday(&giveup,NULL);
3682 0 : giveup.tv_sec += gdisp->SelNotifyTimeout;
3683 :
3684 : for (;;) {
3685 0 : gettimeofday(&tv,NULL);
3686 0 : GXDrawCheckPendingTimers(gdisp);
3687 : #ifdef _WACOM_DRV_BROKEN
3688 : _GXDraw_Wacom_TestEvents(gdisp);
3689 : #endif
3690 : #ifdef HAVE_PTHREAD_H
3691 0 : if ( gdisp->xthread.sync_sock!=-1 ) {
3692 0 : pthread_mutex_lock(&gdisp->xthread.sync_mutex);
3693 0 : if ( gdisp->xthread.things_to_do )
3694 0 : GXDrawDoThings(gdisp);
3695 0 : pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
3696 : }
3697 : #endif
3698 :
3699 0 : while ( XCheckIfEvent(display,event,exposeornotify,(XPointer) w)) {
3700 0 : if ( event->type == SelectionNotify )
3701 0 : return( true );
3702 0 : dispatchEvent(gdisp, event);
3703 : }
3704 : /* Which happens sooner? The timeout for waiting for a paste response,*/
3705 : /* or one of the timers? */
3706 0 : if ( gdisp->timers==NULL )
3707 0 : which = &giveup;
3708 0 : else if ( giveup.tv_sec<gdisp->timers->time_sec ||
3709 0 : ( giveup.tv_sec==gdisp->timers->time_sec && giveup.tv_usec<gdisp->timers->time_usec ))
3710 0 : which = &giveup;
3711 : else {
3712 0 : timer.tv_usec = gdisp->timers->time_usec; timer.tv_sec = gdisp->timers->time_sec;
3713 0 : which = &timer;
3714 : }
3715 0 : offset.tv_sec = which->tv_sec - tv.tv_sec;
3716 0 : if (( offset.tv_usec= which->tv_usec- tv.tv_usec)<0 ) {
3717 0 : offset.tv_usec += 1000000;
3718 0 : --offset.tv_sec;
3719 : }
3720 0 : if ( offset.tv_sec<0 || (offset.tv_sec==0 && offset.tv_usec==0)) {
3721 0 : if ( which == &giveup )
3722 0 : return( false );
3723 : } else
3724 0 : continue; /* Handle timer */
3725 :
3726 0 : fd = XConnectionNumber(display);
3727 0 : FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except);
3728 0 : FD_SET(fd,&read);
3729 0 : FD_SET(fd,&except);
3730 0 : if ( gdisp->xthread.sync_sock!=-1 ) {
3731 0 : FD_SET(gdisp->xthread.sync_sock,&read);
3732 0 : if ( gdisp->xthread.sync_sock>fd )
3733 0 : fd = gdisp->xthread.sync_sock;
3734 : }
3735 : #ifdef _WACOM_DRV_BROKEN
3736 : if ( gdisp->wacom_fd!=-1 ) {
3737 : FD_SET(gdisp->wacom_fd,&read);
3738 : if ( gdisp->wacom_fd>fd )
3739 : fd = gdisp->wacom_fd;
3740 : }
3741 : #endif
3742 :
3743 0 : for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
3744 : {
3745 0 : fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
3746 0 : FD_SET( cb->fd, &read );
3747 0 : fd = MAX( fd, cb->fd );
3748 : }
3749 :
3750 0 : ret = select(fd+1,&read,&write,&except,&offset);
3751 :
3752 0 : for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
3753 : {
3754 0 : fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
3755 0 : if( FD_ISSET(cb->fd,&read))
3756 0 : cb->callback( cb->fd, cb->udata );
3757 : }
3758 0 : }
3759 : }
3760 :
3761 0 : static Atom GXDrawGetAtom(GXDisplay *gd, char *name) {
3762 : int i;
3763 :
3764 0 : if ( gd->atomdata==NULL ) {
3765 0 : gd->atomdata = calloc(10,sizeof(struct atomdata));
3766 0 : gd->amax = 10;
3767 : }
3768 0 : for ( i=0; i<gd->alen; ++i )
3769 0 : if ( strcmp(name,gd->atomdata[i].atomname)==0 )
3770 0 : return( gd->atomdata[i].xatom );
3771 :
3772 0 : if ( i>=gd->amax )
3773 0 : gd->atomdata = realloc(gd->atomdata,(gd->amax+=10)*sizeof(struct atomdata));
3774 0 : gd->atomdata[i].atomname = copy(name);
3775 0 : gd->atomdata[i].xatom = XInternAtom(gd->display,name,false);
3776 0 : ++gd->alen;
3777 0 : return( gd->atomdata[i].xatom );
3778 : }
3779 :
3780 0 : static void GXDrawClearSelData(GXDisplay *gd,enum selnames sel) {
3781 0 : struct seldata *sd = gd->selinfo[sel].datalist, *next;
3782 :
3783 0 : while ( sd!=NULL ) {
3784 0 : next = sd->next;
3785 0 : if ( sd->freedata )
3786 0 : (sd->freedata)(sd->data);
3787 : else
3788 0 : free(sd->data);
3789 0 : free(sd);
3790 0 : sd = next;
3791 : }
3792 0 : gd->selinfo[sel].datalist = NULL;
3793 0 : gd->selinfo[sel].owner = NULL;
3794 0 : }
3795 :
3796 0 : static void GXDrawGrabSelection(GWindow w,enum selnames sel) {
3797 0 : GXDisplay *gd = (GXDisplay *) (w->display);
3798 0 : GXWindow gw = (GXWindow) w;
3799 0 : if ( gd->selinfo[sel].owner!=NULL && gd->selinfo[sel].datalist != NULL) {
3800 : GEvent e;
3801 0 : memset(&e,0,sizeof(e));
3802 0 : e.type = et_selclear;
3803 0 : e.u.selclear.sel = sel;
3804 0 : e.native_window = (void *) (intpt) gd->selinfo[sel].owner->w;
3805 0 : if ( gd->selinfo[sel].owner->eh!=NULL )
3806 0 : (gd->selinfo[sel].owner->eh)((GWindow) gd->selinfo[sel].owner, &e);
3807 : }
3808 : //Only one clipboard exists on Windows. Selectively set the selection owner
3809 : //as otherwise the Windows clipboard will be cleared.
3810 : #ifdef _WIN32
3811 : if (sel == sn_clipboard)
3812 : #endif
3813 0 : XSetSelectionOwner(gd->display,gd->selinfo[sel].sel_atom,gw->w,gd->last_event_time);
3814 0 : GXDrawClearSelData(gd,sel);
3815 0 : gd->selinfo[sel].owner = gw;
3816 0 : gd->selinfo[sel].timestamp = gd->last_event_time;
3817 0 : }
3818 :
3819 0 : static void GXDrawAddSelectionType(GWindow w,enum selnames sel,char *type,
3820 : void *data,int32 cnt,int32 unitsize, void *(*gendata)(void *,int32 *len),
3821 : void (*freedata)(void *)) {
3822 0 : GXDisplay *gd = (GXDisplay *) (w->display);
3823 0 : int typeatom = GXDrawGetAtom(gd,type);
3824 : struct seldata *sd;
3825 :
3826 0 : if ( unitsize!=1 && unitsize!=2 && unitsize!=4 ) {
3827 0 : GDrawIError( "Bad unitsize to GXDrawAddSelectionType" );
3828 0 : unitsize = 1;
3829 : }
3830 0 : for ( sd=gd->selinfo[sel].datalist; sd!=NULL && sd->typeatom!=typeatom;
3831 0 : sd = sd->next );
3832 0 : if ( sd==NULL ) {
3833 0 : sd = malloc(sizeof(struct seldata));
3834 0 : sd->next = gd->selinfo[sel].datalist;
3835 0 : gd->selinfo[sel].datalist = sd;
3836 0 : sd->typeatom = typeatom;
3837 : }
3838 0 : sd->cnt = cnt;
3839 0 : sd->data = data;
3840 0 : sd->unitsize = unitsize;
3841 0 : sd->gendata = gendata;
3842 0 : sd->freedata = freedata;
3843 0 : }
3844 :
3845 0 : static void GXDrawTransmitSelection(GXDisplay *gd,XEvent *event) {
3846 0 : int prop_set = False;
3847 : int which;
3848 : XEvent e_to_send;
3849 : Atom *targets;
3850 0 : Atom cur_targ = event->xselectionrequest.target;
3851 : Atom prop;
3852 : int tlen;
3853 : struct seldata *sd;
3854 0 : int is_multiple = cur_targ == GXDrawGetAtom(gd,"MULTIPLE");
3855 0 : int found = 0;
3856 : void *temp;
3857 : int32 proplen;
3858 :
3859 0 : for ( which = 0; which<sn_max; ++which )
3860 0 : if ( event->xselectionrequest.selection == gd->selinfo[which].sel_atom )
3861 0 : break;
3862 0 : if ( which==sn_max )
3863 0 : return;
3864 :
3865 0 : e_to_send.type = SelectionNotify;
3866 0 : e_to_send.xselection.display = event->xselectionrequest.display;
3867 0 : e_to_send.xselection.requestor = event->xselectionrequest.requestor;
3868 0 : e_to_send.xselection.selection = event->xselectionrequest.selection;
3869 0 : e_to_send.xselection.target = event->xselectionrequest.target;
3870 0 : e_to_send.xselection.property = event->xselectionrequest.property;
3871 0 : e_to_send.xselection.time = event->xselectionrequest.time;
3872 : /* Obsolete convention */
3873 0 : if ( e_to_send.xselection.property==None )
3874 0 : e_to_send.xselection.property = e_to_send.xselection.target;
3875 0 : prop = e_to_send.xselection.property;
3876 :
3877 0 : tlen = 0;
3878 0 : for ( sd = gd->selinfo[which].datalist; sd!=NULL && !found; sd = sd->next, ++tlen ) {
3879 0 : if ( cur_targ==sd->typeatom || is_multiple ) {
3880 0 : found = (cur_targ==sd->typeatom);
3881 0 : prop_set = 1;
3882 0 : if (is_multiple)
3883 0 : prop = sd->typeatom;
3884 0 : temp = sd->data;
3885 0 : proplen = sd->cnt;
3886 0 : if ( sd->gendata )
3887 0 : temp = (sd->gendata)(temp,&proplen);
3888 0 : XChangeProperty(e_to_send.xselection.display,
3889 : e_to_send.xselection.requestor,
3890 : prop,
3891 0 : sd->typeatom,
3892 0 : 8*sd->unitsize,PropModeReplace,
3893 : temp,proplen);
3894 0 : if ( sd->gendata )
3895 0 : free( temp );
3896 : }
3897 : }
3898 0 : sd = gd->selinfo[which].datalist;
3899 0 : if (sd!=NULL && ( cur_targ==GXDrawGetAtom(gd,"LENGTH") || is_multiple )) {
3900 0 : if ( is_multiple )
3901 0 : prop = GXDrawGetAtom(gd,"LENGTH");
3902 0 : temp = NULL; proplen = sd->cnt*sd->unitsize;
3903 0 : if ( sd->gendata )
3904 0 : temp = (sd->gendata)(sd->data,&proplen);
3905 0 : XChangeProperty(e_to_send.xselection.display,
3906 : e_to_send.xselection.requestor,
3907 : prop,
3908 : GXDrawGetAtom(gd,"LENGTH"),32,PropModeReplace,
3909 : (void *) &proplen,1);
3910 0 : free(temp);
3911 0 : prop_set = True;
3912 : }
3913 0 : if ( sd!=NULL && ( cur_targ==GXDrawGetAtom(gd,"IDENTIFY") || is_multiple )) {
3914 0 : int temp = sd->typeatom;
3915 0 : if (is_multiple)
3916 0 : prop = GXDrawGetAtom(gd,"IDENTIFY");
3917 0 : XChangeProperty(e_to_send.xselection.display,
3918 : e_to_send.xselection.requestor,
3919 : prop,
3920 : GXDrawGetAtom(gd,"IDENTIFY"),32,PropModeReplace,
3921 : (void *) &temp,1);
3922 0 : prop_set = True;
3923 : }
3924 0 : if ( cur_targ==GXDrawGetAtom(gd,"TIMESTAMP") || is_multiple ) {
3925 0 : if (is_multiple)
3926 0 : prop = GXDrawGetAtom(gd,"TIMESTAMP");
3927 0 : XChangeProperty(e_to_send.xselection.display,
3928 : e_to_send.xselection.requestor,
3929 : prop,
3930 : XA_INTEGER,32,PropModeReplace,
3931 0 : (void *) &gd->selinfo[which].timestamp,1);
3932 0 : prop_set = True;
3933 : }
3934 0 : if ( cur_targ==GXDrawGetAtom(gd,"TARGETS") || is_multiple ) {
3935 : int i;
3936 0 : targets = calloc(tlen+5,sizeof(Atom));
3937 0 : for ( sd = gd->selinfo[which].datalist, i=0; sd!=NULL; sd = sd->next, ++i )
3938 0 : targets[i] = sd->typeatom;
3939 0 : targets[i++] = GXDrawGetAtom(gd,"LENGTH");
3940 0 : targets[i++] = GXDrawGetAtom(gd,"IDENTIFY");
3941 0 : targets[i++] = GXDrawGetAtom(gd,"TIMESTAMP");
3942 0 : targets[i++] = GXDrawGetAtom(gd,"TARGETS");
3943 0 : targets[i++] = GXDrawGetAtom(gd,"MULTIPLE");
3944 0 : if (is_multiple)
3945 0 : prop = GXDrawGetAtom(gd,"TARGETS");
3946 0 : XChangeProperty(e_to_send.xselection.display,
3947 : e_to_send.xselection.requestor,
3948 : prop,
3949 : XA_ATOM,32,PropModeReplace,
3950 : (void *) targets,i);
3951 0 : free(targets);
3952 0 : prop_set = True;
3953 : }
3954 0 : if ( is_multiple ) {
3955 : int i;
3956 0 : targets = calloc(tlen+5,sizeof(Atom));
3957 0 : for ( sd = gd->selinfo[which].datalist, i=0; sd!=NULL; sd = sd->next, ++i )
3958 0 : targets[i] = sd->typeatom;
3959 0 : targets[i++] = GXDrawGetAtom(gd,"LENGTH");
3960 0 : targets[i++] = GXDrawGetAtom(gd,"IDENTIFY");
3961 0 : targets[i++] = GXDrawGetAtom(gd,"TIMESTAMP");
3962 0 : targets[i++] = GXDrawGetAtom(gd,"TARGETS");
3963 0 : targets[i++] = GXDrawGetAtom(gd,"MULTIPLE");
3964 0 : XChangeProperty(e_to_send.xselection.display,
3965 : e_to_send.xselection.requestor,
3966 0 : targets[i-1], /* multiple */
3967 : XA_ATOM,32,PropModeReplace,
3968 : (void *) targets,i);
3969 0 : XChangeProperty(e_to_send.xselection.display,
3970 : e_to_send.xselection.requestor,
3971 : e_to_send.xselection.target,
3972 : XA_ATOM,32,PropModeReplace,
3973 : (void *) targets,i);
3974 0 : free(targets);
3975 : }
3976 :
3977 0 : if ( !prop_set )
3978 0 : e_to_send.xselection.property = None;
3979 0 : XSendEvent(gd->display,e_to_send.xselection.requestor,True,0,&e_to_send);
3980 : }
3981 :
3982 0 : static void *GXDrawRequestSelection(GWindow w,enum selnames sn, char *typename, int32 *len) {
3983 0 : GXDisplay *gd = (GXDisplay *) (w->display);
3984 0 : GXWindow gw = (GXWindow) w;
3985 0 : Display *display = gd->display;
3986 : unsigned long nitems, bytes_after;
3987 : Atom actual_type;
3988 : int actual_format;
3989 : char *prop;
3990 : char *temp;
3991 : int bytelen;
3992 0 : Atom typeatom = GXDrawGetAtom(gd,typename);
3993 : XEvent xevent;
3994 : struct seldata *sd;
3995 :
3996 0 : if ( len!=NULL )
3997 0 : *len = 0;
3998 :
3999 : /* Do we own the selection? If so check for the type in our list of things*/
4000 : /* if present return a copy (so they can free it), if absent return NULL */
4001 0 : if ( gd->selinfo[sn].owner!=NULL ) {
4002 0 : for ( sd=gd->selinfo[sn].datalist; sd!=NULL; sd=sd->next ) {
4003 0 : if ( sd->typeatom == typeatom ) {
4004 0 : if ( sd->gendata!=NULL ) {
4005 0 : temp = (sd->gendata)(sd->data,len);
4006 0 : *len *= sd->unitsize;
4007 : } else {
4008 0 : bytelen = sd->unitsize*sd->cnt;
4009 0 : temp = malloc(bytelen+4);
4010 0 : memcpy(temp,sd->data,bytelen);
4011 0 : temp[bytelen] = '\0';
4012 0 : temp[bytelen+1] = '\0';
4013 0 : temp[bytelen+2] = '\0';
4014 0 : temp[bytelen+3] = '\0';
4015 0 : *len = bytelen;
4016 : }
4017 0 : return( temp );
4018 : }
4019 : }
4020 0 : return( NULL );
4021 : }
4022 :
4023 : /* Otherwise ask the owner for the selection, wait to be notified that he's*/
4024 : /* given it to us (we might time out, return NULL if we do) */
4025 0 : XConvertSelection(display, gd->selinfo[sn].sel_atom, typeatom,
4026 0 : gd->selinfo[sn].sel_atom, gw->w,gd->last_event_time);
4027 0 : if ( !GXDrawWaitForNotifyEvent(gd,&xevent, gw->w) ||
4028 0 : xevent.xselection.property == None ) {
4029 0 : return( NULL );
4030 0 : } else if (XGetWindowProperty(display,xevent.xselection.requestor,
4031 : xevent.xselection.property,0L,100000000L,True,AnyPropertyType,
4032 : &actual_type,&actual_format,&nitems,&bytes_after,
4033 0 : (unsigned char **) &prop) != Success ||
4034 0 : prop==NULL ) {
4035 0 : GDrawIError("Could not retrieve property in GXDrawRequestSelection" );
4036 0 : return( NULL );
4037 : }
4038 :
4039 0 : bytelen = nitems * (actual_format/8);
4040 0 : temp = malloc(bytelen+4);
4041 0 : memcpy(temp,prop,bytelen);
4042 0 : temp[bytelen]='\0';
4043 0 : temp[bytelen+1]='\0'; /* Nul terminate unicode strings too */
4044 0 : temp[bytelen+2] = '\0';
4045 0 : temp[bytelen+3] = '\0';
4046 0 : if ( len!=NULL )
4047 0 : *len = bytelen;
4048 0 : XFree(prop);
4049 0 : return(temp);
4050 : }
4051 :
4052 0 : static int GXDrawSelectionHasType(GWindow w,enum selnames sn, char *typename) {
4053 0 : GXDisplay *gd = (GXDisplay *) (w->display);
4054 0 : Display *display = gd->display;
4055 0 : GXWindow gw = (GXWindow) w;
4056 : unsigned long nitems, bytes_after;
4057 : Atom actual_type;
4058 : int actual_format;
4059 : char *prop;
4060 0 : Atom typeatom = GXDrawGetAtom(gd,typename);
4061 : int i;
4062 : XEvent xevent;
4063 : struct seldata *sd;
4064 :
4065 : /* Do we own the selection? If so check for the type in our list of things*/
4066 : /* if present return a copy (so they can free it), if absent return NULL */
4067 0 : if ( gd->selinfo[sn].owner!=NULL ) {
4068 0 : for ( sd=gd->selinfo[sn].datalist; sd!=NULL; sd=sd->next ) {
4069 0 : if ( sd->typeatom == typeatom )
4070 0 : return( true );
4071 : }
4072 0 : return( false );
4073 : }
4074 :
4075 0 : if ( gd->seltypes.timestamp!=gd->last_event_time ) {
4076 : /* List is not up to date, ask for a new one */
4077 0 : gd->seltypes.cnt = 0;
4078 0 : XFree(gd->seltypes.types); gd->seltypes.types = NULL;
4079 0 : XConvertSelection(display, gd->selinfo[sn].sel_atom, GXDrawGetAtom(gd,"TARGETS"),
4080 0 : gd->selinfo[sn].sel_atom, gw->w,gd->last_event_time);
4081 0 : if ( !GXDrawWaitForNotifyEvent(gd,&xevent, gw->w) ||
4082 0 : xevent.xselection.property == None ) {
4083 0 : return( false );
4084 0 : } else if (XGetWindowProperty(display,xevent.xselection.requestor,
4085 : xevent.xselection.property,0L,100000000L,True,AnyPropertyType,
4086 : &actual_type,&actual_format,&nitems,&bytes_after,
4087 0 : (unsigned char **) &prop) != Success ||
4088 0 : prop==NULL || actual_format!=32 ) {
4089 0 : GDrawIError("Could not retrieve property in GXDrawSelectionHasType" );
4090 0 : return( false );
4091 : } else {
4092 0 : gd->seltypes.cnt = nitems;
4093 0 : gd->seltypes.types = (Atom *) prop;
4094 0 : gd->seltypes.timestamp = gd->last_event_time = xevent.xselection.time;
4095 : }
4096 : }
4097 0 : for ( i=0; i<gd->seltypes.cnt; ++i )
4098 0 : if ( gd->seltypes.types[i]==typeatom )
4099 0 : return( true );
4100 :
4101 0 : return( false );
4102 : }
4103 :
4104 0 : static void GXDrawBindSelection(GDisplay *disp,enum selnames sn, char *atomname) {
4105 0 : GXDisplay *gdisp = (GXDisplay *) disp;
4106 0 : Display *display = gdisp->display;
4107 0 : if ( sn>=0 && sn<sn_max )
4108 0 : gdisp->selinfo[sn].sel_atom = XInternAtom(display,atomname,False);
4109 0 : }
4110 :
4111 0 : static int GXDrawSelectionHasOwner(GDisplay *disp,enum selnames sn) {
4112 0 : GXDisplay *gdisp = (GXDisplay *) disp;
4113 0 : Display *display = ((GXDisplay *) gdisp)->display;
4114 0 : if ( sn<0 || sn>=sn_max )
4115 0 : return( false );
4116 :
4117 0 : return( XGetSelectionOwner(display,gdisp->selinfo[sn].sel_atom)!=None );
4118 : }
4119 :
4120 0 : static int match(char **list, char *val) {
4121 : int i;
4122 :
4123 0 : for ( i=0; list[i]!=NULL; ++i )
4124 0 : if ( strmatch(val,list[i])==0 )
4125 0 : return( i );
4126 :
4127 0 : return( -1 );
4128 : }
4129 :
4130 0 : static void *vc_cvt(char *val, void *def) {
4131 : static char *classes[] = { "StaticGray", "GrayScale", "StaticColor", "PsuedoColor", "TrueColor", "DirectColor", NULL };
4132 0 : int ret = match(classes,val);
4133 0 : if ( ret== -1 ) {
4134 : char *ept;
4135 0 : ret = strtol(val,&ept,10);
4136 0 : if ( ept==val || *ept!='\0' )
4137 0 : return( def );
4138 : }
4139 0 : return( (void *) (intpt) ret );
4140 : }
4141 :
4142 0 : static void *cm_cvt(char *val, void *def) {
4143 : static char *choices[] = { "default", "current", "copy", "private", NULL };
4144 0 : int ret = match(choices,val);
4145 0 : if ( ret== -1 )
4146 0 : return( (void *) -1 );
4147 :
4148 0 : return( (void *) (intpt) (ret-1) );
4149 : }
4150 :
4151 0 : static void GXResourceInit(GXDisplay *gdisp,char *programname) {
4152 : Atom rmatom, type;
4153 : int format, i; unsigned long nitems, bytes_after;
4154 0 : unsigned char *ret = NULL;
4155 : GResStruct res[21];
4156 : int dithertemp; double sizetemp, sizetempcm;
4157 0 : int depth = -1, vc = -1, cm=-1, cmpos;
4158 0 : int tbf = 1;
4159 : #if __Mac
4160 : int mxc = 1; /* Don't leave this on by default. The cmd key uses the same bit as numlock on other systems */
4161 : #else
4162 0 : int mxc = 0;
4163 : #endif
4164 :
4165 0 : rmatom = XInternAtom(gdisp->display,"RESOURCE_MANAGER",true);
4166 0 : if ( rmatom!=None ) {
4167 0 : XGetWindowProperty(gdisp->display,((GXWindow) (gdisp->groot))->w, rmatom, 0,
4168 : 0x7fffff, false, XA_STRING,
4169 : &type, &format, &nitems, &bytes_after, &ret);
4170 0 : if ( type == None )
4171 0 : ret = NULL;
4172 0 : else if ( type!=XA_STRING || format!=8 ) {
4173 0 : XFree(ret);
4174 0 : ret = NULL;
4175 : }
4176 : }
4177 0 : GResourceAddResourceString((char *) ret,programname);
4178 0 : if ( ret!=NULL ) XFree(ret);
4179 :
4180 0 : memset(res,0,sizeof(res));
4181 0 : i = 0;
4182 0 : res[i].resname = "MultiClickTime"; res[i].type = rt_int; res[i].val = &gdisp->bs.double_time; ++i;
4183 0 : res[i].resname = "MultiClickWiggle"; res[i].type = rt_int; res[i].val = &gdisp->bs.double_wiggle; ++i;
4184 0 : res[i].resname = "SelectionNotifyTimeout"; res[i].type = rt_int; res[i].val = &gdisp->SelNotifyTimeout; ++i;
4185 0 : dithertemp = gdisp->do_dithering;
4186 0 : res[i].resname = "DoDithering"; res[i].type = rt_bool; res[i].val = &dithertemp; ++i;
4187 0 : res[i].resname = "ScreenWidthPixels"; res[i].type = rt_int; res[i].val = &gdisp->groot->pos.width; ++i;
4188 0 : res[i].resname = "ScreenHeightPixels"; res[i].type = rt_int; res[i].val = &gdisp->groot->pos.height; ++i;
4189 0 : sizetemp = WidthMMOfScreen(DefaultScreenOfDisplay(gdisp->display))/25.4;
4190 0 : sizetempcm = WidthMMOfScreen(DefaultScreenOfDisplay(gdisp->display))/10;
4191 0 : gdisp->xres = gdisp->groot->pos.width/sizetemp;
4192 0 : res[i].resname = "ScreenWidthInches"; res[i].type = rt_double; res[i].val = &sizetemp; ++i;
4193 0 : cmpos = i;
4194 0 : res[i].resname = "ScreenWidthCentimeters"; res[i].type = rt_double; res[i].val = &sizetempcm; ++i;
4195 0 : res[i].resname = "Depth"; res[i].type = rt_int; res[i].val = &depth; ++i;
4196 0 : res[i].resname = "VisualClass"; res[i].type = rt_string; res[i].val = &vc; res[i].cvt=vc_cvt; ++i;
4197 0 : res[i].resname = "TwoButtonFixup"; res[i].type = rt_bool; res[i].val = &tbf; ++i;
4198 0 : res[i].resname = "MacOSXCmd"; res[i].type = rt_bool; res[i].val = &mxc; ++i;
4199 0 : res[i].resname = "Colormap"; res[i].type = rt_string; res[i].val = &cm; res[i].cvt=cm_cvt; ++i;
4200 0 : res[i].resname = NULL;
4201 0 : GResourceFind(res,NULL);
4202 :
4203 0 : if ( !res[cmpos].found && !res[cmpos-1].found && rint(gdisp->groot->pos.width/sizetemp) == 75 )
4204 0 : gdisp->res = 100; /* X seems to think that if it doesn't know */
4205 : /* the screen width, then 75 dpi is a good guess */
4206 : /* Now-a-days, 100 seems better */
4207 : else
4208 0 : if ( res[cmpos].found && sizetempcm>=1 )
4209 0 : gdisp->res = gdisp->groot->pos.width*2.54/sizetempcm;
4210 0 : else if ( sizetemp>=1 )
4211 0 : gdisp->res = gdisp->groot->pos.width/sizetemp;
4212 0 : gdisp->desired_depth = depth; gdisp->desired_vc = vc;
4213 0 : gdisp->desired_cm = cm;
4214 0 : gdisp->macosx_cmd = mxc;
4215 0 : gdisp->twobmouse_win = tbf;
4216 0 : }
4217 :
4218 0 : static GWindow GXPrinterStartJob(GDisplay *gdisp,void *user_data,GPrinterAttrs *attrs) {
4219 0 : fprintf(stderr, "Invalid call to GPrinterStartJob on X display\n" );
4220 0 : return( NULL );
4221 : }
4222 :
4223 0 : static void GXPrinterNextPage(GWindow w) {
4224 0 : fprintf(stderr, "Invalid call to GPrinterNextPage on X display\n" );
4225 0 : }
4226 :
4227 0 : static int GXPrinterEndJob(GWindow w,int cancel) {
4228 0 : fprintf(stderr, "Invalid call to GPrinterEndJob on X display\n" );
4229 0 : return( false );
4230 : }
4231 :
4232 : static struct displayfuncs xfuncs = {
4233 : GXDrawInit,
4234 : GXDrawTerm,
4235 : GXDrawNativeDisplay,
4236 :
4237 : GXDrawSetDefaultIcon,
4238 :
4239 : GXDrawCreateTopWindow,
4240 : GXDrawCreateSubWindow,
4241 : GXDrawCreatePixmap,
4242 : GXDrawCreateBitmap,
4243 : GXDrawCreateCursor,
4244 : GXDrawDestroyWindow,
4245 : GXDestroyCursor,
4246 : GXNativeWindowExists,
4247 : GXDrawSetZoom,
4248 : GXDrawSetWindowBorder,
4249 : GXDrawSetWindowBackground,
4250 : GXSetDither,
4251 :
4252 : GXDrawReparentWindow,
4253 : GXDrawSetVisible,
4254 : GXDrawMove,
4255 : GXDrawTrueMove,
4256 : GXDrawResize,
4257 : GXDrawMoveResize,
4258 : GXDrawRaise,
4259 : GXDrawRaiseAbove,
4260 : GXDrawIsAbove,
4261 : GXDrawLower,
4262 : GXDrawSetWindowTitles,
4263 : GXDrawSetWindowTitles8,
4264 : GXDrawGetWindowTitle,
4265 : GXDrawGetWindowTitle8,
4266 : GXDrawSetTransientFor,
4267 : GXDrawGetPointerPosition,
4268 : GXDrawGetPointerWindow,
4269 : GXDrawSetCursor,
4270 : GXDrawGetCursor,
4271 : GXDrawGetRedirectWindow,
4272 : GXDrawTranslateCoordinates,
4273 :
4274 : GXDrawBeep,
4275 : GXDrawFlush,
4276 :
4277 : GXDrawPushClip,
4278 : GXDrawPopClip,
4279 :
4280 : GXDrawClear,
4281 : GXDrawDrawLine,
4282 : GXDrawDrawArrow,
4283 : GXDrawDrawRect,
4284 : GXDrawFillRect,
4285 : GXDrawFillRoundRect,
4286 : GXDrawDrawElipse,
4287 : GXDrawFillElipse,
4288 : GXDrawDrawArc,
4289 : GXDrawDrawPoly,
4290 : GXDrawFillPoly,
4291 : GXDrawScroll,
4292 :
4293 : _GXDraw_Image,
4294 : _GXDraw_TileImage,
4295 : _GXDraw_Glyph,
4296 : _GXDraw_ImageMagnified,
4297 : _GXDraw_CopyScreenToImage,
4298 : _GXDraw_Pixmap,
4299 : _GXDraw_TilePixmap,
4300 :
4301 : GXDrawCreateInputContext,
4302 : GXDrawSetGIC,
4303 :
4304 : GXDrawGrabSelection,
4305 : GXDrawAddSelectionType,
4306 : GXDrawRequestSelection,
4307 : GXDrawSelectionHasType,
4308 : GXDrawBindSelection,
4309 : GXDrawSelectionHasOwner,
4310 :
4311 : GXDrawPointerUngrab,
4312 : GXDrawPointerGrab,
4313 : GXDrawRequestExpose,
4314 : GXDrawForceUpdate,
4315 : GXDrawSync,
4316 : GXDrawSkipMouseMoveEvents,
4317 : GXDrawProcessPendingEvents,
4318 : GXDrawProcessWindowEvents,
4319 : GXDrawProcessOneEvent,
4320 : GXDrawEventLoop,
4321 : GXDrawPostEvent,
4322 : GXDrawPostDragEvent,
4323 : GXDrawRequestDeviceEvents,
4324 :
4325 : GXDrawRequestTimer,
4326 : GXDrawCancelTimer,
4327 :
4328 : GXDrawSyncThread,
4329 :
4330 : GXPrinterStartJob,
4331 : GXPrinterNextPage,
4332 : GXPrinterEndJob,
4333 :
4334 : GXDrawFontMetrics,
4335 :
4336 : GXDrawHasCairo,
4337 : GXDrawPathStartNew,
4338 : GXDrawPathClose,
4339 : GXDrawPathMoveTo,
4340 : GXDrawPathLineTo,
4341 : GXDrawPathCurveTo,
4342 : GXDrawPathStroke,
4343 : GXDrawPathFill,
4344 : GXDrawPathFillAndStroke,
4345 :
4346 : GXDrawLayoutInit,
4347 : GXDraw_LayoutDraw,
4348 : GXDraw_LayoutIndexToPos,
4349 : GXDraw_LayoutXYToIndex,
4350 : GXDraw_LayoutExtents,
4351 : GXDraw_LayoutSetWidth,
4352 : GXDraw_LayoutLineCount,
4353 : GXDraw_LayoutLineStart,
4354 : GXDrawPathStartSubNew,
4355 : GXDrawFillRuleSetWinding,
4356 :
4357 : GXDrawPushClipOnly,
4358 : GXDrawClipPreserve
4359 : };
4360 :
4361 0 : static void GDrawInitXKB(GXDisplay *gdisp) {
4362 : #ifdef _NO_XKB
4363 : gdisp->has_xkb = false;
4364 : #else
4365 0 : int lib_major = XkbMajorVersion, lib_minor = XkbMinorVersion;
4366 :
4367 0 : gdisp->has_xkb = false;
4368 0 : if ( XkbLibraryVersion(&lib_major, &lib_minor))
4369 0 : gdisp->has_xkb = XkbQueryExtension(gdisp->display,
4370 : &gdisp->xkb.opcode,&gdisp->xkb.event,&gdisp->xkb.error,
4371 : &lib_major,&lib_minor);
4372 0 : if ( gdisp->has_xkb ) {
4373 0 : int mask = XkbNewKeyboardNotifyMask | XkbMapNotifyMask;
4374 0 : XkbSelectEvents(gdisp->display,XkbUseCoreKbd,mask,mask);
4375 : }
4376 : #endif
4377 0 : }
4378 :
4379 0 : void _GXDraw_DestroyDisplay(GDisplay * gdisp) {
4380 0 : GXDisplay* gdispc = (GXDisplay*)(gdisp);
4381 0 : if (gdispc->grey_stipple != BadAlloc && gdispc->grey_stipple != BadDrawable && gdispc->grey_stipple != BadValue) {
4382 0 : XFreePixmap(gdispc->display, gdispc->grey_stipple); gdispc->grey_stipple = BadAlloc;
4383 : }
4384 0 : if (gdispc->fence_stipple != BadAlloc && gdispc->fence_stipple != BadDrawable && gdispc->fence_stipple != BadValue) {
4385 0 : XFreePixmap(gdispc->display, gdispc->fence_stipple); gdispc->fence_stipple = BadAlloc;
4386 : }
4387 0 : if (gdispc->pango_context != NULL) {
4388 0 : g_object_unref(gdispc->pango_context); gdispc->pango_context = NULL;
4389 : }
4390 0 : if (gdispc->groot != NULL) {
4391 0 : if (gdispc->groot->ggc != NULL) { free(gdispc->groot->ggc); gdispc->groot->ggc = NULL; }
4392 0 : free(gdispc->groot); gdispc->groot = NULL;
4393 : }
4394 0 : if (gdispc->im != NULL) { XCloseIM(gdispc->im); gdispc->im = NULL; }
4395 0 : if (gdispc->display != NULL) { XCloseDisplay(gdispc->display); gdispc->display = NULL; }
4396 0 : return;
4397 : }
4398 :
4399 0 : GDisplay *_GXDraw_CreateDisplay(char *displayname,char *programname) {
4400 : GXDisplay *gdisp;
4401 : Display *display;
4402 : GXWindow groot;
4403 : Window focus;
4404 : int revert;
4405 : static unsigned char grey_init[8] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
4406 : static unsigned char fence_init[8] = { 0x55, 0x22, 0x55, 0x88, 0x55, 0x22, 0x55, 0x88};
4407 : #ifdef HAVE_PTHREAD_H
4408 : static pthread_mutex_t defmutex = PTHREAD_MUTEX_INITIALIZER;
4409 : #endif
4410 :
4411 0 : display = XOpenDisplay(displayname);
4412 0 : if ( display==NULL )
4413 0 : return( NULL );
4414 :
4415 0 : setlocale(LC_ALL,"");
4416 0 : XSupportsLocale();
4417 0 : XSetLocaleModifiers("");
4418 :
4419 0 : gdisp = calloc(1,sizeof(GXDisplay));
4420 0 : if ( gdisp==NULL ) {
4421 0 : XCloseDisplay(display);
4422 0 : return( NULL );
4423 : }
4424 :
4425 0 : gdisp->funcs = &xfuncs;
4426 0 : gdisp->display = display;
4427 0 : gdisp->screen = DefaultScreen(display);
4428 0 : gdisp->root = RootWindow(display,gdisp->screen);
4429 0 : gdisp->virtualRoot = BadAlloc;
4430 0 : gdisp->res = (25.4*WidthOfScreen(DefaultScreenOfDisplay(display)))/
4431 0 : WidthMMOfScreen(DefaultScreenOfDisplay(display));
4432 0 : gdisp->scale_screen_by = 1;
4433 0 : gdisp->mykey_keysym = XK_F12;
4434 0 : gdisp->mykey_mask = 0;
4435 0 : gdisp->do_dithering = true;
4436 0 : gdisp->desired_vc = gdisp->desired_depth = -1;
4437 :
4438 0 : gdisp->gcstate[0].gc = NULL;
4439 0 : gdisp->gcstate[0].fore_col = 0x1000000; /* Doesn't match any colour */
4440 0 : gdisp->gcstate[0].back_col = 0x1000000; /* Doesn't match any colour */
4441 0 : gdisp->gcstate[0].clip.x = gdisp->gcstate[0].clip.y = 0;
4442 0 : gdisp->gcstate[0].clip.width = gdisp->gcstate[0].clip.height = 0x7fff;
4443 0 : gdisp->gcstate[0].func = df_copy;
4444 :
4445 0 : gdisp->gcstate[1].fore_col = 0x1000000; /* Doesn't match any colour */
4446 0 : gdisp->gcstate[1].back_col = 0x1000000; /* Doesn't match any colour */
4447 0 : gdisp->gcstate[1].clip.x = gdisp->gcstate[1].clip.y = 0;
4448 0 : gdisp->gcstate[1].clip.width = gdisp->gcstate[1].clip.height = 0x7fff;
4449 0 : gdisp->gcstate[1].func = df_copy;
4450 :
4451 0 : gdisp->bs.double_time = 200;
4452 0 : gdisp->bs.double_wiggle = 3;
4453 0 : gdisp->SelNotifyTimeout = 20; /* wait 20 seconds for a response to a selection request */
4454 :
4455 0 : while ( gdisp->mycontext==0 )
4456 0 : gdisp->mycontext = XUniqueContext();
4457 :
4458 0 : gdisp->grey_stipple = XCreatePixmapFromBitmapData(display,gdisp->root,(char *) grey_init,8,8,1,0,1);
4459 0 : gdisp->fence_stipple = XCreatePixmapFromBitmapData(display,gdisp->root,(char *) fence_init,8,8,1,0,1);
4460 :
4461 0 : XGetInputFocus(display,&focus,&revert);
4462 0 : if ( focus==PointerRoot )
4463 0 : gdisp->focusfollowsmouse = true;
4464 :
4465 0 : gdisp->groot = calloc(1,sizeof(struct gxwindow));
4466 0 : groot = (GXWindow)(gdisp->groot);
4467 0 : groot->ggc = _GXDraw_NewGGC();
4468 0 : groot->display = gdisp;
4469 0 : groot->w = gdisp->root;
4470 0 : groot->pos.width = XDisplayWidth(display,gdisp->screen);
4471 0 : groot->pos.height = XDisplayHeight(display,gdisp->screen);
4472 0 : groot->is_toplevel = true;
4473 0 : groot->is_visible = true;
4474 :
4475 0 : GXResourceInit(gdisp,programname);
4476 :
4477 0 : gdisp->bs.double_time = GResourceFindInt( "DoubleClickTime", gdisp->bs.double_time );
4478 0 : gdisp->def_background = GResourceFindColor( "Background", COLOR_CREATE(0xf5,0xff,0xfa));
4479 0 : gdisp->def_foreground = GResourceFindColor( "Foreground", COLOR_CREATE(0x00,0x00,0x00));
4480 0 : if ( GResourceFindBool("Synchronize", false ))
4481 0 : XSynchronize(gdisp->display,true);
4482 :
4483 : #ifdef X_HAVE_UTF8_STRING /* Don't even try without this. I don't want to have to guess encodings myself... */
4484 : /* X Input method initialization */
4485 0 : XSetLocaleModifiers(""); // As it turns out, we can't free this here.
4486 0 : gdisp->im = XOpenIM(display, XrmGetDatabase(display),
4487 : GResourceProgramName, GResourceProgramName);
4488 : /* The only reason this seems to fail is if XMODIFIERS contains an @im */
4489 : /* which points to something that isn't running. If XMODIFIERS is not */
4490 : /* defined we get some kind of built-in default method. If it doesn't */
4491 : /* recognize the locale we still get something */
4492 : /* If it does fail, then fall back on the old fashioned stuff */
4493 : #endif
4494 :
4495 0 : (gdisp->funcs->init)((GDisplay *) gdisp);
4496 0 : gdisp->top_window_count = 0;
4497 0 : gdisp->selinfo[sn_primary].sel_atom = XA_PRIMARY;
4498 0 : gdisp->selinfo[sn_clipboard].sel_atom = XInternAtom(display,"CLIPBOARD",False);
4499 0 : gdisp->selinfo[sn_drag_and_drop].sel_atom = XInternAtom(display,"DRAG_AND_DROP",False);
4500 0 : gdisp->selinfo[sn_user1].sel_atom = XA_PRIMARY;
4501 0 : gdisp->selinfo[sn_user2].sel_atom = XA_PRIMARY;
4502 :
4503 0 : gdisp->xthread.sync_sock = -1;
4504 : #ifdef HAVE_PTHREAD_H
4505 0 : gdisp->xthread.sync_mutex = defmutex;
4506 0 : gdisp->xthread.things_to_do = NULL;
4507 : #endif
4508 0 : XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
4509 0 : _GDraw_InitError((GDisplay *) gdisp);
4510 :
4511 : #ifdef _WACOM_DRV_BROKEN
4512 : _GXDraw_Wacom_Init(gdisp);
4513 : #endif
4514 :
4515 0 : GDrawInitXKB(gdisp);
4516 :
4517 0 : return( (GDisplay *) gdisp);
4518 : }
4519 :
4520 0 : void _XSyncScreen() {
4521 0 : XSync(((GXDisplay *) screen_display)->display,false);
4522 0 : }
4523 :
4524 : /* map GK_ keys to X keys */
4525 : /* Assumes most are mapped 1-1, see gkeysym.h */
4526 : /* abort on unimplemented translations */
4527 0 : int GDrawKeyToXK(int keysym) {
4528 : switch( keysym ) {
4529 : default:
4530 0 : if ( keysym==' ' ||
4531 0 : (keysym>='0' && keysym<='9') ||
4532 0 : (keysym>='A' && keysym<='Z') ||
4533 0 : (keysym>='a' && keysym<='z') )
4534 0 : return( keysym );
4535 : }
4536 0 : abort();
4537 : return( 0 );
4538 : }
4539 :
4540 0 : int GDrawKeyState(int keysym) {
4541 : char key_map_stat[32];
4542 0 : Display *xdisplay = ((GXDisplay *)screen_display)->display;
4543 : KeyCode code;
4544 :
4545 0 : XQueryKeymap(xdisplay, key_map_stat);
4546 :
4547 0 : code = XKeysymToKeycode(xdisplay, GDrawKeyToXK(keysym));
4548 0 : if ( !code ) {
4549 0 : abort();
4550 : return 0;
4551 : }
4552 0 : return ((key_map_stat[code >> 3] >> (code & 7)) & 1);
4553 : }
4554 :
4555 : #else /* NO X */
4556 :
4557 : GDisplay *_GXDraw_CreateDisplay(char *displayname,char *programname) {
4558 : fprintf( stderr, "This program was not compiled with X11, and cannot open the display\n" );
4559 : exit(1);
4560 : }
4561 :
4562 : void _XSyncScreen() {
4563 : }
4564 : #endif
4565 :
4566 :
|