home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xdaliclk.zip / xdaliclock.c < prev    next >
C/C++ Source or Header  |  1992-06-12  |  54KB  |  1,877 lines

  1. /* xdaliclock.c, Copyright (c) 1991, 1992 Jamie Zawinski <jwz@lucid.com>
  2.  *
  3.  * Permission to use, copy, modify, distribute, and sell this software and its
  4.  * documentation for any purpose is hereby granted without fee, provided that
  5.  * the above copyright notice appear in all copies and that both that
  6.  * copyright notice and this permission notice appear in supporting
  7.  * documentation.  No representations are made about the suitability of this
  8.  * software for any purpose.  It is provided "as is" without express or 
  9.  * implied warranty.
  10.  */
  11.  
  12. char *version =
  13.   "XDaliClock v1.05; Copyright (c) 1991, 1992 Jamie Zawinski <jwz@lucid.com>";
  14.  
  15. /*   7 oct 91 (v1.00)    submitted for X11r5 contrib tape.
  16.     26 oct 91 (v1.01)    fixed Expose handling in -noseconds mode;
  17.             access() called with too few args;
  18.             added resource for MM/DD/YY, DD/MM/YY, etc.
  19.      3 jan 92 (v1.02)    merged in VMS support from Daniel C. Newman
  20.             <dan@innosoft.com>.
  21.     16 jan 92 (v1.03)    added more intelligent visual support.
  22.             Made it not die on fonts without per-char info.
  23.      4 jun 92 (v1.04)   more VMS support for resource database files, from
  24.             Tony Kennedy <adk@scri.fsu.edu>.
  25.     10 jun 92 (v1.05)   More from Tony Kennedy: support visuals with different
  26.             depths from default, center digits correctly in
  27.             initial window, and merge geometry defaults in a more
  28.             sophisticated way.  Merged in a slightly reworked 
  29.             version of more general segment-handling code from
  30.             Dan Wallach <c169-bg@auriga.berkeley.edu>.  Added a
  31.             second, even bigger builtin font.  Added the -root
  32.             and -fullscreen arguments.
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <X11/Xlib.h>
  37. #include <X11/Xutil.h>
  38. #include <X11/Xos.h>
  39. #include <X11/Xresource.h>
  40. #include "vroot.h"
  41.  
  42. #ifdef VMS
  43. #include <descrip.h>
  44. # define R_OK 4
  45. #endif
  46.  
  47. #ifdef SHAPE
  48. #include <X11/extensions/shape.h>
  49. #endif
  50.  
  51. #include "defaults.h"
  52.  
  53. #ifndef isupper
  54. # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
  55. #endif
  56. #ifndef _tolower
  57. # define _tolower(c)  ((c) - 'A' + 'a')
  58. #endif
  59.  
  60. #if defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2)
  61.  
  62. int use_builtin_font;
  63.  
  64. struct raw_number {
  65.   char *bits;
  66.   int width, height;
  67. };
  68.  
  69. #endif /* BUILTIN_FONT || BUILTIN_FONT_2 */
  70.  
  71. #ifdef BUILTIN_FONT
  72.  
  73. # include "zero.xbm"
  74. # include "one.xbm"
  75. # include "two.xbm"
  76. # include "three.xbm"
  77. # include "four.xbm"
  78. # include "five.xbm"
  79. # include "six.xbm"
  80. # include "seven.xbm"
  81. # include "eight.xbm"
  82. # include "nine.xbm"
  83. # include "colon.xbm"
  84. # include "slash.xbm"
  85.  
  86. struct raw_number numbers [] = {
  87.   { zero_bits, zero_width, zero_height },
  88.   { one_bits, one_width, one_height },
  89.   { two_bits, two_width, two_height },
  90.   { three_bits, three_width, three_height },
  91.   { four_bits, four_width, four_height },
  92.   { five_bits, five_width, five_height },
  93.   { six_bits, six_width, six_height },
  94.   { seven_bits, seven_width, seven_height },
  95.   { eight_bits, eight_width, eight_height },
  96.   { nine_bits, nine_width, nine_height },
  97.   { colon_bits, colon_width, colon_height },
  98.   { slash_bits, slash_width, slash_height },
  99.   0
  100. };
  101.  
  102. #endif /* BUILTIN_FONT */
  103.  
  104. #ifdef BUILTIN_FONT_2
  105.  
  106. # include "zero2.xbm"
  107. # include "one2.xbm"
  108. # include "two2.xbm"
  109. # include "three2.xbm"
  110. # include "four2.xbm"
  111. # include "five2.xbm"
  112. # include "six2.xbm"
  113. # include "seven2.xbm"
  114. # include "eight2.xbm"
  115. # include "nine2.xbm"
  116. # include "colon2.xbm"
  117. # include "slash2.xbm"
  118.  
  119. struct raw_number numbers_2 [] = {
  120.   { zero2_bits, zero2_width, zero2_height },
  121.   { one2_bits, one2_width, one2_height },
  122.   { two2_bits, two2_width, two2_height },
  123.   { three2_bits, three2_width, three2_height },
  124.   { four2_bits, four2_width, four2_height },
  125.   { five2_bits, five2_width, five2_height },
  126.   { six2_bits, six2_width, six2_height },
  127.   { seven2_bits, seven2_width, seven2_height },
  128.   { eight2_bits, eight2_width, eight2_height },
  129.   { nine2_bits, nine2_width, nine2_height },
  130.   { colon2_bits, colon2_width, colon2_height },
  131.   { slash2_bits, slash2_width, slash2_height },
  132.   0
  133. };
  134.  
  135. #endif /* BUILTIN_FONT_2 */
  136.  
  137. char *progname;
  138. char *app_class;
  139. char *window_title;
  140. XrmDatabase db;
  141. Display *display;
  142. Screen *screen;
  143. int screen_no;
  144. int visual_class;
  145. Visual *visual;
  146. unsigned int visual_depth;
  147. int root_p;
  148. int full_screen_p;
  149. Window window;
  150. Pixmap pixmap;
  151. GC pixmap_draw_gc, pixmap_erase_gc;
  152. GC window_draw_gc, window_erase_gc;
  153. XColor fg_color, bg_color, bd_color;
  154. Colormap cmap;
  155.  
  156. struct frame *base_frames [10];
  157. struct frame *current_frames [6];
  158. struct frame *target_frames [6];
  159. struct frame *clear_frame;
  160. int character_width, character_height;
  161. int x_offsets [6];
  162. int window_offset_x, window_offset_y;
  163. int wander_x, wander_y, wander_delta_x, wander_delta_y;
  164. Pixmap colon, slash;
  165. int colon_char_width;
  166. int time_digits [6];
  167. int last_time_digits [6];
  168. int button_down = 0;
  169. char *hacked_version;
  170.  
  171. Pixmap memory_pig_zeros [9] [10];
  172. Pixmap memory_pig_digits [8] [10];
  173. Pixmap total_oinker_digits [9] [10];
  174.  
  175. int twelve_hour_time;
  176. int be_a_pig;
  177. int minutes_only;
  178. int do_cycle;
  179. enum { MMDDYY, DDMMYY, YYMMDD, YYDDMM, MMYYDD, DDYYMM } date_format;
  180.  
  181. #ifdef SHAPE
  182. int do_shape;
  183. #endif
  184.  
  185. #define MAX(a, b) ((a)>(b)?(a):(b))
  186. #define MIN(a, b) ((a)<(b)?(a):(b))
  187.  
  188. typedef short unsigned int POS;
  189.  
  190. /* Number of horizontal segments/line.  Enlarge this if you are trying
  191.    to use a font that is too "curvy" for XDaliClock to cope with.
  192.    This code was sent to me by Dan Wallach <c169-bg@auriga.berkeley.edu>.
  193.    I'm highly opposed to ever using statically-sized arrays, but I don't
  194.    really feel like hacking on this code enough to clean it up.
  195.  */
  196. #ifndef MAX_SEGS_PER_LINE
  197. #define MAX_SEGS_PER_LINE 3
  198. #endif
  199.  
  200. struct scanline {
  201.   POS left[MAX_SEGS_PER_LINE], right[MAX_SEGS_PER_LINE];
  202. };
  203.  
  204. struct frame {
  205.   struct scanline scanlines [1]; /* scanlines are contiguous here */
  206. };
  207.  
  208.  
  209. struct frame *
  210. image_to_frame (image)
  211.      XImage *image;
  212. {
  213.   register int y, x;
  214.   struct frame *frame;
  215.   int width = image->width;
  216.   int height = image->height;
  217.   POS *left, *right;
  218.   int *nsegs;
  219.   int maxsegments = 0;
  220.  
  221.   frame = (struct frame *)
  222.     malloc (sizeof (struct frame) +
  223.         (sizeof (struct scanline) * (height - 1)));
  224.   nsegs = (int *) malloc (sizeof (int) * height);
  225.   
  226.   for (y = 0; y < height; y++) {
  227.     int seg, end;
  228.     x = 0;
  229. #define getbit(x) (XGetPixel (image, (x), y))
  230.     left = frame->scanlines[y].left;
  231.     right = frame->scanlines[y].right;
  232.  
  233.     for (seg = 0; seg < MAX_SEGS_PER_LINE; seg++)
  234.       left [seg] = right [seg] = width / 2;
  235.  
  236.     for (seg = 0; seg < MAX_SEGS_PER_LINE; seg++)
  237.       {
  238.     for (; x < width; x++)
  239.       if (getbit (x)) break;
  240.     if (x == width) break;
  241.     left [seg] = x;
  242.     for (; x < width; x++)
  243.       if (! getbit (x)) break;
  244.     right [seg] = x;
  245.       }
  246.  
  247.     for (; x < width; x++)
  248.       if (getbit (x))
  249.     {
  250.       fprintf (stderr,
  251.    "%s: font is too curvy.  Increase MAX_SEGS_PER_LINE (%d) and recompile.\n",
  252.            progname, MAX_SEGS_PER_LINE);
  253.       exit (-1);
  254.     }
  255.  
  256.     /* If there were any segments on this line, then replicate the last
  257.        one out to the end of the line.  If it's blank, leave it alone,
  258.        meaning it will be a 0-pixel-wide line down the middle.
  259.      */
  260.     end = seg;
  261.     if (end > 0)
  262.       for (; seg < MAX_SEGS_PER_LINE; seg++)
  263.     {
  264.       left [seg] = left [end-1];
  265.       right [seg] = right [end-1];
  266.     }
  267.     if (end > maxsegments) maxsegments = end;
  268.     nsegs [y] = end;
  269.  
  270. #undef getbit
  271.   }
  272.   return frame;
  273. }
  274.  
  275.  
  276. /* This is kind of gross.
  277.  */
  278. char *default_fonts [] = {
  279.   "-*-charter-bold-i-*-*-*-500-*-*-*-*-*-*",
  280.   "-*-lucidabright-demibold-i-*-*-*-500-*-*-*-*-*-*",
  281.   "-*-new century schoolbook-bold-i-*-*-*-500-*-*-*-*-*-*",
  282.   "-*-helvetica-bold-o-*-*-*-500-*-*-*-*-*-*",
  283.   "-*-lucida-bold-i-*-*-*-500-*-*-*-*-*-*",
  284.  
  285.   "-*-charter-bold-i-*-*-*-360-*-*-*-*-*-*",
  286.   "-*-lucidabright-demibold-i-*-*-*-360-*-*-*-*-*-*",
  287.   "-*-new century schoolbook-bold-i-*-*-*-360-*-*-*-*-*-*",
  288.   "-*-helvetica-bold-o-*-*-*-360-*-*-*-*-*-*",
  289.   "-*-lucida-bold-i-*-*-*-360-*-*-*-*-*-*",
  290.  
  291.   "-*-charter-bold-i-*-*-*-240-*-*-*-*-*-*",
  292.   "-*-lucidabright-demibold-i-*-*-*-240-*-*-*-*-*-*",
  293.   "-*-new century schoolbook-bold-i-*-*-*-240-*-*-*-*-*-*",
  294.   "-*-helvetica-bold-o-*-*-*-240-*-*-*-*-*-*",
  295.   "-*-lucida-bold-i-*-*-*-240-*-*-*-*-*-*",    /* too wide.  bug? */
  296.  
  297.   "-*-charter-bold-i-*-*-*-180-*-*-*-*-*-*",
  298.   "-*-lucidabright-demibold-i-*-*-*-180-*-*-*-*-*-*",
  299.   "-*-new century schoolbook-bold-i-*-*-*-180-*-*-*-*-*-*",
  300.   "-*-helvetica-bold-o-*-*-*-180-*-*-*-*-*-*",    /* too wide */
  301.   "-*-lucida-bold-i-*-*-*-180-*-*-*-*-*-*",    /* too wide */
  302.   0
  303. };
  304.  
  305. void
  306. load_font (font_name)
  307.      char *font_name;
  308. {
  309.   int i, max_lbearing, max_rbearing, max_ascent, max_descent;
  310.   XFontStruct *font = 0;
  311.   Pixmap pixmap;
  312.   XImage *image = 0;
  313.   XGCValues gcvalues;
  314.   GC draw_gc, erase_gc;
  315.   char **fonts = default_fonts;
  316.   int bad_font_name = 0;
  317.  
  318.   if (font_name)
  319.     if (! (font = XLoadQueryFont (display, font_name))) {
  320.       bad_font_name = 1;
  321.       fprintf (stderr, "%s: Couldn't load font \"%s\";\n", progname, font_name);
  322.     }
  323.   if (! font)
  324.     for (; fonts; fonts++)
  325.       if (font = XLoadQueryFont (display, font_name = *fonts))
  326.     break;
  327.   if (bad_font_name && font)
  328.     fprintf (stderr, " using font \"%s\" instead.\n", fonts [0]);
  329.   else if (! font) {
  330.     if (bad_font_name)
  331.       fprintf (stderr, " couldn't load any of the default fonts either.\n");
  332.     else
  333.       fprintf (stderr, "%s: Couldn't load any of the default fonts.\n",
  334.            progname);
  335.     exit (-1);
  336.   }
  337.  
  338.   if (font->min_char_or_byte2 > '0' || font->max_char_or_byte2 < '9') {
  339.     fprintf (stderr, "%s: font %s doesn't contain characters '0'-'9'.\n",
  340.          progname);
  341.     exit (-1);
  342.   }
  343.   max_lbearing = font->min_bounds.lbearing;
  344.   max_rbearing = font->min_bounds.rbearing;
  345.   max_ascent  = font->min_bounds.ascent;
  346.   max_descent = font->min_bounds.descent;
  347.   for (i = '0'; i <= '9'; i++) {
  348.     XCharStruct *ch = (font->per_char
  349.                ? &font->per_char [i - font->min_char_or_byte2]
  350.                : &font->min_bounds);
  351.     max_lbearing = MAX (max_lbearing, ch->lbearing);
  352.     max_rbearing = MAX (max_rbearing, ch->rbearing);
  353.     max_ascent  = MAX (max_ascent,  ch->ascent);
  354.     max_descent = MAX (max_descent, ch->descent);
  355.     if (ch->lbearing == ch->rbearing || ch->ascent == -ch->descent) {
  356.       fprintf (stderr,
  357.         "%s: char '%c' has bbox %dx%d (%d - %d x %d + %d) in font %s\n",
  358.            progname,
  359.            i, ch->rbearing - ch->lbearing, ch->ascent + ch->descent,
  360.            ch->rbearing, ch->lbearing, ch->ascent, ch->descent,
  361.            font_name);
  362.       exit (-1);
  363.     }
  364.   }
  365.   character_width = max_rbearing + max_lbearing + 1; /* min enclosing rect */
  366.   character_height = max_descent + max_ascent + 1;
  367.  
  368.   /* Now we know the combined bbox of the characters we're interested in;
  369.      for each character, write it into a pixmap; grab the bits from that
  370.      pixmap; and fill the scanline-buffers.
  371.    */
  372.   pixmap = XCreatePixmap (display, RootWindowOfScreen (screen),
  373.               character_width + 1, character_height + 1, 1);
  374.   gcvalues.font = font->fid;
  375.   gcvalues.foreground = 1L;
  376.   draw_gc = XCreateGC (display, pixmap, GCFont | GCForeground, &gcvalues);
  377.   gcvalues.foreground = 0L;
  378.   erase_gc = XCreateGC (display, pixmap, GCForeground, &gcvalues);
  379.  
  380.   for (i = 0; i <= 9; i++) {
  381.     XCharStruct *ch = (font->per_char
  382.                ? &font->per_char [i + '0' - font->min_char_or_byte2]
  383.                : &font->min_bounds);
  384.     char s[1];
  385.     s[0] = i + '0';
  386.     XFillRectangle (display, pixmap, erase_gc, 0, 0,
  387.             character_width + 1, character_height + 1);
  388.     XDrawString (display, pixmap, draw_gc, max_lbearing, max_ascent, s, 1);
  389.     if (! image)
  390.       image = XGetImage (display, pixmap, 0, 0,
  391.              character_width, character_height, 1, XYPixmap);
  392.     else
  393.       XGetSubImage (display, pixmap, 0, 0,
  394.             character_width, character_height, 1, XYPixmap,
  395.             image, 0, 0);
  396.     base_frames [i] = image_to_frame (image);
  397.   }
  398.  
  399.   {
  400.     XCharStruct *ch1, *ch2;
  401.     int maxl, maxr, w;
  402.     if (font->per_char)
  403.       {
  404.     ch1 = &font->per_char [':' - font->min_char_or_byte2];
  405.     ch2 = &font->per_char ['/' - font->min_char_or_byte2];
  406.       }
  407.     else
  408.       ch1 = ch2 = &font->min_bounds;
  409.  
  410.     maxl = MAX (ch1->lbearing, ch2->lbearing);
  411.     maxr = MAX (ch1->rbearing, ch2->rbearing);
  412.     w = maxr + maxl + 1;
  413.     colon =
  414.       XCreatePixmap (display, RootWindowOfScreen (screen),
  415.              w+1, character_height+1, 1);
  416.     slash =
  417.       XCreatePixmap (display, RootWindowOfScreen (screen),
  418.              w+1, character_height+1, 1);
  419.     XFillRectangle (display, colon, erase_gc, 0, 0, w+1, character_height+1);
  420.     XFillRectangle (display, slash, erase_gc, 0, 0, w+1, character_height+1);
  421.     XDrawString (display, colon, draw_gc, maxl+1, max_ascent, ":", 1);
  422.     XDrawString (display, slash, draw_gc, maxl+1, max_ascent, "/", 1);
  423.     colon_char_width = w;
  424.   }
  425.  
  426.   XDestroyImage (image);
  427.   XFreePixmap (display, pixmap);
  428.   XFreeFont (display, font);
  429.   XFreeGC (display, draw_gc);
  430.   XFreeGC (display, erase_gc);
  431. }
  432.  
  433. #if defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2)
  434. void
  435. load_builtin_font (which)
  436.      int which;
  437. {
  438.   int i;
  439.   Pixmap pixmap;
  440.   char **fonts = default_fonts;
  441.  
  442. #if defined (BUILTIN_FONT) && defined (BUILTIN_FONT_2)
  443.   struct raw_number *nums = (which == 1 ? numbers : numbers_2);
  444. #else /* ! BUILTIN_FONT && BUILTIN_FONT_2 */
  445. # ifdef BUILTIN_FONT
  446.   struct raw_number *nums = numbers;
  447. # else /* BUILTIN_FONT_2 */
  448.   struct raw_number *nums = numbers_2;
  449. # endif /* BUILTIN_FONT_2 */
  450. #endif /* ! BUILTIN_FONT && BUILTIN_FONT_2 */
  451.  
  452.   XImage *image =
  453.     XCreateImage (display, visual,
  454.           1, XYBitmap, 0,    /* depth, format, offset */
  455.           (char *) 0,        /* data */
  456.           0, 0, 8, 0);         /* w, h, pad, bytes_per_line */
  457.   /* This stuff makes me nervous, but XCreateBitmapFromData() does it too. */
  458.   image->byte_order = LSBFirst;
  459.   image->bitmap_bit_order = LSBFirst;
  460.  
  461.   character_width = character_height = 0;
  462.  
  463.   for (i = 0; i < 10; i++) {
  464.     struct raw_number *number = &nums [i];
  465.     character_width = MAX (character_width, number->width);
  466.     character_height = MAX (character_height, number->height);
  467.     image->width = number->width;
  468.     image->height = number->height;
  469.     image->data = (char *) number->bits;
  470.     image->bytes_per_line = (number->width + 7) / 8;
  471.     base_frames [i] = image_to_frame (image);
  472.   }
  473.   XDestroyImage (image);
  474.  
  475.   colon_char_width = MAX (nums [10].width, nums [11].width);
  476.   colon = XCreateBitmapFromData (display, DefaultRootWindow (display),
  477.                  nums[10].bits,
  478.                  nums[10].width, nums[10].height);
  479.   slash = XCreateBitmapFromData (display, DefaultRootWindow (display),
  480.                  nums[11].bits,
  481.                  nums[11].width, nums[11].height);
  482. }
  483. #endif /* BUILTIN_FONT || BUILTIN_FONT_2 */
  484.  
  485. /*  It doesn't matter especially what MAX_SEGS is -- it gets flushed
  486.     when it might fill up -- this number is just for performance tuning
  487.  */
  488. #define MAX_SEGS MAX_SEGS_PER_LINE * 200
  489. static XSegment segment_buffer [MAX_SEGS + 2];
  490. static int segment_count = 0;
  491.  
  492. void
  493. flush_segment_buffer (drawable, draw_gc)
  494.      Drawable drawable;
  495.      GC draw_gc;
  496. {
  497.   if (! segment_count) return;
  498.   XDrawSegments (display, drawable, draw_gc, segment_buffer, segment_count);
  499.   segment_count = 0;
  500. }
  501.  
  502.  
  503.  
  504. void
  505. draw_frame (frame, drawable, draw_gc, x_off)
  506.      struct frame *frame;
  507.      Drawable drawable;
  508.      GC draw_gc;
  509.      int x_off;
  510. {
  511.   register int y, x;
  512.   for (y = 0; y < character_height; y++) {
  513.     struct scanline *line = &frame->scanlines [y];
  514.     for (x = 0; x < MAX_SEGS_PER_LINE; x++) {
  515.       if (line->left[x] == line->right[x] ||
  516.       (x > 0 &&
  517.        line->left[x] == line->left[x-1] &&
  518.        line->right[x] == line->right[x-1]))
  519.     continue;
  520.       segment_buffer [segment_count].x1 = x_off + line->left[x];
  521.       segment_buffer [segment_count].x2 = x_off + line->right[x];
  522.       segment_buffer [segment_count].y1 = y;
  523.       segment_buffer [segment_count].y2 = y;
  524.       segment_count++;
  525.  
  526.       if (segment_count >= MAX_SEGS)
  527.     flush_segment_buffer (drawable, draw_gc);
  528.     }
  529.   }
  530. }
  531.  
  532. void
  533. set_current_scanlines (into_frame, from_frame)
  534.      struct frame *into_frame, *from_frame;
  535. {
  536.   register int i;
  537.   for (i = 0; i < character_height; i++)
  538.     into_frame->scanlines [i] = from_frame->scanlines [i];
  539. }
  540.  
  541. void
  542. one_step (current_frame, target_frame, tick)
  543.      struct frame *current_frame, *target_frame;
  544.      int tick;
  545. {
  546.   register struct scanline *line = ¤t_frame->scanlines [0];
  547.   register struct scanline *target = &target_frame->scanlines [0];
  548.   register int i = 0, x;
  549.   for (i = 0; i < character_height; i++) {
  550. #define STEP(field) (line->field += ((int) (target->field - line->field))  \
  551.              / tick)
  552.     for (x = 0; x < MAX_SEGS_PER_LINE; x++)
  553.       {
  554.     STEP (left [x]);
  555.     STEP (right [x]);
  556.       }
  557.     line++;
  558.     target++;
  559.   }
  560. }
  561.  
  562. char test_hack;
  563. long
  564. fill_time_digits ()
  565. {
  566.   long clock = time ((time_t *) 0);
  567.   struct tm *tm = localtime (&clock);
  568.   if (test_hack)
  569.     {
  570.       time_digits [0] = time_digits [1] = time_digits [2] =
  571.     time_digits [3] = time_digits [4] = time_digits [5] =
  572.       (test_hack == '-' ? -1 : test_hack - '0');
  573.       test_hack = 0;
  574.     }
  575.   else if (! button_down)
  576.     {
  577.       if (twelve_hour_time && tm->tm_hour > 12) tm->tm_hour -= 12;
  578.       if (twelve_hour_time && tm->tm_hour == 0) tm->tm_hour = 12;
  579.       time_digits [0] = (tm->tm_hour - (tm->tm_hour % 10)) / 10;
  580.       time_digits [1] = tm->tm_hour % 10;
  581.       time_digits [2] = (tm->tm_min - (tm->tm_min % 10)) / 10;
  582.       time_digits [3] = tm->tm_min % 10;
  583.       time_digits [4] = (tm->tm_sec - (tm->tm_sec % 10)) / 10;
  584.       time_digits [5] = tm->tm_sec % 10;
  585.     }
  586.   else
  587.     {
  588.       int m0,m1,d0,d1,y0,y1;
  589.       tm->tm_mon++; /* 0 based */
  590.       m0 = (tm->tm_mon - (tm->tm_mon % 10)) / 10;
  591.       m1 = tm->tm_mon % 10;
  592.       d0 = (tm->tm_mday - (tm->tm_mday % 10)) / 10;
  593.       d1 = tm->tm_mday % 10;
  594.       y0 = (tm->tm_year - (tm->tm_year % 10)) / 10;
  595.       y1 = tm->tm_year % 10;
  596.  
  597.       switch (date_format) {
  598.       case MMDDYY:
  599.     time_digits [0] = m0; time_digits [1] = m1;
  600.     time_digits [2] = d0; time_digits [3] = d1;
  601.     time_digits [4] = y0; time_digits [5] = y1;
  602.     break;
  603.       case DDMMYY:
  604.     time_digits [0] = d0; time_digits [1] = d1;
  605.     time_digits [2] = m0; time_digits [3] = m1;
  606.     time_digits [4] = y0; time_digits [5] = y1;
  607.     break;
  608.       case YYMMDD:
  609.     time_digits [0] = y0; time_digits [1] = y1;
  610.     time_digits [2] = m0; time_digits [3] = m1;
  611.     time_digits [4] = d0; time_digits [5] = d1;
  612.     break;
  613.       case YYDDMM:
  614.     time_digits [0] = y0; time_digits [1] = y1;
  615.     time_digits [2] = d0; time_digits [3] = d1;
  616.     time_digits [4] = m0; time_digits [5] = m1;
  617.     break;
  618.       /* These are silly, but are included for completeness... */
  619.       case MMYYDD:
  620.     time_digits [0] = m0; time_digits [1] = m1;
  621.     time_digits [2] = y0; time_digits [3] = y1;
  622.     time_digits [4] = d0; time_digits [5] = d1;
  623.     break;
  624.       case DDYYMM:
  625.     time_digits [0] = d0; time_digits [1] = d1;
  626.     time_digits [2] = y0; time_digits [3] = y1;
  627.     time_digits [4] = m0; time_digits [5] = m1;
  628.     break;
  629.       }
  630.     }
  631.   return clock;
  632. }
  633.  
  634.  
  635. void
  636. fill_pig_cache (display, drawable, work_frame)
  637.      Display *display;
  638.      Drawable drawable;
  639.      struct frame *work_frame;
  640. {
  641.   int i;
  642.   /* do `[1-9]' to `0'
  643.      We have very little to gain by caching the `[347]' to `0' transitions,
  644.      but what the hell.
  645.    */
  646.   for (i = 0; i < 9; i++)
  647.     {
  648.       int tick;
  649.       set_current_scanlines (work_frame, base_frames [0]);
  650.       for (tick = 9; tick >= 0; tick--)
  651.     {
  652.       Pixmap p = XCreatePixmap (display, drawable,
  653.                     character_width, character_height, 1);
  654.       XFillRectangle (display, p, pixmap_erase_gc, 0, 0,
  655.               character_width, character_height);
  656.       draw_frame (work_frame, p, pixmap_draw_gc, 0);
  657.       flush_segment_buffer (p, pixmap_draw_gc);
  658.       memory_pig_zeros [i] [9 - tick] = p;
  659.       if (tick)
  660.         one_step (work_frame, base_frames [i+1], tick);
  661.     }
  662.     }
  663.   /* do `[1-8]' to `[2-9]' */
  664.   for (i = 0; i < 8; i++)
  665.     {
  666.       int tick;
  667.       set_current_scanlines (work_frame, base_frames [i+1]);
  668.       for (tick = 9; tick >= 0; tick--)
  669.     {
  670.       Pixmap p = XCreatePixmap (display, drawable,
  671.                     character_width, character_height, 1);
  672.       XFillRectangle (display, p, pixmap_erase_gc, 0, 0,
  673.               character_width, character_height);
  674.       draw_frame (work_frame, p, pixmap_draw_gc, 0);
  675.       flush_segment_buffer (p, pixmap_draw_gc);
  676.       memory_pig_digits [i] [9 - tick] = p;
  677.       if (tick)
  678.         one_step (work_frame, base_frames [i+2], tick);
  679.     }
  680.     }
  681.   if (be_a_pig > 1)
  682.     /* do `[1-7]' to `[3-9]' and `9' to `1' */
  683.     for (i = 0; i < 9; i++)
  684.       {
  685.     int tick;
  686.     if (i == 7) continue; /* zero transitions are already done */
  687.     set_current_scanlines (work_frame, base_frames [i+1]);
  688.     for (tick = 9; tick >= 0; tick--)
  689.       {
  690.         Pixmap p = XCreatePixmap (display, drawable,
  691.                       character_width, character_height, 1);
  692.         XFillRectangle (display, p, pixmap_erase_gc, 0, 0,
  693.                 character_width, character_height);
  694.         draw_frame (work_frame, p, pixmap_draw_gc, 0);
  695.         flush_segment_buffer (p, pixmap_draw_gc);
  696.         total_oinker_digits [i] [9 - tick] = p;
  697.         if (tick)
  698.           one_step (work_frame, base_frames [(i+3)%10], tick);
  699.       }
  700.       }
  701. }
  702.  
  703.  
  704. void
  705. initialize (font_name)
  706.      char *font_name;
  707. {
  708.   int i, x;
  709. #if defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2)
  710.   if (use_builtin_font)
  711.     load_builtin_font (use_builtin_font);
  712.   else
  713. #endif
  714.     load_font (font_name);
  715.  
  716.   bzero (memory_pig_zeros, sizeof (memory_pig_zeros));
  717.   bzero (memory_pig_digits, sizeof (memory_pig_digits));
  718.  
  719.   for (i = 0; i < 6; i++)
  720.     current_frames [i] = (struct frame *)
  721.       malloc (sizeof (struct frame) +
  722.           (sizeof (struct scanline) * (character_height - 1)));
  723.  
  724.   clear_frame = (struct frame *)
  725.     malloc (sizeof (struct frame) +
  726.         (sizeof (struct scanline) * (character_height - 1)));
  727.   for (i = 0; i < character_height; i++)
  728.     for (x = 0; x < MAX_SEGS_PER_LINE; x++)
  729.       clear_frame->scanlines [i].left [x] =
  730.     clear_frame->scanlines [i].right [x] = character_width / 2;
  731.   
  732.   x_offsets [0] = 0;
  733.   x_offsets [1] = x_offsets [0] + character_width;
  734.   x_offsets [2] = x_offsets [1] + character_width + colon_char_width;
  735.   x_offsets [3] = x_offsets [2] + character_width;
  736.   x_offsets [4] = x_offsets [3] + character_width + colon_char_width;
  737.   x_offsets [5] = x_offsets [4] + character_width;
  738. }
  739.  
  740.  
  741. static char *
  742. visual_class_name ()
  743. {
  744.   char *s = (visual_class == StaticGray  ? "StaticGray" :
  745.          visual_class == StaticColor ? "StaticColor" :
  746.          visual_class == TrueColor   ? "TrueColor" :
  747.          visual_class == GrayScale   ? "GrayScale" :
  748.          visual_class == PseudoColor ? "PseudoColor" :
  749.          visual_class == DirectColor ? "DirectColor" :
  750.          0);
  751.   if (s) return s;
  752.   s = (char *) malloc (100);
  753.   sprintf (s, "<<UnknownVisual %d>>", visual_class);
  754.   return s;
  755. }
  756.  
  757. void
  758. pick_visual_and_screen ()
  759. {
  760.   screen_no = DefaultScreen (display);
  761.  
  762.   if (visual_class < 0 || root_p)
  763.     visual = DefaultVisual (display, screen_no);
  764.   else
  765.     {
  766.       XVisualInfo vi_in, *vi_out;
  767.       int out_count;
  768.       vi_in.class = visual_class;
  769.       vi_out = XGetVisualInfo (display, VisualClassMask, &vi_in, &out_count);
  770.       if (vi_out)
  771.     {       /* choose the 'best' one, if multiple */
  772.       int i, best;
  773.       for (i = 0, best = 0; i < out_count; i++)
  774.         if (vi_out [i].depth > vi_out [best].depth)
  775.           best = i;
  776.       visual = vi_out [best].visual;
  777.       screen_no = vi_out [best].screen;
  778.       visual_depth = vi_out [best].depth;
  779.       XFree((char *) vi_out);
  780.     }
  781.       else
  782.     {
  783.       fprintf (stderr,
  784.            "%s: Visual type %s not available on display %s.\n",
  785.            progname, visual_class_name (), DisplayString (display));
  786.       visual = DefaultVisual (display, screen_no);
  787.       visual_class = visual->class;
  788.       fprintf (stderr, "\tUsing default visual %s.\n",
  789.            visual_class_name ());
  790.     }
  791.     }
  792.   screen = ScreenOfDisplay (display, screen_no);
  793. }
  794.  
  795.  
  796. void
  797. allocate_colors (fg, bg, bd)
  798.      char *fg, *bg, *bd;
  799. {
  800.   if (visual == DefaultVisual (display, screen_no) || visual_class == -1)
  801.     cmap = DefaultColormapOfScreen (screen);
  802.   else
  803.     cmap = XCreateColormap (display, RootWindow (display, screen_no), 
  804.                 visual, AllocNone);
  805.  
  806.   if (do_cycle)
  807.     {
  808.       unsigned long plane_masks;
  809.       unsigned long pixels [2];
  810.  
  811.       if (visual_class == StaticGray ||
  812.       visual_class == StaticColor ||
  813.       visual_class == TrueColor)
  814.     {
  815.       fprintf (stderr,
  816.            (!root_p
  817.             ? "%s: -cycle is incompatible with visual %s.\n"
  818.     : "%s: -cycle is incompatible with the root window's visual, %s.\n"),
  819.            progname, visual_class_name ());
  820.       do_cycle = 0;
  821.       allocate_colors (fg, bg, bd);
  822.     }
  823.       else if (XAllocColorCells (display, cmap, False,
  824.                  &plane_masks, 0, pixels, 2))
  825.     {
  826.       fg_color.pixel = pixels [0];
  827.       bg_color.pixel = pixels [1];
  828.       XParseColor (display, cmap, fg, &fg_color);
  829.       XParseColor (display, cmap, bg, &bg_color);
  830.       fg_color.flags = bg_color.flags = DoRed | DoGreen | DoBlue;
  831.       XStoreColor (display, cmap, &fg_color);
  832.       XStoreColor (display, cmap, &bg_color);
  833.     }
  834.       else
  835.     {
  836.       fprintf (stderr,
  837.   "%s: couldn't allocate two read-write color cells on visual %s (0x%x).\n",
  838.            progname, visual_class_name ());
  839.       do_cycle = 0;
  840.       allocate_colors (fg, bg, bd);
  841.     }
  842.     }
  843.   else
  844.     {
  845.       if (! XParseColor (display, cmap, fg, &fg_color))
  846.     {
  847.       fprintf (stderr, "%s: can't parse color %s; using black\n",
  848.            progname, fg);
  849.       fg_color.pixel = BlackPixelOfScreen (screen);
  850.     }
  851.       else if (! XAllocColor (display, cmap, &fg_color))
  852.     {
  853.       fprintf (stderr,
  854.            "%s: couldn't allocate color \"%s\", using black\n",
  855.            progname, fg);
  856.       fg_color.pixel = BlackPixelOfScreen (screen);
  857.     }
  858.  
  859.       if (! XParseColor (display, cmap, bg, &bg_color))
  860.     {
  861.       fprintf (stderr, "%s: can't parse color %s; using white\n",
  862.            progname, bg);
  863.       bg_color.pixel = WhitePixelOfScreen (screen);
  864.     }
  865.       else if (! XAllocColor (display, cmap, &bg_color))
  866.     {
  867.       fprintf (stderr,
  868.            "%s: couldn't allocate color \"%s\", using white\n",
  869.            progname, bg);
  870.       bg_color.pixel = WhitePixelOfScreen (screen);
  871.     }
  872.     }
  873.  
  874.   /* Set border color to something reasonable in the colormap */
  875.   if (! XParseColor (display, cmap, bd, &bd_color))
  876.     {
  877.       fprintf (stderr, "%s: can't parse color %s; using white\n",
  878.            progname, bd);
  879.       bd_color.pixel = WhitePixelOfScreen (screen);
  880.     }
  881.   else if (! XAllocColor (display, cmap, &bd_color))
  882.     {
  883.       fprintf (stderr, "%s: couldn't allocate color \"%s\", using white\n",
  884.            progname, bd);
  885.       bd_color.pixel = WhitePixelOfScreen (screen);
  886.     }
  887. }
  888.  
  889.  
  890. void
  891. wander ()
  892. {
  893.   wander_x += wander_delta_x;
  894.   if (wander_x == character_width || wander_x == 0)
  895.     {
  896.       wander_delta_x = -wander_delta_x;
  897.       wander_y += wander_delta_y;
  898.       if (wander_y == character_height || wander_y == 0)
  899.     wander_delta_y = -wander_delta_y;
  900.     }
  901. }
  902.  
  903.  
  904. void 
  905. draw_colon ()
  906. {
  907.   Pixmap glyph = button_down ? slash : colon;
  908.   XCopyPlane (display, glyph, pixmap, pixmap_draw_gc,
  909.           0, 0, character_width, character_height,
  910.           x_offsets [1] + character_width, 0, 1);
  911.   if (! minutes_only)
  912.     XCopyPlane (display, glyph, pixmap, pixmap_draw_gc,
  913.         0, 0, character_width, character_height,
  914.         x_offsets [3] + character_width, 0, 1);
  915.   XStoreName (display, window, button_down ? hacked_version : window_title);
  916. }
  917.  
  918.  
  919. void
  920. initialize_window (fg, bg, bd, bw, geom, def_geom)
  921.      char *fg, *bg, *bd;
  922.      int bw;
  923.      char *geom, *def_geom;
  924. {
  925.   XSetWindowAttributes attributes;
  926.   unsigned long attribute_mask;
  927.   XClassHint class_hints;
  928.   XSizeHints size_hints;
  929.   XGCValues gcvalues;
  930.   int ndigits = minutes_only ? 4 : 6;
  931.   int i;
  932.  
  933.   allocate_colors (fg, bg, bd);
  934.  
  935. #ifdef SHAPE
  936.   if (! (root_p || full_screen_p))
  937.     {
  938.       int shape_event_base, shape_error_base;
  939.       if (do_shape && !XShapeQueryExtension (display,
  940.                          &shape_event_base,
  941.                          &shape_error_base))
  942.     {
  943.       fprintf (stderr, "%s: no shape extension on this display\n",
  944.            progname);
  945.       do_shape = 0;
  946.     }
  947.     }
  948. #endif
  949.  
  950.   attribute_mask = CWBackPixel | CWEventMask;
  951.   attributes.event_mask = ( KeyPressMask | ButtonPressMask |
  952.                 ButtonReleaseMask | StructureNotifyMask |
  953.                 ExposureMask );
  954.   attributes.background_pixel = bg_color.pixel;
  955.   class_hints.res_name = progname;
  956.   class_hints.res_class = app_class;
  957.   size_hints.flags = PMinSize;
  958.   size_hints.min_width = x_offsets [ndigits-1] + character_width + 1;
  959.   size_hints.min_height = character_height + 1;
  960.  
  961.   /* Call XGeometry twice so that we can merge partial geometry specifications
  962.    * from the command line with those from the resource files.
  963.    *
  964.    * The resource file specifies def_geom, e.g., def_geom = "200x30-100".
  965.    * The command line specifies geom, e.g., geom = "+0-0".
  966.    * These should be merged to produce "200x30+0-0", and i should flag the
  967.    * fields set in this specification so that those set in neither can be
  968.    * set to their hard-coded defaults.
  969.    */
  970.   if (full_screen_p)
  971.     {
  972.       size_hints.x  = size_hints.y  = -50;
  973.       size_hints.width = WidthOfScreen (screen) + 100;
  974.       size_hints.height = HeightOfScreen (screen) + 100;
  975.       size_hints.flags = USSize|USPosition;
  976.     }
  977.   else
  978.     {
  979.       i = XGeometry (display, screen_no, def_geom, 0, bw,
  980.              1, 1, 0, 0, &size_hints.x, &size_hints.y,
  981.              &size_hints.width, &size_hints.height);
  982.       
  983.       i |= XGeometry (display, screen_no, geom, def_geom, bw,
  984.               1, 1, 0, 0, &size_hints.x, &size_hints.y,
  985.               &size_hints.width, &size_hints.height);
  986.       
  987.       if (i & (XValue|YValue))
  988.     size_hints.flags |= USPosition;
  989.       else
  990.     size_hints.x = size_hints.y = 0;
  991.       
  992.       if (i & (WidthValue|HeightValue))
  993.     size_hints.flags |= USSize;
  994.       else
  995.     {
  996.       size_hints.width = x_offsets [ndigits-1] + character_width + 20;
  997.       size_hints.height = character_height + 20;
  998.     }
  999.     }
  1000.  
  1001.   attributes.colormap = cmap;
  1002.   attributes.border_pixel = bd_color.pixel; /* must have correct depth! */
  1003.   attribute_mask |= CWColormap | CWBorderPixel;
  1004.  
  1005.   if (root_p)
  1006.     {
  1007.       window = RootWindowOfScreen (screen);
  1008.       XSetWindowBackground (display, window, bg_color.pixel);
  1009.       XClearWindow (display, window);
  1010.     }
  1011.   else
  1012.     window = XCreateWindow (display, DefaultRootWindow (display),
  1013.                 size_hints.x, size_hints.y,
  1014.                 size_hints.width, size_hints.height, bw,
  1015.                 visual_depth, InputOutput, /* class */
  1016.                 visual, attribute_mask, &attributes);
  1017.  
  1018.   /* Center stuff in window correctly when first created */
  1019.   {
  1020.     int width = x_offsets [minutes_only ? 3 : 5] + character_width;
  1021.     if (root_p)
  1022.       {
  1023.     window_offset_x = (WidthOfScreen (screen) - width) / 2;
  1024.     window_offset_y = (HeightOfScreen (screen) - character_height) / 2;
  1025.       }
  1026.     else
  1027.       {
  1028.     XWindowAttributes wa;
  1029.     XGetWindowAttributes (display, window, &wa);
  1030.     window_offset_x = (wa.width - width) / 2;
  1031.     window_offset_y = (wa.height - character_height) / 2;
  1032.       }
  1033.   }
  1034.  
  1035.   XStoreName (display, window, window_title);
  1036.   XSetClassHint (display, window, &class_hints);
  1037.   XSetWMNormalHints (display, window, &size_hints);
  1038.  
  1039.   pixmap = XCreatePixmap (display, window,
  1040.               x_offsets [ndigits-1] + character_width + 1,
  1041.               character_height + 1, 1);
  1042.  
  1043.   gcvalues.foreground = fg_color.pixel;
  1044.   gcvalues.background = bg_color.pixel;
  1045.   gcvalues.function = GXcopy;
  1046.   gcvalues.graphics_exposures = False;
  1047.   window_draw_gc = XCreateGC (display, window,
  1048.                   GCForeground | GCBackground | GCFunction |
  1049.                   GCGraphicsExposures,
  1050.                   &gcvalues);
  1051.   gcvalues.foreground = bg_color.pixel;
  1052.   gcvalues.background = fg_color.pixel;
  1053.   window_erase_gc= XCreateGC (display, window,
  1054.                   GCForeground | GCBackground | GCFunction |
  1055.                   GCGraphicsExposures,
  1056.                   &gcvalues);
  1057.   gcvalues.foreground = 1;
  1058.   gcvalues.background = 0;
  1059.   pixmap_draw_gc = XCreateGC (display, pixmap,
  1060.                   GCForeground | GCBackground | GCFunction |
  1061.                   GCGraphicsExposures,
  1062.                   &gcvalues);
  1063.   gcvalues.foreground = 0;
  1064.   gcvalues.background = 1;
  1065.   pixmap_erase_gc= XCreateGC (display, pixmap,
  1066.                   GCForeground | GCBackground | GCFunction |
  1067.                   GCGraphicsExposures,
  1068.                   &gcvalues);
  1069.   
  1070.   XFillRectangle (display, pixmap, pixmap_erase_gc,
  1071.           0, 0, x_offsets [ndigits-1] + character_width + 1,
  1072.           character_height + 1);
  1073.  
  1074.   XMapWindow (display, window);
  1075.   XFlush (display);
  1076.  
  1077.   if (be_a_pig)
  1078.     fill_pig_cache (display, window, current_frames [0]);
  1079.  
  1080.   for (i = 0; i < ndigits; i++)
  1081.     {
  1082.       last_time_digits [i] = -1;
  1083.       set_current_scanlines (current_frames [i], clear_frame);
  1084.     }
  1085.   XFillRectangle (display, window, window_erase_gc,
  1086.           0, 0, x_offsets [ndigits-1] + character_width,
  1087.           character_height + 1);
  1088.   draw_colon ();
  1089. }
  1090.  
  1091.  
  1092. void
  1093. hsv_to_rgb (h,s,v, r,g,b)
  1094.      int h;            /* 0 - 360   */
  1095.      double s, v;        /* 0.0 - 1.0 */
  1096.      unsigned short *r, *g, *b;    /* 0 - 65535 */
  1097. {
  1098.   double H, S, V, R, G, B;
  1099.   double p1, p2, p3;
  1100.   double f;
  1101.   int i;
  1102.   S = s; V = v;
  1103.   H = (h % 360) / 60.0;
  1104.   i = H;
  1105.   f = H - i;
  1106.   p1 = V * (1 - S);
  1107.   p2 = V * (1 - (S * f));
  1108.   p3 = V * (1 - (S * (1 - f)));
  1109.   if      (i == 0) { R = V;  G = p3; B = p1; }
  1110.   else if (i == 1) { R = p2; G = V;  B = p1; }
  1111.   else if (i == 2) { R = p1; G = V;  B = p3; }
  1112.   else if (i == 3) { R = p1; G = p2; B = V;  }
  1113.   else if (i == 4) { R = p3; G = p1; B = V;  }
  1114.   else           { R = V;  G = p1; B = p2; }
  1115.   *r = R * 65535;
  1116.   *g = G * 65535;
  1117.   *b = B * 65535;
  1118. }
  1119.  
  1120. void
  1121. cycle_colors ()
  1122. {
  1123.   static int hue_tick;
  1124.   hsv_to_rgb (hue_tick,
  1125.           1.0, 1.0,
  1126.           &fg_color.red, &fg_color.green, &fg_color.blue);
  1127.   hsv_to_rgb ((hue_tick + 180) % 360,
  1128.           1.0, 1.0,
  1129.           &bg_color.red, &bg_color.green, &bg_color.blue);
  1130.   hue_tick = (hue_tick+1) % 360;
  1131.   XStoreColor (display, cmap, &fg_color);
  1132.   XStoreColor (display, cmap, &bg_color);
  1133. }
  1134.  
  1135. #define TICK_INTERVAL    80000L    /* 8/100th second */
  1136. #define SEC_INTERVAL  1000000L    /* 1 second */
  1137.  
  1138. #ifdef VMS
  1139.  
  1140. #define SEC_DELTA  "0000 00:00:01.00"
  1141. #define TICK_DELTA "0000 00:00:00.08"
  1142. static int bin_sec_delta[2], bin_tick_delta[2], deltas_set = 0;
  1143.  
  1144. void
  1145. set_deltas ()
  1146. {
  1147.   int status;
  1148.   extern int SYS$BINTIM ();
  1149.   $DESCRIPTOR (str_sec_delta,  SEC_DELTA);
  1150.   $DESCRIPTOR (str_tick_delta, TICK_DELTA);
  1151.   
  1152.   if (!deltas_set)
  1153.     {
  1154.       status = SYS$BINTIM (&str_sec_delta, &bin_sec_delta);
  1155.       if (!(status & 1))
  1156.     {
  1157.       printf ("Cannot convert delta time ");
  1158.       printf (SEC_DELTA);
  1159.       printf ("; status code = %d\n", status);
  1160.       exit (status);
  1161.     }
  1162.       status = SYS$BINTIM (&str_tick_delta, &bin_tick_delta);
  1163.       if (!(status & 1))
  1164.     {
  1165.       printf ("Cannot convert delta time ");
  1166.       printf (TICK_DELTA);
  1167.       printf ("; status code = %d\n", status);
  1168.       exit (status);
  1169.     }
  1170.       deltas_set = 1;
  1171.     }
  1172. }
  1173.  
  1174. void
  1175. clock_usleep (usecs)
  1176.      unsigned long usecs;
  1177. {
  1178.   int status, *bin_delta;
  1179.   extern int SYS$SCHWDK (), SYS$HIBER (); 
  1180.   
  1181.   if (!deltas_set) set_deltas ();
  1182.   bin_delta = (usecs == TICK_INTERVAL) ? &bin_tick_delta : &bin_sec_delta;
  1183.   status = SYS$SCHDWK (0, 0, bin_delta, 0);
  1184.   if ((status & 1)) (void) SYS$HIBER ();
  1185. }
  1186.  
  1187. #else /* ! VMS */
  1188.  
  1189. #ifdef NO_SELECT
  1190.   /* If you don't have select() or usleep(), I guess you lose...
  1191.      Maybe you have napms() instead?  Let me know.
  1192.    */
  1193. #define clock_usleep(usecs) usleep((usecs))
  1194.  
  1195. #else /* ! NO_SELECT */
  1196.  
  1197. void
  1198. clock_usleep (usecs)
  1199.      unsigned long usecs;
  1200. {
  1201.   struct timeval tv;
  1202.   tv.tv_sec  = usecs / 1000000L;
  1203.   tv.tv_usec = usecs % 1000000L;
  1204.   (void) select (0, 0, 0, 0, &tv);
  1205. }
  1206.  
  1207. #endif /* ! NO_SELECT */
  1208. #endif /*! VMS */
  1209.  
  1210. #define TICK_SLEEP()    clock_usleep (TICK_INTERVAL) /* 8/100th second */
  1211. #define SEC_SLEEP()    clock_usleep (SEC_INTERVAL)  /* 1 second */
  1212.  
  1213. /* The above pair of routines can't be implemented using a combination of
  1214.    sleep() and usleep() if you system has them, because they interfere with
  1215.    each other: using sleep() will cause later calls to usleep() to fail.
  1216.    The select() version is more efficient anyway (fewer system calls.)
  1217.  */
  1218.  
  1219.  
  1220. void
  1221. run_clock ()
  1222. {
  1223.   int ndigits = minutes_only ? 4 : 6;
  1224.   event_loop (display, window); /* wait for initial mapwindow event */
  1225.   while (1) {
  1226.     int n, tick;
  1227.     long clock;
  1228.     int different_minute;
  1229.  
  1230.     clock = fill_time_digits ();
  1231.  
  1232.     different_minute = (time_digits [3] != last_time_digits [3]);
  1233.  
  1234.     for (n = 0; n < ndigits; n++)
  1235.       if (time_digits [n] == last_time_digits [n])
  1236.     target_frames [n] = 0;
  1237.       else if (time_digits [n] == -1)
  1238.     target_frames [n] = clear_frame;
  1239.       else
  1240.     target_frames [n] = base_frames [time_digits [n]];
  1241.  
  1242.     if (twelve_hour_time && target_frames [0] && time_digits [0] == 0)
  1243.       {
  1244.     target_frames [0] = clear_frame;
  1245.     time_digits [0] = -1;
  1246.       }
  1247.     if (time_digits [0] == -1 && last_time_digits [0] == -1)
  1248.       target_frames [0] = 0;
  1249.     if (last_time_digits [0] == -2) /* evil hack for 12<->24 mode toggle */
  1250.       target_frames [0] = clear_frame;
  1251.  
  1252.     for (tick = 9; tick >= 0; tick--) {
  1253.       int j;
  1254.       if (do_cycle) cycle_colors ();
  1255.       for (j = 0; j < ndigits; j++)
  1256.     {
  1257.       if (target_frames [j])
  1258.         {
  1259.           if (be_a_pig && time_digits [j] == 0 &&
  1260.           last_time_digits [j] != -1)
  1261.         {
  1262.           Pixmap p =
  1263.             memory_pig_zeros [last_time_digits [j] - 1] [tick];
  1264.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1265.                   character_width, character_height,
  1266.                   x_offsets [j], 0, 1);
  1267.         }
  1268.           else if (be_a_pig && last_time_digits [j] == 0 &&
  1269.                time_digits [j] != -1)
  1270.         {
  1271.           Pixmap p =
  1272.             memory_pig_zeros [time_digits [j] - 1] [9 - tick];
  1273.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1274.                   character_width, character_height,
  1275.                   x_offsets [j], 0, 1);
  1276.         }
  1277.           else if (be_a_pig && last_time_digits [j] != -1 &&
  1278.                time_digits [j] == last_time_digits [j] + 1)
  1279.         {
  1280.           Pixmap p =
  1281.             memory_pig_digits [last_time_digits [j] - 1] [9 - tick];
  1282.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1283.                   character_width, character_height,
  1284.                   x_offsets [j], 0, 1);
  1285.         }
  1286.           /* This case isn't terribly common, but we've got it cached,
  1287.          so why not use it. */
  1288.           else if (be_a_pig && time_digits [j] != -1 &&
  1289.                last_time_digits [j] == time_digits [j] + 1)
  1290.         {
  1291.           Pixmap p =
  1292.             memory_pig_digits [time_digits [j] - 1] [tick];
  1293.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1294.                   character_width, character_height,
  1295.                   x_offsets [j], 0, 1);
  1296.         }
  1297.  
  1298.           else if (be_a_pig > 1 && last_time_digits [j] != -1 &&
  1299.                time_digits [j] == ((last_time_digits [j] + 2) % 10))
  1300.         {
  1301.           Pixmap p =
  1302.             total_oinker_digits [last_time_digits [j] - 1] [9 - tick];
  1303.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1304.                   character_width, character_height,
  1305.                   x_offsets [j], 0, 1);
  1306.         }
  1307.           else if (be_a_pig > 1 && time_digits [j] != -1 &&
  1308.                last_time_digits [j] == ((time_digits [j] + 2) % 10))
  1309.         {
  1310.           Pixmap p =
  1311.             total_oinker_digits [time_digits [j] - 1] [tick];
  1312.           XCopyPlane (display, p, pixmap, pixmap_draw_gc, 0, 0,
  1313.                   character_width, character_height,
  1314.                   x_offsets [j], 0, 1);
  1315.         }
  1316.           else
  1317.         {
  1318. #if 0
  1319.           if (be_a_pig && tick == 9)
  1320.             fprintf (stderr, "cache miss!  %d -> %d\n",
  1321.                  last_time_digits [j], time_digits [j]);
  1322. #endif
  1323.           /* sends 20 bytes */
  1324.           XFillRectangle (display, pixmap, pixmap_erase_gc,
  1325.                   x_offsets [j], 0, character_width + 1,
  1326.                   character_height);
  1327.           draw_frame (current_frames [j], pixmap, pixmap_draw_gc,
  1328.                   x_offsets [j]);
  1329.         }
  1330.           if (tick)
  1331.         one_step (current_frames[j], target_frames [j], tick);
  1332.         }
  1333.     }
  1334.       /* sends up to 1k in non-pig mode */
  1335.       flush_segment_buffer (pixmap, pixmap_draw_gc);
  1336.       
  1337. #ifdef SHAPE
  1338.       if (do_shape)
  1339.     XShapeCombineMask (display, window, ShapeBounding, 0, 0,
  1340.                pixmap, ShapeSet);
  1341.       else
  1342. #endif
  1343.     /* sends 28 bytes */
  1344.     XCopyPlane (display, pixmap, window, window_draw_gc, 0, 0, 
  1345.             x_offsets [ndigits-1] + character_width,
  1346.             character_height,
  1347.             window_offset_x +(wander_x - (character_width / 2)),
  1348.             window_offset_y +(wander_y - (character_height / 2)),
  1349.             1);
  1350.       XFlush (display);
  1351.       TICK_SLEEP ();
  1352.     }
  1353.     bcopy (time_digits, last_time_digits, sizeof (time_digits));
  1354.  
  1355.     /* sends up to 1k in non-pig mode */
  1356.     flush_segment_buffer (pixmap, pixmap_draw_gc);
  1357.  
  1358. #ifdef SHAPE
  1359.     if (do_shape)
  1360.       XShapeCombineMask (display, window, ShapeBounding, 0, 0,
  1361.              pixmap, ShapeSet);
  1362.     else
  1363. #endif
  1364.  
  1365.       if ((root_p || full_screen_p) && different_minute)
  1366.     {
  1367.       XClearWindow (display, window);
  1368.       wander ();
  1369.     }
  1370.  
  1371.       /* sends 28 bytes */
  1372.       XCopyPlane (display, pixmap, window, window_draw_gc, 0, 0,
  1373.           x_offsets [ndigits-1] + character_width, character_height,
  1374.           window_offset_x +(wander_x - (character_width / 2)),
  1375.           window_offset_y +(wander_y - (character_height / 2)),
  1376.           1);
  1377.  
  1378.     if (minutes_only)
  1379.       {
  1380.     /* This is slightly sleazy: when in no-seconds mode, wake up
  1381.        once a second to cycle colors and poll for events, until the
  1382.        minute has expired.  We could do this with an interrupt timer
  1383.        or by selecting on the display file descriptor, but that would
  1384.        be more work.
  1385.      */
  1386.     long now = time ((time_t *) 0);
  1387.     struct tm *tm = localtime (&now);
  1388.     long target = now + (60 - tm->tm_sec);
  1389.     while ((now = time ((time_t *) 0)) <= target)
  1390.       {
  1391.         /* if event_loop returns true, we need to go and repaint stuff
  1392.            right now, instead of waiting for the minute to elapse.
  1393.            */
  1394.         if (event_loop (display, window))
  1395.           break;
  1396.  
  1397.         if (now == target-1)    /* the home stretch; sync up */
  1398.           TICK_SLEEP ();
  1399.         else
  1400.           {
  1401.         if (do_cycle) cycle_colors ();
  1402.         SEC_SLEEP ();
  1403.           }
  1404.       }
  1405.       }
  1406.     else
  1407.       {
  1408.     /* Sync to the second-strobe by repeatedly sleeping for about
  1409.        1/10th second until time() returns a different value.
  1410.      */
  1411.     long now = clock;
  1412.     while (clock == now)
  1413.       {
  1414.         TICK_SLEEP ();
  1415.         now = time ((time_t *) 0);
  1416.         event_loop (display, window);
  1417.       }
  1418.       }
  1419.   }
  1420. }
  1421.  
  1422.  
  1423. int
  1424. event_loop (display, window)
  1425.      Display *display;
  1426.      Window window;
  1427. {
  1428.   static int mapped_p = 0;
  1429.   int wait_for_buttonup = button_down;
  1430.   int redraw_p = 0;
  1431.   XSync (display, False);
  1432.   while (XPending (display) || !(mapped_p || root_p) ||
  1433.      (wait_for_buttonup && button_down))
  1434.     {
  1435.       XEvent event;
  1436.       XNextEvent (display, &event);
  1437.       switch (event.xany.type)
  1438.     {
  1439.     case KeyPress:
  1440.       {
  1441.         KeySym keysym;
  1442.         XComposeStatus status;
  1443.         char buffer [10];
  1444.         int nbytes = XLookupString (&event.xkey, buffer, sizeof (buffer),
  1445.                     &keysym, &status);
  1446.         if (nbytes == 0) break;
  1447.         if (nbytes != 1) buffer [0] = 0;
  1448.         switch (buffer [0]) {
  1449.         case 'q': case 'Q': case 3:
  1450. #ifdef VMS
  1451.           exit (1);
  1452. #else
  1453.           exit (0);
  1454. #endif
  1455.         case ' ':
  1456.           twelve_hour_time = !twelve_hour_time;
  1457.           if (twelve_hour_time && time_digits [0] == 0)
  1458.         last_time_digits [0] = -2; /* evil hack */
  1459.           redraw_p = 1;
  1460.           break;
  1461.         case '0': case '1': case '2': case '3': case '4': case '5':
  1462.         case '6': case '7': case '8': case '9': case '-':
  1463.           if (event.xkey.state)
  1464.         {
  1465.           test_hack = buffer [0];
  1466.           redraw_p = 1;
  1467.           break;
  1468.         }
  1469.         default:
  1470.           XBell (display, 0);
  1471.           break;
  1472.         }
  1473.       }
  1474.       break;
  1475.     case ButtonPress:
  1476.       button_down |= (1<<event.xbutton.button);
  1477.       if (! wait_for_buttonup) draw_colon ();
  1478.       redraw_p = 1;
  1479.       break;
  1480.     case ButtonRelease:
  1481.       button_down &= ~(1<<event.xbutton.button);
  1482.       if (! button_down) draw_colon ();
  1483.       redraw_p = 1;
  1484.       break;
  1485.     case ConfigureNotify:
  1486.       {
  1487.         int width = x_offsets [minutes_only ? 3 : 5] + character_width;
  1488.         window_offset_x = (event.xconfigure.width - width) / 2;
  1489.         window_offset_y = (event.xconfigure.height - character_height) / 2;
  1490.         XClearWindow (display, window);
  1491.         redraw_p = 1;
  1492.       }
  1493.       break;
  1494.     case Expose:
  1495.     case MapNotify:
  1496.       mapped_p = 1;
  1497.       redraw_p = 1;
  1498.       break;
  1499.     case UnmapNotify:
  1500.       mapped_p = 0;
  1501.       break;
  1502.     }
  1503.     }
  1504.   return redraw_p;
  1505. }
  1506.  
  1507.  
  1508. void
  1509. usage ()
  1510. {
  1511.   fprintf (stderr, "%s\n\
  1512. usage: %s [ switches ]\nwhere switches contain\n\n\
  1513.   -12                Display twelve hour time (default).\n\
  1514.   -24                Display twenty-four hour time.\n\
  1515.   -seconds            Display seconds (default).\n\
  1516.   -noseconds            Don't display seconds.\n\
  1517.   -cycle            Do color-cycling.\n\
  1518.   -nocycle            Don't do color-cycling (default).\n\
  1519.   -display <host:dpy>        The display to run on.\n\
  1520.   -visual <visual-class>    The visual to use.\n\
  1521.   -geometry <geometry>        Size and position of window.\n\
  1522.   -foreground or -fg <color>    Foreground color (default black).\n\
  1523.   -background or -bg <color>    Background color (default white).\n\
  1524.   -reverse or -rv        Swap foreground and background.\n\
  1525.   -borderwidth or -bw <int>    Border width.\n\
  1526.   -bd or -border <color>    Border color.\n\
  1527.   -title <string>        Window title.\n\
  1528.   -name <string>        Resource-manager class name (XDaliClock).\n\
  1529. ", version, progname);
  1530. #if defined (BUILTIN_FONT) && defined (BUILTIN_FONT_2)
  1531.   fprintf (stderr, "\
  1532.   -font    or -fn <font>        Name of an X font to use, or the string\n\
  1533.                 \"BUILTIN\", meaning to use the large builtin\n\
  1534.                 font (this is the default), or \"BUILTIN2\",\n\
  1535.                 meaning to use the even larger builtin font.\n\
  1536.   -builtin            Same as -font BUILTIN.\n\
  1537.   -builtin2            Same as -font BUILTIN2.\n\
  1538. ");
  1539. #else /* ! (BUILTIN_FONT && BUILTIN_FONT_2) */
  1540. #if (defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2))
  1541.   fprintf (stderr, "\
  1542.   -font    or -fn <font>        Name of an X font to use, or the string\n\
  1543.                 \"BUILTIN\", meaning to use the large builtin\n\
  1544.                 font (this is the default).\n\
  1545.   -builtin            Same as -font BUILTIN.\n\
  1546. ");
  1547. #else /* ! (BUILTIN_FONT || BUILTIN_FONT_2) */
  1548.   fprintf (stderr, "\
  1549.   -font    or -fn <font>        Name of an X font to use.\n\
  1550. ");
  1551. #endif /* ! (BUILTIN_FONT || BUILTIN_FONT_2) */
  1552. #endif /* ! (BUILTIN_FONT && BUILTIN_FONT_2) */
  1553.   fprintf (stderr, "\
  1554.   -memory <high|medium|low>    Tune the memory versus bandwidth consumption;\n\
  1555.                 default is \"low\".\n\
  1556.   -oink                Same as -memory medium.\n\
  1557.   -oink-oink            Same as -memory high.\n\
  1558. ");
  1559. #ifdef SHAPE
  1560.   fprintf (stderr, "\
  1561.   -shape            Use the Shape extension if available.\n\
  1562.   -noshape            Don't.\n");
  1563. #endif
  1564. #if !(defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2)) || !defined (SHAPE)
  1565.   fprintf (stderr, "\n");
  1566. # ifndef BUILTIN_FONT
  1567.    fprintf(stderr, "This version has been compiled without the builtin fonts");
  1568. # endif
  1569. # ifndef SHAPE
  1570. #  ifndef BUILTIN_FONT
  1571.   fprintf (stderr, ", or support for the\nShape Extension.\n");
  1572. #  else
  1573.   fprintf (stderr, "\
  1574. This version has been compiled without support for the Shape Extension.\n");
  1575. #  endif
  1576. # else
  1577.   fprintf (stderr, ".\n");
  1578. # endif
  1579. #endif
  1580.   exit (-1);
  1581. }
  1582.  
  1583. void
  1584. hack_version ()
  1585. {
  1586.   char *src = version;
  1587.   char *dst = hacked_version = (char *) malloc (strlen (version) + 1);
  1588. #define digitp(x) (('0' <= (x)) && ((x) <= '9'))
  1589.   while (*src)
  1590.     if (!strncmp ("Copyright (c)", src, 13))
  1591.       *dst++ = '\251', src += 13;
  1592.     else if (digitp (src[0]) && digitp (src[1]) && digitp (src[2]) &&
  1593.          digitp (src[3]) && src[4] == ',' && src[5] == ' ')
  1594.       src += 6;
  1595.     else
  1596.       *dst++ = *src++;
  1597.   *dst = 0;
  1598. }
  1599.  
  1600. char *
  1601. get_string (res_name, res_class)
  1602.      char *res_name, *res_class;
  1603. {
  1604.   XrmValue value;
  1605.   char    *type, *p;
  1606.   char full_name [1024], full_class [1024];
  1607.   strcpy (full_name, progname);
  1608.   strcat (full_name, ".");
  1609.   strcat (full_name, res_name);
  1610.   strcpy (full_class, app_class);
  1611.   strcat (full_class, ".");
  1612.   strcat (full_class, res_class);
  1613.   if (XrmGetResource (db, full_name, full_class, &type, &value))
  1614.     {
  1615.       char *str = (char *) malloc (value.size + 1);
  1616.       strncpy (str, (char *) value.addr, value.size);
  1617.       str [value.size] = 0;
  1618.       return str;
  1619.     }
  1620.   return 0;
  1621. }
  1622.  
  1623. int 
  1624. get_boolean (res_name, res_class)
  1625.      char *res_name, *res_class;
  1626. {
  1627.   char *tmp, buf [100];
  1628.   char *s = get_string (res_name, res_class);
  1629.   if (! s) return 0;
  1630.   for (tmp = buf; *s; s++)
  1631.     *tmp++ = isupper (*s) ? _tolower (*s) : *s;
  1632.   *tmp = 0;
  1633.  
  1634.   if (!strcmp (buf, "on") || !strcmp (buf, "true") || !strcmp (buf, "yes"))
  1635.     return 1;
  1636.   if (!strcmp (buf,"off") || !strcmp (buf, "false") || !strcmp (buf,"no"))
  1637.     return 0;
  1638.   fprintf (stderr, "%s: %s must be boolean, not %s.\n",
  1639.        progname, res_name, buf);
  1640.   return 0;
  1641. }
  1642.  
  1643. void
  1644. get_piggedness ()
  1645. {
  1646.   char *tmp, buf [100];
  1647.   char *s = get_string ("memory", "Memory");
  1648.   be_a_pig = 0;
  1649.   if (! s) return;
  1650.   for (tmp = buf; *s; s++)
  1651.     *tmp++ = isupper (*s) ? _tolower (*s) : *s;
  1652.   *tmp = 0;
  1653.  
  1654.   if (!strcmp (buf, "high") || !strcmp (buf, "hi") || !strcmp (buf, "sleazy"))
  1655.     be_a_pig = 2;
  1656.   else if (!strcmp (buf, "medium") || !strcmp (buf, "med"))
  1657.     be_a_pig = 1;
  1658.   else if (!strcmp (buf, "low") || !strcmp (buf, "lo"))
  1659.     be_a_pig = 0;
  1660.   else
  1661.     fprintf (stderr,
  1662.       "%s: memory must be \"high\", \"medium\", or \"low\", not \"%s\".\n",
  1663.          progname, buf);
  1664. }
  1665.  
  1666. int 
  1667. get_integer (res_name, res_class)
  1668.      char *res_name, *res_class;
  1669. {
  1670.   int val;
  1671.   char *s = get_string (res_name, res_class);
  1672.   if (!s) return 0;
  1673.   if (1 == sscanf (s, " %d %c", &val))
  1674.     return val;
  1675.   fprintf (stderr, "%s: %s must be an integer, not %s.\n",
  1676.        progname, res_name, s);
  1677.   return 0;
  1678. }
  1679.  
  1680.  
  1681. int 
  1682. get_time_mode (res_name, res_class)
  1683.      char *res_name, *res_class;
  1684. {
  1685.   char *s = get_string (res_name, res_class);
  1686.   if (! s) return 1;
  1687.   if (!strcmp (s, "12")) return 1;
  1688.   if (!strcmp (s, "24")) return 0;
  1689.   fprintf (stderr, "%s: %s must be \"12\" or \"24\", not \"%s\".\n",
  1690.        progname, res_name, s);
  1691.   return 1;
  1692. }
  1693.  
  1694.  
  1695. void
  1696. get_date_mode ()
  1697. {
  1698.   char *tmp, buf [100];
  1699.   char *s = get_string ("datemode", "DateMode");
  1700.   date_format = MMDDYY;
  1701.   if (! s) return;
  1702.   for (tmp = buf; *s; s++)
  1703.     *tmp++ = isupper (*s) ? _tolower (*s) : *s;
  1704.   *tmp = 0;
  1705.   if (!strcmp (buf, "mmddyy") || !strcmp (buf, "mm/dd/yy") ||
  1706.       !strcmp (buf, "mm-dd-yy"))
  1707.     date_format = MMDDYY;
  1708.   else if (!strcmp (buf, "ddmmyy") || !strcmp (buf, "dd/mm/yy") ||
  1709.        !strcmp (buf, "dd-mm-yy"))
  1710.     date_format = DDMMYY;
  1711.   else if (!strcmp (buf, "yymmdd") || !strcmp (buf, "yy/mm/dd") ||
  1712.        !strcmp (buf, "yy-mm-dd"))
  1713.     date_format = YYMMDD;
  1714.   else if (!strcmp (buf, "yyddmm") || !strcmp (buf, "yy/dd/mm") ||
  1715.        !strcmp (buf, "yy-dd-mm"))
  1716.     date_format = YYDDMM;
  1717.   else if (!strcmp (buf, "mmyydd") || !strcmp (buf, "mm/yy/dd") ||
  1718.        !strcmp (buf, "mm-yy-dd"))
  1719.     date_format = MMYYDD;
  1720.   else if (!strcmp (buf, "ddyymm") || !strcmp (buf, "dd/yy/mm") ||
  1721.        !strcmp (buf, "dd-yy-mm"))
  1722.     date_format = DDYYMM;
  1723.   else 
  1724.     fprintf (stderr,
  1725.       "%s: DateMode must be \"MM/DD/YY\", \"DD/MM/YY\", etc; not \"%s\"\n",
  1726.          progname, buf);
  1727. }
  1728.  
  1729.  
  1730. void
  1731. get_visual_class ()
  1732. {
  1733.   char *tmp, buf [100];
  1734.   char *s = get_string ("visual", "Visual");
  1735.   visual_class = (do_cycle ? PseudoColor : -1);
  1736.   if (! s) return;
  1737.   for (tmp = buf; *s; s++)
  1738.     *tmp++ = isupper (*s) ? _tolower (*s) : *s;
  1739.   *tmp = 0;
  1740.   if      (!strcmp (buf, "staticgray"))  visual_class = StaticGray;
  1741.   else if (!strcmp (buf, "staticcolor")) visual_class = StaticColor;
  1742.   else if (!strcmp (buf, "truecolor"))   visual_class = TrueColor;
  1743.   else if (!strcmp (buf, "grayscale"))   visual_class = GrayScale;
  1744.   else if (!strcmp (buf, "pseudocolor")) visual_class = PseudoColor;
  1745.   else if (!strcmp (buf, "directcolor")) visual_class = DirectColor;
  1746.   else
  1747.     fprintf (stderr, "%s: Unrecognized visual type \"%s\".\n", progname, buf);
  1748. }
  1749.  
  1750.  
  1751. main (argc, argv)
  1752.      int argc;
  1753.      char **argv;
  1754. {
  1755.   char *display_name = 0;
  1756.   char *tmp, *font, *fg, *bg, *bd, *geom, *def_geom;
  1757.   int i, bw, rv;
  1758.   XrmDatabase cmdDB;
  1759. #ifndef __STDC__
  1760.   char *getenv ();
  1761. #endif
  1762.  
  1763.   progname = argv [0];
  1764. #ifdef VMS
  1765.   while (tmp = rindex (progname, ']'))
  1766.     progname = tmp+1;
  1767.   if (tmp = rindex (progname, '.'))
  1768.     *tmp = '\0';
  1769. #else
  1770.   if (tmp = rindex (progname, '/'))
  1771.     progname = tmp+1;
  1772. #endif
  1773.   
  1774.   XrmParseCommand (&db, xdaliclock_options, num_options, progname, &argc, argv);
  1775.   if (argc > 1)
  1776.     {
  1777.       if (strcmp (argv [1], "-help"))
  1778.     fprintf (stderr, "%s: unknown option \"%s\"\n\n", progname, argv [1]);
  1779.       usage ();
  1780.     }
  1781.  
  1782.   app_class = "XDaliClock";
  1783.   tmp = get_string ("name", "Name");
  1784.   if (tmp) app_class = tmp;
  1785.  
  1786.   display_name = get_string ("display", "Display");
  1787.   if (! display_name) display_name = (char *) getenv ("DISPLAY");
  1788. #ifndef VMS
  1789.   if (!display_name)  display_name = ":0";
  1790. #endif
  1791.   display = XOpenDisplay (display_name);
  1792.   if (! display)
  1793.     {
  1794.       fprintf(stderr, "%s: couldn't open display %s\n", progname, display_name);
  1795.       exit (-1);
  1796.     }
  1797.  
  1798.   cmdDB = db;
  1799.   db = XrmGetStringDatabase (xdaliclockDefaults);
  1800.   
  1801.   if (tmp = XResourceManagerString (display))
  1802.     XrmMergeDatabases (XrmGetStringDatabase (tmp), &db);
  1803.  
  1804.   if (getenv ("XENVIRONMENT") &&
  1805.       access ((char *) getenv ("XENVIRONMENT"), R_OK) == 0)
  1806.     XrmMergeDatabases (XrmGetFileDatabase ((char *) getenv ("XENVIRONMENT")),
  1807.                &db);
  1808.   else
  1809.     {
  1810. #ifdef VMS
  1811.       char *fn;
  1812.       fn = "DECW$SYSTEM_DEFAULTS:XDALICLOCK.DAT";
  1813.       if (access (fn, R_OK) == 0)
  1814.     XrmMergeDatabases (XrmGetFileDatabase (fn), &db);
  1815.       fn = "DECW$USER_DEFAULTS:XDALICLOCK.DAT";
  1816.       if (access (fn, R_OK) == 0)
  1817.     XrmMergeDatabases (XrmGetFileDatabase (fn), &db);
  1818.       fn = "DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT";
  1819.       if (access (fn, R_OK) == 0)
  1820.     XrmMergeDatabases (XrmGetFileDatabase (fn), &db);
  1821. #else
  1822.       char fn [1000];
  1823.       sprintf (fn, "%s/.Xdefaults", getenv("HOME"));
  1824.       if (access (fn, R_OK) == 0)
  1825.     XrmMergeDatabases (XrmGetFileDatabase (fn), &db);
  1826. #endif
  1827.     }
  1828.  
  1829.   /* Get geometry resource from the resource files EXCLUDING command line */
  1830.   def_geom = get_string ("geometry", "Geometry");
  1831.  
  1832.   XrmMergeDatabases (cmdDB, &db);
  1833.  
  1834.   fg    = get_string ("foreground", "Foreground");
  1835.   bg    = get_string ("background", "Background");
  1836.   bd    = get_string ("border", "Border");
  1837.   bw    = get_integer ("borderWidth", "BorderWidth");
  1838.   geom = get_string ("geometry", "Geometry"); /* command line part */
  1839.   rv    = get_boolean ("reverseVideo", "ReverseVideo");
  1840.   font    = get_string ("font", "Font");
  1841.   window_title    = get_string ("title", "Title");
  1842.   do_cycle    = get_boolean ("cycle", "Cycle");
  1843.   minutes_only    = !get_boolean ("seconds", "Seconds");
  1844.   twelve_hour_time = get_time_mode ("mode", "Mode");
  1845.   root_p    = get_boolean ("onroot", "OnRoot");
  1846.   full_screen_p    = get_boolean ("fullScreen", "FullScreen");
  1847.   get_visual_class ();
  1848.   get_date_mode ();
  1849.   get_piggedness ();
  1850. #if defined (BUILTIN_FONT) || defined (BUILTIN_FONT_2)
  1851.   use_builtin_font = !font;
  1852.   if (!strcasecmp (font, "BUILTIN")) use_builtin_font = 1;
  1853.   if (!strcasecmp (font, "BUILTIN2")) use_builtin_font = 2;
  1854. #endif /* BUILTIN_FONT || BUILTIN_FONT_2 */
  1855. #ifdef SHAPE
  1856.   if (full_screen_p || root_p)
  1857.     do_shape = 0;
  1858.   else
  1859.     do_shape = get_boolean ("shape", "Shape");
  1860. #endif
  1861.  
  1862.   if (! fg) fg = ((bg && strcasecmp (bg, "white")) ? "white" : "black");
  1863.   if (! bg) bg = ((fg && strcasecmp (fg, "white")) ? "white" : "black");
  1864.   if (! bd) bd = fg;
  1865.  
  1866.   if (rv) tmp = fg, fg = bg, bg = tmp;
  1867.  
  1868.   pick_visual_and_screen ();
  1869.   initialize (font);
  1870.   initialize_window (fg, bg, bd, bw, geom, def_geom);
  1871.   hack_version ();
  1872.   wander_x = character_width / 2;
  1873.   wander_y = character_height / 2;
  1874.   wander_delta_x = wander_delta_y = 1;
  1875.   run_clock ();
  1876. }
  1877.