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