"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(&current_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 }