"Fossies" - the Fresh Open Source Software Archive 
Member "xearth-1.1/x11.c" (7 Nov 1999, 42464 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * x11.c
3 * kirk johnson
4 * july 1993
5 *
6 * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
7 *
8 * Parts of the source code (as marked) are:
9 * Copyright (C) 1989, 1990, 1991 by Jim Frost
10 * Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
11 *
12 * Permission to use, copy, modify and freely distribute xearth for
13 * non-commercial and not-for-profit purposes is hereby granted
14 * without fee, provided that both the above copyright notice and this
15 * permission notice appear in all copies and in supporting
16 * documentation.
17 *
18 * Unisys Corporation holds worldwide patent rights on the Lempel Zev
19 * Welch (LZW) compression technique employed in the CompuServe GIF
20 * image file format as well as in other formats. Unisys has made it
21 * clear, however, that it does not require licensing or fees to be
22 * paid for freely distributed, non-commercial applications (such as
23 * xearth) that employ LZW/GIF technology. Those wishing further
24 * information about licensing the LZW patent should contact Unisys
25 * directly at (lzw_info@unisys.com) or by writing to
26 *
27 * Unisys Corporation
28 * Welch Licensing Department
29 * M/S-C1SW19
30 * P.O. Box 500
31 * Blue Bell, PA 19424
32 *
33 * The author makes no representations about the suitability of this
34 * software for any purpose. It is provided "as is" without express or
35 * implied warranty.
36 *
37 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
40 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
43 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 */
45
46 #include "xearth.h"
47 #include <X11/Xlib.h>
48 #include <X11/Intrinsic.h>
49 #include <X11/Xatom.h>
50 #include <X11/Xproto.h>
51 #include <signal.h>
52 #include "kljcpyrt.h"
53
54 #define RETAIN_PROP_NAME "_XSETROOT_ID"
55
56 #define MONO_1 (0)
57 #define MONO_8 (1)
58 #define COLOR_8 (2)
59 #define MONO_16 (3)
60 #define COLOR_16 (4)
61 #define MONO_32 (5)
62 #define COLOR_32 (6)
63
64 #define LABEL_LEFT_FLUSH (1<<0)
65 #define LABEL_TOP_FLUSH (1<<1)
66
67 static void init_x_general _P((int, char *[]));
68 static void process_opts _P((void));
69 static void init_x_colors _P((void));
70 static void init_x_pixmaps _P((void));
71 static void init_x_root_window _P((void));
72 static void init_x_separate_window _P((void));
73 static void wakeup _P((int));
74 static int get_bits_per_pixel _P((int));
75 static XFontStruct *load_x_font _P((Display *, char *));
76 static void get_proj_type _P((void));
77 static void get_viewing_position _P((void));
78 static void get_sun_position _P((void));
79 static void get_rotation _P((void));
80 static void get_size _P((void));
81 static void get_shift _P((void));
82 static void get_labelpos _P((void));
83 static void get_geometry _P((void));
84 static void x11_setup _P((void));
85 static void pack_mono_1 _P((u16or32 *, u_char *));
86 static void pack_8 _P((u16or32 *, Pixel *, u_char *));
87 static void pack_16 _P((u16or32 *, Pixel *, u_char *));
88 static void pack_24 _P((u16or32 *, Pixel *, u_char *));
89 static void pack_32 _P((u16or32 *, Pixel *, u_char *));
90 static int x11_row _P((u_char *));
91 static void x11_cleanup _P((void));
92 static void draw_label _P((Display *));
93 static void mark_location _P((Display *, MarkerInfo *));
94 static void draw_outlined_string _P((Display *, Pixmap, Pixel, Pixel,
95 int, int, char *, int));
96 static Window GetVRoot _P((Display *));
97 static void updateProperty _P((Display *, Window, const char *, Atom,
98 int, int, int));
99 static void preserveResource _P((Display *, Window));
100 static void freePrevious _P((Display *, Window));
101 static int xkill_handler _P((Display *, XErrorEvent *));
102
103 static int bpp;
104 static u16or32 *dith;
105 static u_char *xbuf;
106 static int idx;
107 static XImage *xim;
108 static Pixmap work_pix;
109 static Pixmap disp_pix;
110 static int (*orig_error_handler) _P((Display *, XErrorEvent *));
111
112 #ifdef DEBUG
113 static int frame = 0;
114 #endif /* DEBUG */
115
116 char *progclass;
117 Widget app_shell;
118 XtAppContext app_context;
119 XrmDatabase db;
120
121 Display *dsply; /* display connection */
122 int scrn; /* screen number */
123 Window root; /* root window */
124 Window xearth_window; /* xearth window */
125 Colormap cmap; /* default colormap */
126 Visual *visl; /* default visual */
127 int dpth; /* default depth */
128 Pixel white; /* white pixel */
129 Pixel black; /* black pixel */
130 Pixel hlight; /* highlight pixel */
131 GC gc; /* graphics context */
132 Pixel *pels; /* allocated colors */
133 char *font_name; /* text font name */
134 XFontStruct *font; /* basic text font */
135
136 static int do_once; /* only render once? */
137 static int mono; /* render in mono? */
138 static int use_root; /* render into root? */
139 static int window_pos_flag; /* spec'ed window pos? */
140 static int window_xvalue; /* window x position */
141 static int window_yvalue; /* window y position */
142 static int window_gravity; /* window gravity */
143
144 static int label_xvalue; /* label x position */
145 static int label_yvalue; /* label y position */
146 static int label_orient; /* label orientation */
147
148
149 static char *defaults[] =
150 {
151 "*proj: orthographic",
152 "*pos: sunrel 0 0",
153 "*rot: 0",
154 "*shift: 0 0",
155 "*mag: 1.0",
156 "*shade: on",
157 "*label: off",
158 "*labelpos: -5-5",
159 "*markers: on",
160 "*markerfile: built-in",
161 "*wait: 300",
162 "*timewarp: 1",
163 "*day: 100",
164 "*night: 5",
165 "*term: 1",
166 "*twopix: on",
167 "*ncolors: 64",
168 "*fork: off",
169 "*once: off",
170 "*nice: 0",
171 "*stars: on",
172 "*starfreq: 0.002",
173 "*bigstars: 0",
174 "*grid: off",
175 "*grid1: 6",
176 "*grid2: 15",
177 "*gamma: 1.0",
178 "*font: variable",
179 "*title: xearth",
180 "*iconname: xearth",
181 NULL
182 };
183
184 static XrmOptionDescRec options[] =
185 {
186 { "-proj", ".proj", XrmoptionSepArg, 0 },
187 { "-pos", ".pos", XrmoptionSepArg, 0 },
188 { "-rot", ".rot", XrmoptionSepArg, 0 },
189 { "-mag", ".mag", XrmoptionSepArg, 0 },
190 { "-shade", ".shade", XrmoptionNoArg, "on" },
191 { "-noshade", ".shade", XrmoptionNoArg, "off" },
192 { "-sunpos", ".sunpos", XrmoptionSepArg, 0 },
193 { "-size", ".size", XrmoptionSepArg, 0 },
194 { "-shift", ".shift", XrmoptionSepArg, 0 },
195 { "-label", ".label", XrmoptionNoArg, "on" },
196 { "-nolabel", ".label", XrmoptionNoArg, "off" },
197 { "-labelpos", ".labelpos", XrmoptionSepArg, 0 },
198 { "-markers", ".markers", XrmoptionNoArg, "on" },
199 { "-nomarkers", ".markers", XrmoptionNoArg, "off" },
200 { "-markerfile", ".markerfile", XrmoptionSepArg, 0 },
201 { "-showmarkers", ".showmarkers", XrmoptionNoArg, "on" },
202 { "-wait", ".wait", XrmoptionSepArg, 0 },
203 { "-timewarp", ".timewarp", XrmoptionSepArg, 0 },
204 { "-day", ".day", XrmoptionSepArg, 0 },
205 { "-night", ".night", XrmoptionSepArg, 0 },
206 { "-term", ".term", XrmoptionSepArg, 0 },
207 { "-onepix", ".twopix", XrmoptionNoArg, "off" },
208 { "-twopix", ".twopix", XrmoptionNoArg, "on" },
209 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
210 { "-fork", ".fork", XrmoptionNoArg, "on" },
211 { "-nofork", ".fork", XrmoptionNoArg, "off" },
212 { "-once", ".once", XrmoptionNoArg, "on" },
213 { "-noonce", ".once", XrmoptionNoArg, "off" },
214 { "-nice", ".nice", XrmoptionSepArg, 0 },
215 { "-version", ".version", XrmoptionNoArg, "on" },
216 { "-stars", ".stars", XrmoptionNoArg, "on" },
217 { "-nostars", ".stars", XrmoptionNoArg, "off" },
218 { "-starfreq", ".starfreq", XrmoptionSepArg, 0 },
219 { "-bigstars", ".bigstars", XrmoptionSepArg, 0 },
220 { "-grid", ".grid", XrmoptionNoArg, "on" },
221 { "-nogrid", ".grid", XrmoptionNoArg, "off" },
222 { "-grid1", ".grid1", XrmoptionSepArg, 0 },
223 { "-grid2", ".grid2", XrmoptionSepArg, 0 },
224 { "-time", ".time", XrmoptionSepArg, 0 },
225 { "-gamma", ".gamma", XrmoptionSepArg, 0 },
226 { "-font", ".font", XrmoptionSepArg, 0 },
227 { "-mono", ".mono", XrmoptionNoArg, "on" },
228 { "-nomono", ".mono", XrmoptionNoArg, "off" },
229 { "-root", ".root", XrmoptionNoArg, "on" },
230 { "-noroot", ".root", XrmoptionNoArg, "off" },
231 { "-geometry", ".geometry", XrmoptionSepArg, 0 },
232 { "-title", ".title", XrmoptionSepArg, 0 },
233 { "-iconname", ".iconname", XrmoptionSepArg, 0 },
234 };
235
236
237 void command_line_x(argc, argv)
238 int argc;
239 char *argv[];
240 {
241 init_x_general(argc, argv);
242 process_opts();
243
244 init_x_colors();
245 init_x_pixmaps();
246 font = load_x_font(dsply, font_name);
247
248 if (use_root)
249 init_x_root_window();
250 else
251 init_x_separate_window();
252 }
253
254
255 static void init_x_general(argc, argv)
256 int argc;
257 char *argv[];
258 {
259 progname = argv[0];
260 progclass = "XEarth";
261 app_shell = XtAppInitialize(&app_context, progclass,
262 options, XtNumber(options),
263 &argc, argv, defaults, 0, 0);
264 if (argc > 1) usage(NULL);
265
266 dsply = XtDisplay(app_shell);
267 scrn = DefaultScreen(dsply);
268 db = XtDatabase(dsply);
269
270 XtGetApplicationNameAndClass(dsply, &progname, &progclass);
271
272 root = RootWindow(dsply, scrn);
273 cmap = DefaultColormap(dsply, scrn);
274 visl = DefaultVisual(dsply, scrn);
275 dpth = DefaultDepth(dsply, scrn);
276 wdth = DisplayWidth(dsply, scrn);
277 hght = DisplayHeight(dsply, scrn);
278 white = WhitePixel(dsply, scrn);
279 black = BlackPixel(dsply, scrn);
280 gc = XCreateGC(dsply, root, 0, NULL);
281 hlight = white;
282 XSetState(dsply, gc, white, black, GXcopy, AllPlanes);
283
284 bpp = get_bits_per_pixel(dpth);
285 }
286
287
288 static void process_opts()
289 {
290 if (get_boolean_resource("version", "Version"))
291 version_info(1);
292
293 if (get_boolean_resource("showmarkers", "Showmarkers"))
294 {
295 markerfile = get_string_resource("markerfile", "Markerfile");
296 show_marker_info(markerfile);
297 }
298
299 /* process complex resources
300 */
301 get_proj_type();
302 get_viewing_position();
303 get_sun_position();
304 get_size();
305 get_shift();
306 get_labelpos();
307 get_rotation();
308 get_geometry();
309
310 /* process simple resources
311 */
312 view_mag = get_float_resource("mag", "Mag");
313 do_shade = get_boolean_resource("shade", "Shade");
314 do_label = get_boolean_resource("label", "Label");
315 do_markers = get_boolean_resource("markers", "Markers");
316 markerfile = get_string_resource("markerfile", "Markerfile");
317 wait_time = get_integer_resource("wait", "Wait");
318 time_warp = get_float_resource("timewarp", "Timewarp");
319 day = get_integer_resource("day", "Day");
320 night = get_integer_resource("night", "Night");
321 terminator = get_integer_resource("term", "Term");
322 use_two_pixmaps = get_boolean_resource("twopix", "Twopix");
323 num_colors = get_integer_resource("ncolors", "Ncolors");
324 do_fork = get_boolean_resource("fork", "Fork");
325 do_once = get_boolean_resource("once", "Once");
326 priority = get_integer_resource("nice", "Nice");
327 do_stars = get_boolean_resource("stars", "Stars");
328 star_freq = get_float_resource("starfreq", "Starfreq");
329 big_stars = get_integer_resource("bigstars", "Bigstars");
330 do_grid = get_boolean_resource("grid", "Grid");
331 grid_big = get_integer_resource("grid1", "Grid1");
332 grid_small = get_integer_resource("grid2", "Grid2");
333 fixed_time = get_integer_resource("time", "Time");
334 xgamma = get_float_resource("gamma", "Gamma");
335 font_name = get_string_resource("font", "Font");
336 mono = get_boolean_resource("mono", "Mono");
337
338 /* various sanity checks on simple resources
339 */
340 if ((view_rot < -180) || (view_rot > 360))
341 fatal("viewing rotation must be between -180 and 360");
342 if (view_mag <= 0)
343 fatal("viewing magnification must be positive");
344 if (wait_time < 0)
345 fatal("arg to -wait must be non-negative");
346 if (time_warp <= 0)
347 fatal("arg to -timewarp must be positive");
348 if ((num_colors < 3) || (num_colors > 1024))
349 fatal("arg to -ncolors must be between 3 and 1024");
350 if ((star_freq < 0) || (star_freq > 1))
351 fatal("arg to -starfreq must be between 0 and 1");
352 if ((big_stars < 0) || (big_stars > 100))
353 fatal("arg to -bigstars must be between 0 and 100");
354 if (grid_big <= 0)
355 fatal("arg to -grid1 must be positive");
356 if (grid_small <= 0)
357 fatal("arg to -grid2 must be positive");
358 if ((day > 100) || (day < 0))
359 fatal("arg to -day must be between 0 and 100");
360 if ((night > 100) || (night < 0))
361 fatal("arg to -night must be between 0 and 100");
362 if ((terminator > 100) || (terminator < 0))
363 fatal("arg to -term must be between 0 and 100");
364 if (xgamma <= 0)
365 fatal("arg to -gamma must be positive");
366
367 /* if we're only rendering once, make sure we don't
368 * waste memory by allocating two pixmaps
369 */
370 if (do_once)
371 use_two_pixmaps = 0;
372
373 /* if we're working with a one-bit display, force -mono mode
374 */
375 if (dpth == 1)
376 mono = 1;
377 }
378
379
380 static void init_x_colors()
381 {
382 int i;
383 XColor xc, junk;
384 u_char *tmp;
385 double inv_xgamma;
386
387 if (mono)
388 {
389 mono_dither_setup();
390 pels = (Pixel *) malloc((unsigned) sizeof(Pixel) * 2);
391 assert(pels != NULL);
392 pels[0] = black;
393 pels[1] = white;
394 }
395 else
396 {
397 if (XAllocNamedColor(dsply, cmap, "red", &xc, &junk) != 0)
398 hlight = xc.pixel;
399
400 dither_setup(num_colors);
401 pels = (Pixel *) malloc((unsigned) sizeof(Pixel) * dither_ncolors);
402 assert(pels != NULL);
403
404 tmp = dither_colormap;
405 inv_xgamma = 1.0 / xgamma;
406 for (i=0; i<dither_ncolors; i++)
407 {
408 xc.red = ((1<<16)-1) * pow(((double) tmp[0] / 255), inv_xgamma);
409 xc.green = ((1<<16)-1) * pow(((double) tmp[1] / 255), inv_xgamma);
410 xc.blue = ((1<<16)-1) * pow(((double) tmp[2] / 255), inv_xgamma);
411
412 if (XAllocColor(dsply, cmap, &xc) == 0)
413 fatal("unable to allocate enough colors");
414 pels[i] = xc.pixel;
415
416 tmp += 3;
417 }
418 }
419 }
420
421
422 static void init_x_pixmaps()
423 {
424 work_pix = XCreatePixmap(dsply, root, (unsigned) wdth,
425 (unsigned) hght, (unsigned) dpth);
426 if (use_two_pixmaps)
427 disp_pix = XCreatePixmap(dsply, root, (unsigned) wdth,
428 (unsigned) hght, (unsigned) dpth);
429 }
430
431
432 static void init_x_root_window()
433 {
434 xearth_window = GetVRoot(dsply);
435
436 /* try to free any resources retained by any previous clients that
437 * scribbled in the root window (also deletes the _XSETROOT_ID
438 * property from the root window, if it was there)
439 */
440 freePrevious(dsply, xearth_window);
441
442 /* 18 may 1994
443 *
444 * setting the _XSETROOT_ID property is dangerous if xearth might be
445 * killed by other means (e.g., from the shell), because some other
446 * client might allocate a resource with the same resource ID that
447 * xearth had stored in the _XSETROOT_ID property, so subsequent
448 * attempts to free any resources retained by a client that had
449 * scribbled on the root window via XKillClient() may end up killing
450 * the wrong client.
451 *
452 * this possibility could be eliminated by setting the closedown
453 * mode for the display connection to RetainPermanent, but this
454 * seemed to be causing core dumps in an R5pl26 server -- i submitted
455 * a bug report to the X consortium about this. i _think_ the server
456 * core dumps were related to the fact that xearth can sleep for a
457 * _long_ time between protocol requests, perhaps longer than it
458 * takes for one server to die (e.g., when somebody logs out) and a
459 * new server to be restarted, and somehow exercising the display
460 * connection from the old server was causing the new one to crash?
461 *
462 * possible fixes:
463 *
464 * - replace the big sleep() with a loop that interleaves sleep(1)
465 * and, say, calls to XNoOp() to test the display connection;
466 * presumably one second is short enough to avoid the possibility
467 * of one server dying and another restarting before a call to
468 * XNoOp() catches the fact that the connection to the old server
469 * died.
470 *
471 * - use RetainTemporary mode instead of RetainPermanent? need to
472 * check the X documentation and figure out exactly what this
473 * would mean.
474 *
475 * it would be nice to install the _XSETROOT_ID property so xearth
476 * interoperates gracefully with other things that try to scribble
477 * on the root window (e.g., xsetroot, xloadimage, xv), but until i
478 * figure out a fix to the problems described above, probably best
479 * not to bother.
480 */
481 /* preserveResource(dsply, xearth_window); */
482 }
483
484
485 static void init_x_separate_window()
486 {
487 XSizeHints *xsh;
488 char *title;
489 char *iname;
490
491 xearth_window = XCreateSimpleWindow(dsply,
492 root,
493 window_xvalue,
494 window_yvalue,
495 wdth,
496 hght,
497 DefaultBorderWidth,
498 white,
499 black);
500
501 xsh = XAllocSizeHints();
502 xsh->width = wdth;
503 xsh->height = hght;
504 xsh->min_width = wdth;
505 xsh->min_height = hght;
506 xsh->max_width = wdth;
507 xsh->max_height = hght;
508 xsh->base_width = wdth;
509 xsh->base_height = hght;
510 xsh->flags = (PSize|PMinSize|PMaxSize|PBaseSize);
511
512 if (window_pos_flag)
513 {
514 xsh->x = window_xvalue;
515 xsh->y = window_yvalue;
516 xsh->win_gravity = window_gravity;
517 xsh->flags |= (USPosition|PWinGravity);
518 }
519
520 title = get_string_resource("title", "Title");
521 iname = get_string_resource("iconname", "Iconname");
522 if ((title == NULL) || (iname == NULL))
523 fatal("title or iconname is NULL (this shouldn't happen)");
524
525 XSetWMNormalHints(dsply, xearth_window, xsh);
526 XStoreName(dsply, xearth_window, title);
527 XSetIconName(dsply, xearth_window, iname);
528
529 XMapRaised(dsply, xearth_window);
530 XSync(dsply, False);
531
532 XFree((char *) xsh);
533 free(title);
534 free(iname);
535 }
536
537
538 void x11_output()
539 {
540 while (1)
541 {
542 compute_positions();
543
544 /* if we were really clever, we'd only
545 * do this if the position has changed
546 */
547 scan_map();
548 do_dots();
549
550 /* for now, go ahead and reload the marker info every time
551 * we redraw, but maybe change this in the future?
552 */
553 load_marker_info(markerfile);
554
555 x11_setup();
556 render(x11_row);
557 x11_cleanup();
558
559 if (do_once)
560 {
561 if (use_root)
562 preserveResource(dsply, xearth_window);
563 XSync(dsply, True);
564 return;
565 }
566
567 /* schedule an alarm for wait_time seconds and pause. alarm() and
568 * pause() are used instead of sleep so that if xearth is sent a
569 * SIGSTOP and SIGCONT separated by more than wait_time, it will
570 * refresh the screen as soon as the SIGCONT is received. this
571 * facilitates graceful interaction with things like FvwmBacker.
572 * (thanks to Richard Everson for passing this along.)
573 */
574 signal(SIGALRM, wakeup);
575 signal(SIGCONT, wakeup);
576 if (wait_time > 0)
577 {
578 /* only do the alarm()/pause() stuff if wait_time is non-zero,
579 * else alarm() will not behave as desired.
580 */
581 alarm(wait_time);
582 pause();
583 }
584 }
585 }
586
587
588 /* no-op signal handler for catching SIGALRM and SIGCONT
589 * (used to wake up from pause() system call)
590 */
591 static void wakeup(int junk)
592 {
593 /* nothing */
594 }
595
596
597 /* determine bits_per_pixel value for pixmaps of specified depth
598 */
599 static int get_bits_per_pixel(depth)
600 int depth;
601 {
602 int i;
603 int cnt;
604 XPixmapFormatValues *pmf;
605 int rslt;
606
607 pmf = XListPixmapFormats(dsply, &cnt);
608 if (pmf == NULL)
609 fatal("unable to get pixmap format list");
610
611 rslt = 0;
612 for (i=0; i<cnt; i++)
613 if (pmf[i].depth == depth)
614 {
615 rslt = pmf[i].bits_per_pixel;
616 break;
617 }
618
619 if (rslt == 0)
620 fatal("unable to determine pixmap format");
621
622 XFree(pmf);
623
624 return rslt;
625 }
626
627
628 static XFontStruct *load_x_font(dpy, fontname)
629 Display *dpy;
630 char *fontname;
631 {
632 XFontStruct *rslt;
633
634 rslt = XLoadQueryFont(dpy, fontname);
635 if (rslt == NULL)
636 {
637 rslt = XQueryFont(dpy, XGContextFromGC(gc));
638 if (rslt == NULL)
639 fatal("completely unable to load fonts");
640 else
641 warning("unable to load font, reverting to default");
642 }
643 else
644 {
645 XSetFont(dpy, gc, rslt->fid);
646 }
647
648 return rslt;
649 }
650
651
652 /* fetch and decode 'proj' resource (projection type)
653 */
654 static void get_proj_type()
655 {
656 char *res;
657
658 res = get_string_resource("proj", "Proj");
659 if (res != NULL)
660 {
661 decode_proj_type(res);
662 free(res);
663 }
664 }
665
666
667 /* fetch and decode 'pos' resource (viewing position specifier)
668 */
669 static void get_viewing_position()
670 {
671 char *res;
672
673 res = get_string_resource("pos", "Pos");
674 if (res != NULL)
675 {
676 decode_viewing_pos(res);
677 free(res);
678 }
679 }
680
681
682 /* fetch and decode 'sunpos' resource (sun position specifier)
683 */
684 static void get_sun_position()
685 {
686 char *res;
687
688 res = get_string_resource("sunpos", "Sunpos");
689 if (res != NULL)
690 {
691 decode_sun_pos(res);
692 free(res);
693 }
694 }
695
696
697 /* fetch and decode 'rot' resource (rotation specifier)
698 */
699 static void get_rotation()
700 {
701 char *res;
702
703 res = get_string_resource("rot", "Rotation");
704 if (res != NULL)
705 {
706 decode_rotation(res);
707 free(res);
708 }
709 }
710
711
712 /* fetch and decode 'size' resource (size specifier)
713 */
714 static void get_size()
715 {
716 char *res;
717
718 res = get_string_resource("size", "Size");
719 if (res != NULL)
720 {
721 decode_size(res);
722 free(res);
723 }
724 }
725
726
727 /* fetch and decode 'shift' resource (shift specifier)
728 */
729 static void get_shift()
730 {
731 char *res;
732
733 res = get_string_resource("shift", "Shift");
734 if (res != NULL)
735 {
736 decode_shift(res);
737 free(res);
738 }
739 }
740
741
742 /* fetch and decode 'labelpos' resource (label position)
743 */
744 static void get_labelpos()
745 {
746 char *res;
747 int mask;
748 int x, y;
749 unsigned w, h;
750
751 /* it's somewhat brute-force ugly to hard-code these here,
752 * duplicating information contained in defaults[], but such it is.
753 */
754 label_orient = 0;
755 label_xvalue = wdth - 5;
756 label_yvalue = hght - 5;
757
758 res = get_string_resource("labelpos", "Labelpos");
759 if (res != NULL)
760 {
761 mask = XParseGeometry(res, &x, &y, &w, &h);
762
763 if (mask & (WidthValue | HeightValue))
764 warning("width and height ignored in label position");
765
766 if ((mask & XValue) && (mask & YValue))
767 {
768 label_xvalue = x;
769 label_yvalue = y;
770
771 if ((mask & XNegative) == 0)
772 label_orient |= LABEL_LEFT_FLUSH;
773
774 if ((mask & YNegative) == 0)
775 label_orient |= LABEL_TOP_FLUSH;
776 }
777 else
778 {
779 warning("label position must specify x and y offsets");
780 }
781
782 free(res);
783 }
784 }
785
786
787 /* fetch and decode 'root' and 'geometry' resource (whether to render
788 * into root or separate window; if separate window, position of that
789 * window) [this is pretty ugly code, but it gets the job done ...]
790 */
791 static void get_geometry()
792 {
793 int check_geom;
794 char *res;
795 int mask;
796 int x, y;
797 int w, h;
798
799 res = get_string_resource("root", "Root");
800 if (res != NULL)
801 {
802 free(res);
803 if (get_boolean_resource("root", "Root"))
804 {
805 /* user specified -root; render into the root window
806 * (ignore any -geometry, if provided)
807 */
808 use_root = 1;
809 check_geom = 0;
810 }
811 else
812 {
813 /* user specified -noroot; render into separate window
814 */
815 use_root = 0;
816 check_geom = 1;
817 }
818 }
819 else
820 {
821 /* user specified neither -root nor -noroot; if -geometry is
822 * provided, render into separate window, else render into root
823 */
824 use_root = 1;
825 check_geom = 1;
826 }
827
828 /* if check_geom isn't set, nothing more to do
829 */
830 if (check_geom == 0) return;
831
832 /* look for -geometry and try to make sense of it
833 */
834 res = get_string_resource("geometry", "Geometry");
835 if (res != NULL)
836 {
837 /* if -geometry is specified, assume -noroot and set default width
838 * and height (which get overridden by -geometry width and height,
839 * if provided)
840 */
841 use_root = 0;
842 wdth = DefaultWdthHght;
843 hght = DefaultWdthHght;
844
845 mask = XParseGeometry(res, &x, &y, &w, &h);
846
847 /* extract width and height information
848 */
849 if ((mask & WidthValue) && (mask & HeightValue))
850 {
851 wdth = w;
852 hght = h;
853 }
854 else
855 {
856 if ((mask & WidthValue) || (mask & HeightValue))
857 warning("geometry must specify both width and height");
858 }
859
860 /* extract position information
861 */
862 if ((mask & XValue) && (mask & YValue))
863 {
864 window_pos_flag = 1;
865 window_xvalue = x;
866 window_yvalue = y;
867
868 if (mask & XNegative)
869 {
870 window_xvalue += (DisplayWidth(dsply, scrn) - wdth);
871 window_xvalue -= (2 * DefaultBorderWidth);
872 }
873
874 if (mask & YNegative)
875 {
876 window_yvalue += (DisplayHeight(dsply, scrn) - hght);
877 window_yvalue -= (2 * DefaultBorderWidth);
878 }
879
880 if (mask & XNegative)
881 if (mask & YNegative)
882 window_gravity = SouthEastGravity;
883 else
884 window_gravity = NorthEastGravity;
885 else
886 if (mask & YNegative)
887 window_gravity = SouthWestGravity;
888 else
889 window_gravity = NorthWestGravity;
890 }
891 else
892 {
893 if ((mask & XValue) || (mask & YValue))
894 warning("geometry must specify both x and y offsets");
895
896 window_pos_flag = 0;
897 window_xvalue = 0;
898 window_yvalue = 0;
899 window_gravity = 0;
900 }
901
902 free(res);
903 }
904 else if (use_root == 0)
905 {
906 /* if -noroot was specified but no -geometry was provided, assume
907 * defaults
908 */
909 wdth = DefaultWdthHght;
910 hght = DefaultWdthHght;
911 window_pos_flag = 0;
912 window_xvalue = 0;
913 window_yvalue = 0;
914 }
915 }
916
917
918 static void x11_setup()
919 {
920 unsigned dith_size;
921 unsigned xbuf_size;
922
923 switch (bpp)
924 {
925 case 1:
926 dith_size = wdth + 7;
927 break;
928
929 case 8:
930 case 16:
931 case 24:
932 case 32:
933 dith_size = wdth;
934 break;
935
936 default:
937 dith_size = 0; /* keep lint happy */
938 fprintf(stderr,
939 "xearth %s: fatal - unsupported pixmap format (%d bits/pixel)\n",
940 VersionString, bpp);
941 exit(1);
942 }
943
944 xbuf_size = (dith_size * bpp) >> 3;
945
946 dith = (u16or32 *) malloc((unsigned) sizeof(u16or32) * dith_size);
947 assert(dith != NULL);
948
949 xbuf = (u_char *) malloc((unsigned) xbuf_size);
950 assert(xbuf != NULL);
951
952 xim = XCreateImage(dsply, visl, (unsigned) dpth, ZPixmap, 0,
953 (char *) xbuf, (unsigned) wdth, 1, 8,
954 xbuf_size);
955
956 if (xim->bits_per_pixel != bpp)
957 {
958 fprintf(stderr,
959 "xearth %s: fatal - unexpected bits/pixel for depth %d\n",
960 VersionString, dpth);
961 fprintf(stderr,
962 " (expected %d bits/pixel, actual value is %d)\n",
963 bpp, xim->bits_per_pixel);
964 exit(1);
965 }
966
967 if (bpp == 1)
968 {
969 /* force MSBFirst bitmap_bit_order and byte_order
970 */
971 xim->bitmap_bit_order = MSBFirst;
972 xim->byte_order = MSBFirst;
973 }
974
975 idx = 0;
976 }
977
978
979 /* pack pixels into ximage format (assuming bits_per_pixel == 1,
980 * bitmap_bit_order == MSBFirst, and byte_order == MSBFirst)
981 */
982 static void pack_mono_1(src, dst)
983 u16or32 *src;
984 u_char *dst;
985 {
986 int i, i_lim;
987 unsigned val;
988
989 i_lim = wdth;
990 for (i=0; i<i_lim; i+=8)
991 {
992 val = ((src[0] << 7) | (src[1] << 6) | (src[2] << 5) |
993 (src[3] << 4) | (src[4] << 3) | (src[5] << 2) |
994 (src[6] << 1) | (src[7] << 0));
995
996 /* if white is pixel 0, need to toggle the bits
997 */
998 dst[i>>3] = (white == 0) ? (~ val) : val;
999 src += 8;
1000 }
1001 }
1002
1003
1004 /* pack pixels into ximage format (assuming bits_per_pixel == 8)
1005 */
1006 static void pack_8(src, map, dst)
1007 u16or32 *src;
1008 Pixel *map;
1009 u_char *dst;
1010 {
1011 int i, i_lim;
1012 unsigned val;
1013
1014 i_lim = wdth;
1015 for (i=0; i<i_lim; i++)
1016 {
1017 val = map[src[i]];
1018 dst[i] = val;
1019 }
1020 }
1021
1022
1023 /* pack pixels into ximage format (assuming bits_per_pixel == 16)
1024 */
1025 static void pack_16(src, map, dst)
1026 u16or32 *src;
1027 Pixel *map;
1028 u_char *dst;
1029 {
1030 int i, i_lim;
1031 unsigned val;
1032
1033 i_lim = wdth;
1034
1035 if (xim->byte_order == MSBFirst)
1036 {
1037 for (i=0; i<i_lim; i++)
1038 {
1039 val = map[src[i]];
1040 dst[0] = (val >> 8) & 0xff;
1041 dst[1] = val & 0xff;
1042 dst += 2;
1043 }
1044 }
1045 else /* (xim->byte_order == LSBFirst) */
1046 {
1047 for (i=0; i<i_lim; i++)
1048 {
1049 val = map[src[i]];
1050 dst[0] = val & 0xff;
1051 dst[1] = (val >> 8) & 0xff;
1052 dst += 2;
1053 }
1054 }
1055 }
1056
1057
1058 /* pack pixels into ximage format (assuming bits_per_pixel == 24)
1059 */
1060 static void pack_24(src, map, dst)
1061 u16or32 *src;
1062 Pixel *map;
1063 u_char *dst;
1064 {
1065 int i, i_lim;
1066 unsigned val;
1067
1068 i_lim = wdth;
1069
1070 if (xim->byte_order == MSBFirst)
1071 {
1072 for (i=0; i<i_lim; i++)
1073 {
1074 val = map[src[i]];
1075 dst[0] = (val >> 16) & 0xff;
1076 dst[1] = (val >> 8) & 0xff;
1077 dst[2] = val & 0xff;
1078 dst += 3;
1079 }
1080 }
1081 else /* (xim->byte_order == LSBFirst) */
1082 {
1083 for (i=0; i<i_lim; i++)
1084 {
1085 val = map[src[i]];
1086 dst[0] = val & 0xff;
1087 dst[1] = (val >> 8) & 0xff;
1088 dst[2] = (val >> 16) & 0xff;
1089 dst += 3;
1090 }
1091 }
1092 }
1093
1094
1095 /* pack pixels into ximage format (assuming bits_per_pixel == 32)
1096 */
1097 static void pack_32(src, map, dst)
1098 u16or32 *src;
1099 Pixel *map;
1100 u_char *dst;
1101 {
1102 int i, i_lim;
1103 unsigned val;
1104
1105 i_lim = wdth;
1106
1107 if (xim->byte_order == MSBFirst)
1108 {
1109 for (i=0; i<i_lim; i++)
1110 {
1111 val = map[src[i]];
1112 dst[0] = (val >> 24) & 0xff;
1113 dst[1] = (val >> 16) & 0xff;
1114 dst[2] = (val >> 8) & 0xff;
1115 dst[3] = val & 0xff;
1116 dst += 4;
1117 }
1118 }
1119 else /* (xim->byte_order == LSBFirst) */
1120 {
1121 for (i=0; i<i_lim; i++)
1122 {
1123 val = map[src[i]];
1124 dst[0] = val & 0xff;
1125 dst[1] = (val >> 8) & 0xff;
1126 dst[2] = (val >> 16) & 0xff;
1127 dst[3] = (val >> 24) & 0xff;
1128 dst += 4;
1129 }
1130 }
1131 }
1132
1133
1134 static int x11_row(row)
1135 u_char *row;
1136 {
1137 if (mono)
1138 mono_dither_row(row, dith);
1139 else
1140 dither_row(row, dith);
1141
1142 switch (bpp)
1143 {
1144 case 1:
1145 pack_mono_1(dith, xbuf);
1146 break;
1147
1148 case 8:
1149 pack_8(dith, pels, xbuf);
1150 break;
1151
1152 case 16:
1153 pack_16(dith, pels, xbuf);
1154 break;
1155
1156 case 24:
1157 pack_24(dith, pels, xbuf);
1158 break;
1159
1160 case 32:
1161 pack_32(dith, pels, xbuf);
1162 break;
1163
1164 default:
1165 fprintf(stderr,
1166 "xearth %s: fatal - unsupported pixmap format (%d bits/pixel)\n",
1167 VersionString, bpp);
1168 exit(1);
1169 }
1170
1171 XPutImage(dsply, work_pix, gc, xim, 0, 0, 0, idx, (unsigned) wdth, 1);
1172 idx += 1;
1173
1174 return 0;
1175 }
1176
1177
1178 static void x11_cleanup()
1179 {
1180 MarkerInfo *minfo;
1181 Display *dpy;
1182 Pixmap tmp;
1183
1184 XDestroyImage(xim);
1185 free(dith);
1186
1187 dpy = dsply;
1188
1189 if (do_markers)
1190 {
1191 minfo = marker_info;
1192 while (minfo->label != NULL)
1193 {
1194 mark_location(dpy, minfo);
1195 minfo += 1;
1196 }
1197 }
1198
1199 if (do_label) draw_label(dpy);
1200
1201 XSetWindowBackgroundPixmap(dpy, xearth_window, work_pix);
1202 XClearWindow(dpy, xearth_window);
1203 XSync(dpy, True);
1204
1205 if (use_two_pixmaps)
1206 {
1207 tmp = work_pix;
1208 work_pix = disp_pix;
1209 disp_pix = tmp;
1210 }
1211 }
1212
1213
1214 static void draw_label(dpy)
1215 Display *dpy;
1216 {
1217 int dy;
1218 int x, y;
1219 int len;
1220 int direction;
1221 int ascent;
1222 int descent;
1223 char buf[128];
1224 XCharStruct extents;
1225
1226 dy = font->ascent + font->descent + 1;
1227
1228 if (label_orient & LABEL_TOP_FLUSH)
1229 {
1230 y = label_yvalue + font->ascent;
1231 }
1232 else
1233 {
1234 y = (hght + label_yvalue) - font->descent;
1235 #ifdef DEBUG
1236 y -= 3 * dy; /* 4 lines of text */
1237 #else
1238 y -= 2 * dy; /* 3 lines of text */
1239 #endif
1240 }
1241
1242 #ifdef DEBUG
1243 frame += 1;
1244 sprintf(buf, "frame %d", frame);
1245 len = strlen(buf);
1246 XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents);
1247 if (label_orient & LABEL_LEFT_FLUSH)
1248 x = label_xvalue - extents.lbearing;
1249 else
1250 x = (wdth + label_xvalue) - extents.rbearing;
1251 draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len);
1252 y += dy;
1253 #endif /* DEBUG */
1254
1255 strftime(buf, sizeof(buf), "%d %b %y %H:%M %Z", localtime(¤t_time));
1256 len = strlen(buf);
1257 XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents);
1258 if (label_orient & LABEL_LEFT_FLUSH)
1259 x = label_xvalue - extents.lbearing;
1260 else
1261 x = (wdth + label_xvalue) - extents.rbearing;
1262 draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len);
1263 y += dy;
1264
1265 sprintf(buf, "view %.1f %c %.1f %c",
1266 fabs(view_lat), ((view_lat < 0) ? 'S' : 'N'),
1267 fabs(view_lon), ((view_lon < 0) ? 'W' : 'E'));
1268 len = strlen(buf);
1269 XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents);
1270 if (label_orient & LABEL_LEFT_FLUSH)
1271 x = label_xvalue - extents.lbearing;
1272 else
1273 x = (wdth + label_xvalue) - extents.rbearing;
1274 draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len);
1275 y += dy;
1276
1277 sprintf(buf, "sun %.1f %c %.1f %c",
1278 fabs(sun_lat), ((sun_lat < 0) ? 'S' : 'N'),
1279 fabs(sun_lon), ((sun_lon < 0) ? 'W' : 'E'));
1280 len = strlen(buf);
1281 XTextExtents(font, buf, len, &direction, &ascent, &descent, &extents);
1282 if (label_orient & LABEL_LEFT_FLUSH)
1283 x = label_xvalue - extents.lbearing;
1284 else
1285 x = (wdth + label_xvalue) - extents.rbearing;
1286 draw_outlined_string(dpy, work_pix, white, black, x, y, buf, len);
1287 y += dy;
1288 }
1289
1290
1291 static void mark_location(dpy, info)
1292 Display *dpy;
1293 MarkerInfo *info;
1294 {
1295 int x, y;
1296 int len;
1297 double lat, lon;
1298 double pos[3];
1299 char *text;
1300 int direction;
1301 int ascent;
1302 int descent;
1303 XCharStruct extents;
1304
1305 lat = info->lat * (M_PI/180);
1306 lon = info->lon * (M_PI/180);
1307
1308 pos[0] = sin(lon) * cos(lat);
1309 pos[1] = sin(lat);
1310 pos[2] = cos(lon) * cos(lat);
1311
1312 XFORM_ROTATE(pos, view_pos_info);
1313
1314 if (proj_type == ProjTypeOrthographic)
1315 {
1316 /* if the marker isn't visible, return immediately
1317 */
1318 if (pos[2] <= 0) return;
1319 }
1320 else if (proj_type == ProjTypeMercator)
1321 {
1322 /* apply mercator projection
1323 */
1324 pos[0] = MERCATOR_X(pos[0], pos[2]);
1325 pos[1] = MERCATOR_Y(pos[1]);
1326 }
1327 else /* (proj_type == ProjTypeCylindrical) */
1328 {
1329 /* apply cylindrical projection
1330 */
1331 pos[0] = CYLINDRICAL_X(pos[0], pos[2]);
1332 pos[1] = CYLINDRICAL_Y(pos[1]);
1333 }
1334
1335 x = XPROJECT(pos[0]);
1336 y = YPROJECT(pos[1]);
1337
1338 XSetForeground(dpy, gc, black);
1339 XDrawArc(dpy, work_pix, gc, x-3, y-3, 6, 6, 0, 360*64);
1340 XDrawArc(dpy, work_pix, gc, x-1, y-1, 2, 2, 0, 360*64);
1341 XSetForeground(dpy, gc, hlight);
1342 XDrawArc(dpy, work_pix, gc, x-2, y-2, 4, 4, 0, 360*64);
1343
1344 text = info->label;
1345 if (text != NULL)
1346 {
1347 len = strlen(text);
1348 XTextExtents(font, text, len, &direction, &ascent, &descent, &extents);
1349
1350 switch (info->align)
1351 {
1352 case MarkerAlignLeft:
1353 x -= (extents.rbearing + 4);
1354 y += (font->ascent + font->descent) / 3;
1355 break;
1356
1357 case MarkerAlignRight:
1358 case MarkerAlignDefault:
1359 x += (extents.lbearing + 3);
1360 y += (font->ascent + font->descent) / 3;
1361 break;
1362
1363 case MarkerAlignAbove:
1364 x -= (extents.rbearing - extents.lbearing) / 2;
1365 y -= (extents.descent + 4);
1366 break;
1367
1368 case MarkerAlignBelow:
1369 x -= (extents.rbearing - extents.lbearing) / 2;
1370 y += (extents.ascent + 5);
1371 break;
1372
1373 default:
1374 assert(0);
1375 }
1376
1377 draw_outlined_string(dpy, work_pix, hlight, black, x, y, text, len);
1378 }
1379
1380 XSetForeground(dpy, gc, white);
1381 }
1382
1383
1384 static void draw_outlined_string(dpy, pix, fg, bg, x, y, text, len)
1385 Display *dpy;
1386 Pixmap pix;
1387 Pixel fg;
1388 Pixel bg;
1389 int x;
1390 int y;
1391 char *text;
1392 int len;
1393 {
1394 XSetForeground(dpy, gc, bg);
1395 XDrawString(dpy, pix, gc, x+1, y, text, len);
1396 XDrawString(dpy, pix, gc, x-1, y, text, len);
1397 XDrawString(dpy, pix, gc, x, y+1, text, len);
1398 XDrawString(dpy, pix, gc, x, y-1, text, len);
1399 XSetForeground(dpy, gc, fg);
1400 XDrawString(dpy, pix, gc, x, y, text, len);
1401 }
1402
1403
1404 /* Function Name: GetVRoot
1405 * Description: Gets the root window, even if it's a virtual root
1406 * Arguments: the display and the screen
1407 * Returns: the root window for the client
1408 *
1409 * (taken nearly verbatim from the june 1993 comp.windows.x FAQ, item 148)
1410 */
1411 static Window GetVRoot(dpy)
1412 Display *dpy;
1413 {
1414 int i;
1415 Window rootReturn, parentReturn, *children;
1416 unsigned int numChildren;
1417 Atom __SWM_VROOT = None;
1418 Window rslt = root;
1419
1420 __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
1421 XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren);
1422 for (i=0; i<numChildren; i++)
1423 {
1424 Atom actual_type;
1425 int actual_format;
1426 unsigned long nitems, bytesafter;
1427 Window *newRoot = NULL;
1428
1429 /* item 148 in the FAQ neglects to mention that there is a race
1430 * condition here; consider a child of the root window that
1431 * existed when XQueryTree() was called, but has disappeared
1432 * before XGetWindowProperty() gets called for that window ...
1433 */
1434 if ((XGetWindowProperty(dpy, children[i], __SWM_VROOT, 0, 1,
1435 False, XA_WINDOW, &actual_type,
1436 &actual_format, &nitems, &bytesafter,
1437 (unsigned char **) &newRoot) == Success)
1438 && newRoot)
1439 {
1440 rslt = *newRoot;
1441 break;
1442 }
1443 }
1444
1445 /* item 148 in the FAQ also neglects to mention that we probably
1446 * want to free the list of children after we're done with it ...
1447 */
1448 XFree((void *) children);
1449
1450 return rslt;
1451 }
1452
1453
1454 /*
1455 * the following code is lifted nearly verbatim from jim frost's
1456 * xloadimage code (version 3.00). that code includes a note
1457 * indicating that the changes to allow proper freeing of previously
1458 * allocated resources made by Deron Dann Johnson (dj@eng.sun.com),
1459 * thus he may well be the author of this code.
1460 *
1461 * Copyright (C) 1989, 1990, 1991 by Jim Frost.
1462 *
1463 * xkill_handler() and the XSetErrorHandler() code in freePrevious()
1464 * were not in the original xloadimage code; this is new as of xearth
1465 * version 0.91.
1466 */
1467
1468 static void updateProperty(dpy, w, name, type, format, data, nelem)
1469 Display *dpy;
1470 Window w;
1471 const char *name;
1472 Atom type;
1473 int format;
1474 int data;
1475 int nelem;
1476 {
1477 /* intern the property name */
1478 Atom atom = XInternAtom(dpy, name, 0);
1479
1480 /* create or replace the property */
1481 XChangeProperty(dpy, w, atom, type, format, PropModeReplace,
1482 (unsigned char *)&data, nelem);
1483 }
1484
1485
1486 /* Sets the close-down mode of the client to 'RetainPermanent'
1487 * so all client resources will be preserved after the client
1488 * exits. Puts a property on the default root window containing
1489 * an XID of the client so that the resources can later be killed.
1490 */
1491 static void preserveResource(dpy, w)
1492 Display *dpy;
1493 Window w;
1494 {
1495 /* create dummy resource */
1496 Pixmap pm = XCreatePixmap(dpy, w, 1, 1, 1);
1497
1498 /* create/replace the property */
1499 updateProperty(dpy, w, RETAIN_PROP_NAME, XA_PIXMAP, 32, (int)pm, 1);
1500
1501 /* retain all client resources until explicitly killed */
1502 XSetCloseDownMode(dpy, RetainPermanent);
1503 }
1504
1505
1506 /* Flushes any resources previously retained by the client,
1507 * if any exist.
1508 */
1509 static void freePrevious(dpy, w)
1510 Display *dpy;
1511 Window w;
1512 {
1513 Pixmap *pm;
1514 Atom actual_type;
1515 int format;
1516 unsigned long nitems;
1517 unsigned long bytes_after;
1518
1519 /* intern the property name */
1520 Atom atom = XInternAtom(dpy, RETAIN_PROP_NAME, 0);
1521
1522 /* look for existing resource allocation */
1523 if ((XGetWindowProperty(dpy, w, atom, 0, 1, 1 /*delete*/,
1524 AnyPropertyType, &actual_type,
1525 &format, &nitems, &bytes_after,
1526 (unsigned char **) &pm) == Success) &&
1527 (nitems == 1))
1528 if ((actual_type == XA_PIXMAP) && (format == 32) &&
1529 (nitems == 1) && (bytes_after == 0))
1530 {
1531 /* blast it away, but first provide new X error handler in case
1532 * the client that installed the RETAIN_PROP_NAME (_XSETROOT_ID)
1533 * property on the root window has already terminated
1534 */
1535 orig_error_handler = XSetErrorHandler(xkill_handler);
1536 XKillClient(dpy, (XID) *pm);
1537 XSync(dpy, False);
1538 XSetErrorHandler(orig_error_handler);
1539 XFree((void *) pm);
1540 }
1541 else if (actual_type != None)
1542 {
1543 fprintf(stderr,
1544 "%s: warning: invalid format encountered for property %s\n",
1545 RETAIN_PROP_NAME, progname);
1546 }
1547 }
1548
1549
1550 static int xkill_handler(dpy, xev)
1551 Display *dpy;
1552 XErrorEvent *xev;
1553 {
1554 /* ignore any BadValue errors from the call to XKillClient() in
1555 * freePrevious(); they should only happen if the client that
1556 * installed the RETAIN_PROP_NAME (_XSETROOT_ID) property on the
1557 * root window has already terminated
1558 */
1559 if ((xev->error_code == BadValue) &&
1560 (xev->request_code == X_KillClient))
1561 {
1562 fprintf(stderr, "ignoring BadValue error from XKillClient()\n");
1563 fflush(stderr);
1564 return 0;
1565 }
1566
1567 /* pass any other errors get on to the original error handler
1568 */
1569 return orig_error_handler(dpy, xev);
1570 }