Logo Search packages:      
Sourcecode: dclock version File versions  Download package

Dclock.c

/*
 * Dclock.c (v.2.0) -- a digital clock widget.
 * Copyright (c) 1988 Dan Heller <argv@sun.com>
 * Modifications 2/93 by Tim Edwards <tim@sinh.stanford.edu>
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <values.h>
#include <math.h>
#include <time.h>
#include <wait.h>
#include <errno.h>
#include <X11/IntrinsicP.h>
#include <X11/Xos.h>
#include <X11/StringDefs.h>
#include "DclockP.h"

static void
    Initialize(), Resize(), ResizeNow(), Realize(), Destroy(), Redisplay(),
    GetGC(), invert_bitmap(), build_segments(), timeout(), toggle_bell(),
    toggle_reverse_video(), toggle_scroll(), toggle_seconds(), show_bell(),
    toggle_military_time(), toggle_date(), make_number(), make_number_one(),
    set_alarm(),
    show_date(), show_alarm(), scroll_time(), toggle_alarm(), outline_digit(),
    toggle_fade(), toggle_tails(), increase_slope(), decrease_slope(),
    widen_segment(), thin_segment(), increase_space(), decrease_space(),
    toggle_blink(), print_help(), print_dump(), playbell(), toggle_dateup();

static void XfFillArc(), XfFillPolygon();

/* some definitions */

#define BORDER          5
#define CLOCK_WIDTH     220
#define CLOCK_HEIGHT    80
#define DATE_FMT  "%A, %B %d, %Y"
#define when            break;case
#define otherwise break;default

#define sign(a)         ((a) < 0.0 ? -1 : 1)
#define abs(a)          ((a) < 0 ? -(a) : (a))

/* the x-value of the colon as measured from the window x=0 */

#define cx (int)(digit_w + (w->dclock.miltime ? digit_w : \
      w->dclock.space_factor * 2 * digit_w + segxwidth))

/* A few variables and initial values */

static Boolean SetValues(), show_time();
static Dimension winwidth = CLOCK_WIDTH;
static Dimension winheight = CLOCK_HEIGHT;
static Boolean false = False;
static Boolean true = True;
static int fade_rate = 50;
static float y_ratio;
static float sslope = 6.0;
static float sspacer = 0.09;
static float smallrat = 0.67;
static float secgap = 0.3;
static float widfac = 0.13;
static Pixmap old_pix[4];
static int old_digs[4];
static struct tm before;
static char *saved_date;
static cur_position;    /* outline current digit for setting alarm */
static struct { int hrs, mins; } Alarm;
static int TopOffset = 0;

/* define what keys do what when pressed in the window */

static char defaultTranslations[] =
    "<Key>b:            toggle-bell()           \n\
     <Key>j:            toggle-scroll()         \n\
     <Key>f:            toggle-fade()           \n\
     <Key>s:            toggle-seconds()  \n\
     <Key>r:            toggle-reverse-video()  \n\
     <Key>colon:  toggle-blink()          \n\
     <Key>m:            toggle-military-time()  \n\
     <Key>d:            toggle-date()           \n\
     <Key>u:            toggle-dateup()         \n\
     <Key>t:            toggle-tails()          \n\
     <Key>a:            toggle-alarm()          \n\
     <Key>h:            print-help()            \n\
     Shift<Key>slash:   print-help()            \n\
     <Key>v:            print-dump()            \n\
     <Key>+:            widen-segment()         \n\
     <Key>-:            thin-segment()          \n\
     <Key>slash:  slope-increase()  \n\
     <Key>backslash:    slope-decrease()  \n\
     Shift<Key>comma:   space-decrease()  \n\
     Shift<Key>period:  space-increase()  \n\
     <BtnDown>:         set-alarm()";

static XtActionsRec actionsList[] = {
    { "toggle-bell",          toggle_bell       },
    { "toggle-scroll",        toggle_scroll           },
    { "toggle-fade",          toggle_fade       },
    { "toggle-seconds",       toggle_seconds          },
    { "toggle-reverse-video", toggle_reverse_video    },
    { "toggle-blink",         toggle_blink            },
    { "toggle-military-time", toggle_military_time    },
    { "toggle-date",          toggle_date       },
    { "toggle-dateup",        toggle_dateup           },
    { "toggle-tails",         toggle_tails            },
    { "toggle-alarm",         toggle_alarm            },
    { "widen-segment",        widen_segment           },
    { "thin-segment",         thin_segment            },
    { "slope-decrease",       decrease_slope          },
    { "slope-increase",       increase_slope          },
    { "space-decrease",       decrease_space          },
    { "space-increase",       increase_space          },
    { "set-alarm",            set_alarm         },
    { "print-help",           print_help        },
    { "print-dump",           print_dump        },
};

/* Initialization values for all of the X resources */

static XtResource resources[] = {
    { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
      XtOffset(Widget,core.width), XtRDimension, (caddr_t)&winwidth },
    { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
      XtOffset(Widget,core.height), XtRDimension, (caddr_t)&winheight },
    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
        XtOffset(DclockWidget,dclock.foreground), XtRString, "Chartreuse"},
    { XtNled_off, XtCForeground, XtRPixel, sizeof(Pixel),
        XtOffset(DclockWidget,dclock.led_off), XtRString, "DarkGreen"},
    { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
        XtOffset(DclockWidget,dclock.background), XtRString, "DarkSlateGray"},
    { XtNtails, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.tails), XtRBoolean, (caddr_t)&true},
    { XtNfade, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.fade), XtRBoolean, (caddr_t)&true},
    { XtNfadeRate, XtCTime, XtRInt, sizeof (int),
      XtOffset(DclockWidget,dclock.fade_rate), XtRInt, (caddr_t)&fade_rate},
    { XtNscroll, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.scroll), XtRBoolean, (caddr_t)&false},
    { XtNdisplayTime, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.display_time), XtRBoolean, (caddr_t)&true},
    { XtNalarm, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.alarm), XtRBoolean, (caddr_t)&false},
    { XtNalarmTime, XtCTime, XtRString, sizeof (char *),
      XtOffset(DclockWidget,dclock.alarm_time), XtRString, "00:00" },
    { XtNalarmPersist, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.alarm_persist), XtRBoolean, (caddr_t)&false},
    { XtNbell, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.bell), XtRBoolean, (caddr_t)&false},
    { XtNseconds, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.seconds), XtRBoolean, (caddr_t)&false},
    { XtNblink, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.blink), XtRBoolean, (caddr_t)&true},
    { XtNmilitaryTime, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.miltime), XtRBoolean, (caddr_t)&false},
    { XtNutcTime, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.utc), XtRBoolean, (caddr_t)&false},
    { XtNdate, XtCString, XtRString, sizeof (String),
      XtOffset(DclockWidget,dclock.date_fmt), XtRString, NULL},
    { XtNdateUp, XtCBoolean, XtRBoolean, sizeof (Boolean),
      XtOffset(DclockWidget,dclock.dateup), XtRBoolean, (caddr_t)&false},
    { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
      XtOffset(DclockWidget,dclock.font), XtRString, "fixed"},
#ifdef XFT_SUPPORT
    { XftNfontName, "fontName", XtRString, sizeof(String),
      XtOffset(DclockWidget,dclock.xftfontname), XtRString, "charter"},
#endif
    { XtNangle, "Slope", XtRFloat, sizeof(float),
      XtOffset(DclockWidget,dclock.angle), XtRFloat, (caddr_t)&sslope},
    { XtNwidthFactor, "Ratio", XtRFloat, sizeof(float),
      XtOffset(DclockWidget,dclock.width_factor), XtRFloat, (caddr_t)&widfac},
    { XtNsmallRatio, "Ratio", XtRFloat, sizeof(float),
      XtOffset(DclockWidget,dclock.small_ratio), XtRFloat,(caddr_t)&smallrat},
    { XtNsecondGap, "Ratio", XtRFloat, sizeof(float),
      XtOffset(DclockWidget,dclock.sec_gap), XtRFloat, (caddr_t)&secgap}, 
    { XtNspaceFactor, "Ratio", XtRFloat, sizeof(float),
      XtOffset(DclockWidget,dclock.space_factor), XtRFloat,(caddr_t)&sspacer},
    { XtNalarmFile, "alarmFile", XtRString, sizeof(String),
      XtOffset(DclockWidget,dclock.alarmfile), XtRString, (String)NULL},
    { XtNbellFile, "bellFile", XtRString, sizeof(String),
      XtOffset(DclockWidget,dclock.bellfile), XtRString, (String)NULL},
    { XtNaudioPlay, "audioPlay", XtRString, sizeof(String),
      XtOffset(DclockWidget,dclock.audioplay), XtRString, "/usr/bin/play"},
};

/* Define the Dclock widget */

DclockClassRec dclockClassRec = {
    { /* core fields */
    /* superclass       */    &widgetClassRec,
    /* class_name       */    "Dclock",
    /* widget_size            */    sizeof(DclockRec),
    /* class_initialize       */    NULL,
    /* class_part_initialize  */    NULL,
    /* class_inited           */    FALSE,
    /* initialize       */    Initialize,
    /* initialize_hook        */    NULL,
    /* realize                */    Realize,
    /* actions                */    actionsList,
    /* num_actions            */    XtNumber(actionsList),
    /* resources        */    resources,
    /* resource_count         */    XtNumber(resources),
    /* xrm_class        */    NULLQUARK,
    /* compress_motion        */    TRUE,
    /* compress_exposure      */    TRUE,
    /* compress_enterleave    */    TRUE,
    /* visible_interest       */    FALSE,
    /* destroy                */    Destroy,
    /* resize                 */    Resize,
    /* expose                 */    Redisplay,
    /* set_values       */    SetValues,
    /* set_values_hook        */    NULL,
    /* set_values_almost      */    XtInheritSetValuesAlmost,
    /* get_values_hook        */    NULL,
    /* accept_focus           */    NULL,
    /* version                */    XtVersion,
    /* callback_private       */    NULL,
    /* tm_table               */    defaultTranslations,
    /* query_geometry         */    NULL,
    }
};
WidgetClass dclockWidgetClass = (WidgetClass) &dclockClassRec;


#ifdef NO_USLEEP
#define usleep(x) { struct timeval st_delay;                \
                    st_delay.tv_usec = (x); st_delay.tv_sec = 0;  \
                    select(32, NULL, NULL, NULL, &st_delay); }
#endif


/*
 * These stipples give different densities for the
 * different stages of fading.
 */
static unsigned char stpl_1_8th[] =
{
    0x80, 0x80, 0x08, 0x08, 0x80, 0x80, 0x08, 0x08,
    0x80, 0x80, 0x08, 0x08, 0x80, 0x80, 0x08, 0x08,
    0x80, 0x80, 0x08, 0x08, 0x80, 0x80, 0x08, 0x08,
    0x80, 0x80, 0x08, 0x08, 0x80, 0x80, 0x08, 0x08
};

static unsigned char stpl_1_4th[] =
{
    0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22,
    0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22,
    0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22,
    0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22
};

static unsigned char stpl_3_8ths[] =
{
    0xA2, 0xA2, 0x15, 0x15, 0xA8, 0xA8, 0x45, 0x45,
    0x2A, 0x2A, 0x51, 0x51, 0x8A, 0x8A, 0x54, 0x54,
    0xA2, 0xA2, 0x15, 0x15, 0xA8, 0xA8, 0x45, 0x45,
    0x2A, 0x2A, 0x51, 0x51, 0x8A, 0x8A, 0x54, 0x54
};

static unsigned char stpl_one_half[] =
{
    0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
    0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
    0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
    0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA
};

/*
 * fade_stip[] eventually contains the pixmaps used for each
 * iteration of fading (initialized in Initialize()).
 * If smooth color variations are used instead, then the
 * colormap index values are held in fadevector[].
 */
#define FADE_ITER 8
static Pixmap fade_stip[FADE_ITER];
int fadevector[FADE_ITER];
int bsave = 0;
Boolean use_stipple;

#define MAX_PTS         6     /* max # of pts per segment polygon */
#define NUM_SEGS  7     /* number of segments in a digit */

/*
 * These constants give the bit positions for the segmask[]
 * digit masks.
 */
#define TOP       0
#define MIDDLE          1
#define BOTTOM          2
#define TOP_LEFT  3
#define BOT_LEFT  4
#define TOP_RIGHT 5
#define BOT_RIGHT 6

#define msk(i)          (1 << (i))

/*
 * segmask[n] contains a bitmask of the segments which
 * should be lit for digit 'n'.
 */
int segmask[11] =
{
/* 0 */ msk(TOP) | msk(TOP_RIGHT) | msk(BOT_RIGHT) | msk(BOTTOM)
        | msk(BOT_LEFT) | msk(TOP_LEFT),
/* 1 */     msk(TOP_RIGHT) | msk(BOT_RIGHT),
/* 2 */ msk(TOP) | msk(TOP_RIGHT) | msk(MIDDLE) | msk(BOT_LEFT)
        | msk(BOTTOM),
/* 3 */ msk(TOP) | msk(TOP_RIGHT) | msk(MIDDLE) | msk(BOT_RIGHT)
        | msk(BOTTOM),
/* 4 */ msk(TOP_LEFT) | msk(MIDDLE) | msk(TOP_RIGHT) | msk(BOT_RIGHT),
/* 5 */ msk(TOP) | msk(TOP_LEFT) | msk(MIDDLE) | msk(BOT_RIGHT)
        | msk(BOTTOM),
/* 6 */ msk(TOP_LEFT) | msk(BOT_LEFT) | msk(MIDDLE) | msk(BOTTOM)
        | msk(BOT_RIGHT),
/* 7 */ msk(TOP) | msk(TOP_RIGHT) | msk(BOT_RIGHT),
/* 8 */ msk(TOP_LEFT) | msk(BOT_LEFT) | msk(MIDDLE) | msk(TOP)
        | msk(BOTTOM) | msk(TOP_RIGHT) | msk(BOT_RIGHT),
/* 9 */ msk(TOP) | msk(TOP_LEFT) | msk(TOP_RIGHT) | msk(MIDDLE)
        | msk(BOT_RIGHT),
/* blank */ 0
};

/*
 * num_segment_pts indicates the number of vertices on the
 * polygon that describes a segment
 */
static int num_segment_pts = 6;
float slope_add, segxwidth, sxw;

/* Clipping masks to prevent angled digits from obscuring one another */

Region clip_norm, clip_small, clip_colon; 
XPoint clip_pts[5];

00337 typedef struct {
   float x;
   float y;
} XfPoint;

typedef XfPoint segment_pts[NUM_SEGS][MAX_PTS];

segment_pts tiny_segment_pts;
segment_pts norm_segment_pts;

/* ARGSUSED */
static void
Initialize (request, new)
DclockWidget   request;
DclockWidget   new;
{
    int i, n;
    Display *dpy = XtDisplay(new);
    Drawable root;
    Colormap cmap = DefaultColormap (dpy, DefaultScreen(dpy));
    XColor cvcolor, cvfg, cvbg;
    float frac;

    root = RootWindow(dpy, DefaultScreen(dpy));

    if (new->dclock.alarm_time) {
      if (sscanf(new->dclock.alarm_time, "%2d:%2d",
            &Alarm.hrs, &Alarm.mins) != 2 || Alarm.hrs >= 24 ||
            Alarm.mins >= 60) {
          XtWarning("Alarm Time is in incorrect format.");
          new->dclock.alarm_time = "00:00";
          Alarm.hrs = Alarm.mins = 0;
      }
      new->dclock.alarm_time =
          strcpy(XtMalloc(strlen(new->dclock.alarm_time)+1),
                           new->dclock.alarm_time);
    }

    /* control allowable features */

    if (new->dclock.fade) new->dclock.scroll = False;
    if (new->dclock.angle < 1.0) new->dclock.angle = 1.0;    
    if (new->dclock.angle > 2 * winheight) new->dclock.angle = 2 * winheight;
    if (new->dclock.space_factor > 0.8) new->dclock.space_factor = 0.8;
    if (new->dclock.space_factor < 0.0) new->dclock.space_factor = 0.0;
    if (new->dclock.small_ratio < 0.1) new->dclock.small_ratio = 0.1;
    if (new->dclock.small_ratio > 1.0) new->dclock.small_ratio = 1.0;
    if (new->dclock.width_factor > 0.24) new->dclock.width_factor = 0.24;
    if (new->dclock.width_factor < 0.01) new->dclock.width_factor = 0.01;
    if (new->dclock.sec_gap < 0.0) new->dclock.sec_gap = 0.0;

#ifdef XFT_SUPPORT
    new->dclock.xftfont = XftFontOpen(dpy, DefaultScreen(dpy),
            XFT_FAMILY, XftTypeString, new->dclock.xftfontname,
            XFT_SIZE, XftTypeDouble, ((float)new->core.height / 6.0) - 4.0,
            NULL);
    new->dclock.xftdraw = NULL;
#endif

    GetGC(new);

    /* Get RGB values for the foreground and background */

    cvfg.pixel = new->dclock.foreground;
    XQueryColor(dpy, cmap, &cvfg);
    cvbg.pixel = new->dclock.led_off;
    XQueryColor(dpy, cmap, &cvbg);

    /* Attempt to initialize a color vector of FADE_ITER points between */
    /* foreground and background */

    use_stipple = False;
    for (i = 0; i < FADE_ITER; i++) {
       frac = (float)i / (float)(FADE_ITER - 1);
       /* gamma correction */
       frac = pow(frac, 0.5);

       cvcolor.green = cvbg.green + (int)((float)(cvfg.green - cvbg.green) * frac);
       cvcolor.blue = cvbg.blue + (int)((float)(cvfg.blue - cvbg.blue) * frac);
       cvcolor.red = cvbg.red + (int)((float)(cvfg.red - cvbg.red) * frac);

       if (!XAllocColor(dpy, cmap, &cvcolor)) {
        use_stipple = True;
        break;
       }
       fadevector[i] = cvcolor.pixel;
    }

    if (use_stipple) {
       fade_stip[1] = XCreateBitmapFromData(dpy, root, stpl_1_8th, 16, 16);
       fade_stip[2] = XCreateBitmapFromData(dpy, root, stpl_1_4th, 16, 16);
       fade_stip[3] = XCreateBitmapFromData(dpy, root, stpl_3_8ths, 16, 16);
       fade_stip[4] = XCreateBitmapFromData(dpy, root, stpl_one_half, 16, 16);
       invert_bitmap(stpl_1_8th, 16, 16);
       invert_bitmap(stpl_1_4th, 16, 16);
       invert_bitmap(stpl_3_8ths, 16, 16);
       fade_stip[5] = XCreateBitmapFromData(dpy, root, stpl_3_8ths, 16, 16);
       fade_stip[6] = XCreateBitmapFromData(dpy, root, stpl_1_4th, 16, 16);
       fade_stip[7] = XCreateBitmapFromData(dpy, root, stpl_1_8th, 16, 16);

       for (n = 1; n != FADE_ITER; ++n)
         if (!fade_stip[n])
         {
             fprintf(stderr, "dclock: Couldn't create stipple!\n");
             exit(1);
         }
    }

    if (!new->dclock.date_fmt || !*new->dclock.date_fmt)
      saved_date = DATE_FMT;
    if (new->dclock.date_fmt && !*new->dclock.date_fmt)
      new->dclock.date_fmt = NULL;
    if (new->dclock.dateup && new->dclock.date_fmt)
#ifdef XFT_SUPPORT
      TopOffset = new->core.height / 6;
#else
      TopOffset = new->dclock.font->ascent + new->dclock.font->descent;
#endif

    else
      TopOffset = 0;

    /* Shouldn't be necessary, but play it safe anyway */
    for (n = 0; n < 10; n++)
    {
      new->dclock.digits[n] = 0;
      new->dclock.tiny_digits[n] = 0;
    }
    new->dclock.digit_one[0] = new->dclock.digit_one[1] = 0;
    new->dclock.colon[0] = new->dclock.colon[1] = 0;

    new->dclock.interval_id = (XtIntervalId)NULL;
    new->dclock.punt_resize = (XtIntervalId)NULL;

}

static void
GetGC(w)
DclockWidget w;
{ XGCValues       xgcv;
    XtGCMask      gc_mask =
                GCGraphicsExposures | GCFont | GCForeground | GCBackground;

    xgcv.font = w->dclock.font->fid;
    xgcv.graphics_exposures = FALSE;
    xgcv.foreground = w->dclock.foreground;
    xgcv.background = w->dclock.background;

    w->dclock.foreGC = XtGetGC ((Widget) w, gc_mask, &xgcv);

    xgcv.foreground = w->dclock.background;
    xgcv.background = w->dclock.foreground;

    w->dclock.backGC = XtGetGC ((Widget) w, gc_mask, &xgcv);
}


static void
invert_bitmap(bm, h, w)
unsigned char *bm;
int h, w;
{
    int i, *wp;

    for (wp = (int *) bm, i = (h*w) / (8*sizeof(int)); i != 0; --i, ++wp)
      *wp = ~(*wp);
}

static void
Realize (w, valueMask, attrs)
Widget w;
XtValueMask *valueMask;
XSetWindowAttributes *attrs;
{
    Display *dp = XtDisplay(w); 
    DclockWidget dw = (DclockWidget)w;
    int sc = DefaultScreen(dp);
    Visual *vs = DefaultVisual(dp, sc);;

    *valueMask |= CWBitGravity;
    attrs->bit_gravity = ForgetGravity;
    vs = DefaultVisual(dp, sc);
    XtCreateWindow(w, InputOutput, (Visual *)CopyFromParent, *valueMask, attrs);

#ifdef XFT_SUPPORT
    if (dw->dclock.xftdraw == NULL) {
      XColor color;
      Colormap cm = DefaultColormap(dp, sc);

      dw->dclock.xftdraw = XftDrawCreate(dp, XtWindow(w), vs, cm);

      color.pixel = dw->dclock.foreground;
      XQueryColor(dp, cm, &color);
      dw->dclock.xftfg.color.red = color.red;
      dw->dclock.xftfg.color.green = color.green;
      dw->dclock.xftfg.color.blue = color.blue;
      dw->dclock.xftfg.color.alpha = 0xffff;
      dw->dclock.xftfg.pixel = color.pixel;

      color.pixel = dw->dclock.background;
      XQueryColor(dp, cm, &color);
      dw->dclock.xftbg.color.red = color.red;
      dw->dclock.xftbg.color.green = color.green;
      dw->dclock.xftbg.color.blue = color.blue;
      dw->dclock.xftbg.color.alpha = 0xffff;
      dw->dclock.xftbg.pixel = color.pixel;
    }
#endif
    ResizeNow(w);
}

static void
Destroy (w)
DclockWidget w;
{
    int n;

    /* Be nice and free up memory before exiting. */

    if (w->dclock.interval_id != (XtIntervalId)NULL)
      XtRemoveTimeOut(w->dclock.interval_id);
    if (w->dclock.punt_resize != (XtIntervalId)NULL)
      XtRemoveTimeOut(w->dclock.punt_resize);
    XtReleaseGC ((Widget)w, w->dclock.foreGC);
    XtReleaseGC ((Widget)w, w->dclock.backGC);
    for (n = 0; n < 10; n++) {
      XFreePixmap(XtDisplay(w), w->dclock.digits[n]);
      XFreePixmap(XtDisplay(w), w->dclock.tiny_digits[n]);
    }
    XFreePixmap(XtDisplay(w), w->dclock.digit_one[0]);
    XFreePixmap(XtDisplay(w), w->dclock.digit_one[1]);
    if (w->dclock.colon[0])
      XFreePixmap(XtDisplay(w), w->dclock.colon[0]);
    if (w->dclock.colon[1])
      XFreePixmap(XtDisplay(w), w->dclock.colon[1]);
    XDestroyRegion(clip_norm);
    XDestroyRegion(clip_small);
    XDestroyRegion(clip_colon);

#ifdef XFT_SUPPORT
    XftFontClose(XtDisplay(w), w->dclock.xftfont);
#endif
}

/* ARGSUSED */
static void
ResizeNow  (w)
DclockWidget    w;
{
    int i, j; 
    float digit_w, digit_h, seg_width;
    Pixmap pix;
    GC gc = w->dclock.foreGC;
    Display *dpy = XtDisplay(w);

    if (!XtIsRealized((Widget)w))
      return;

    winwidth = w->core.width;
    winheight = w->core.height;

#ifdef XFT_SUPPORT
    XftFontClose(dpy, w->dclock.xftfont);
    w->dclock.xftfont = XftFontOpen(dpy, DefaultScreen(dpy),
            XFT_FAMILY, XftTypeString, w->dclock.xftfontname,
            XFT_SIZE, XftTypeDouble, ((float)winheight / 6.0) - 4.0,
            NULL);
#endif

    y_ratio = (float)winheight / CLOCK_HEIGHT;

    if (w->dclock.date_fmt || !w->dclock.display_time || w->dclock.alarm ||
      w->dclock.bell)
      /* make win temporarily shorter so digits will fit on top of date */
#ifdef XFT_SUPPORT
      winheight -= w->core.height / 6;
#else
      winheight -= w->dclock.font->ascent + w->dclock.font->descent;
#endif

    /*
     * if the width of all segments are equal, then the width in x is the
     * segment width times the cosine of the slope angle.
     */
    sxw = (w->dclock.width_factor * 
      sqrt(1 + (w->dclock.angle)*(w->dclock.angle)))/(w->dclock.angle);

    /* height of the digit, leaving some room for a border */
    digit_h = winheight - y_ratio * BORDER*2;

    /* the amount of skew measured along x due to the slope of the digits */
    slope_add = digit_h / (w->dclock.angle); 

    /* calculate the width of the digit based on everything. */
    /*   All attributes are calculated as ratios to the digit width. */
    /*   The colon is 1/2 the digit width; */
    /*   All other ratios are widget attributes. */

    digit_w = (winwidth - slope_add * !(w->dclock.seconds) -
      (slope_add * w->dclock.small_ratio) * w->dclock.seconds) / (3.5 + 
      w->dclock.miltime + w->dclock.seconds * (2 * w->dclock.small_ratio 
      + w->dclock.sec_gap) + (2 * w->dclock.space_factor + sxw) * 
      !(w->dclock.miltime));

    /* segment widths as measured in x and y */

    segxwidth = sxw * digit_w;
    seg_width = w->dclock.width_factor * (digit_w + slope_add);
    
    /* create the clipping masks */

    clip_pts[0].x = clip_pts[4].x = 0;
    clip_pts[1].x = (int)(slope_add);
    clip_pts[2].x = (int)(slope_add + digit_w);
    clip_pts[3].x = (int)digit_w;
    clip_pts[1].y = clip_pts[2].y = 0;
    clip_pts[0].y = clip_pts[4].y = clip_pts[3].y = digit_h;
    clip_norm = XPolygonRegion(clip_pts, 5, WindingRule);
    
    for(i = 0; i < 5; i++) {
      clip_pts[i].x = (int)((float)clip_pts[i].x * w->dclock.small_ratio);
      clip_pts[i].y = (int)((float)clip_pts[i].y * w->dclock.small_ratio);
    }
    clip_small = XPolygonRegion(clip_pts, 5, WindingRule);

    clip_pts[1].x = (int)slope_add;
    clip_pts[2].x = (int)(slope_add + 0.5 * digit_w);
    clip_pts[3].x = (int)(0.5 * digit_w);
    clip_pts[0].y = clip_pts[4].y = clip_pts[3].y = digit_h;
    clip_colon = XPolygonRegion(clip_pts, 5, WindingRule);

/*  printf("segxwidth = %f\n", segxwidth);
    printf("winwidth = %d\n", winwidth);
    printf("digit_w = %f\n", digit_w);   */

    w->dclock.digit_w = digit_w;
    w->dclock.digit_h = digit_h;

    if (w->dclock.tails)
    {
      segmask[6] |=  msk(TOP);
      segmask[9] |=  msk(BOTTOM);
    }
    else
    {
      segmask[6] &=  ~msk(TOP);
      segmask[9] &=  ~msk(BOTTOM);
    }

    build_segments(w, norm_segment_pts, slope_add + digit_w, digit_h);

/*      printf("Tiny Segment Relative Points Dump:\n");
        for (i = 0; i < 7; i++) 
         for (j = 0; j < 6; j++)
            printf("digit[%d] point[%d]: x=%d, y=%d\n", i, j, 
            tiny_segment_pts[i][j].x, tiny_segment_pts[i][j].y); 
*/

    if (w->dclock.seconds)
      build_segments(w, tiny_segment_pts, w->dclock.small_ratio * (slope_add 
         + digit_w), w->dclock.small_ratio * digit_h);

    for (i = 0; i < 10; i++) {

      /* Make the big digit */

      if (w->dclock.digits[i])
          XFreePixmap(XtDisplay(w), w->dclock.digits[i]);
      w->dclock.digits[i] =
            XCreatePixmap(XtDisplay(w), XtWindow(w), (int)(slope_add + 
            digit_w), (int)digit_h, DefaultDepthOfScreen(XtScreen(w)));
      XFillRectangle(XtDisplay(w), w->dclock.digits[i], w->dclock.backGC, 
            0, 0, (int)(slope_add + digit_w), (int)digit_h);
      make_number(w, w->dclock.digits[i], gc, i, norm_segment_pts);

      /* make smaller version of this digit for use by "seconds" */

      if (w->dclock.tiny_digits[i])
          XFreePixmap(XtDisplay(w), w->dclock.tiny_digits[i]);
      if (w->dclock.seconds)
      {
          w->dclock.tiny_digits[i] =
                  XCreatePixmap(XtDisplay(w), XtWindow(w), (int)(
                              (slope_add + digit_w) * 
                              w->dclock.small_ratio),
                              (int)(w->dclock.small_ratio * digit_h),
                              DefaultDepthOfScreen(XtScreen(w)));
          XFillRectangle(XtDisplay(w), w->dclock.tiny_digits[i],
                     w->dclock.backGC, 0, 0, (int)((slope_add + 
                        digit_w) * w->dclock.small_ratio),
                        (int)(w->dclock.small_ratio * digit_h));
          make_number(w, w->dclock.tiny_digits[i], gc, i, tiny_segment_pts);
      }
      else
          w->dclock.tiny_digits[i] = (Pixmap)NULL;
    }

    /* digit_one is either the number "1" or a blank */

    if (w->dclock.digit_one[1])
      XFreePixmap(XtDisplay(w), w->dclock.digit_one[1]);
    w->dclock.digit_one[1] =
            XCreatePixmap(XtDisplay(w), XtWindow(w), (int)(slope_add +
            digit_w), (int)digit_h, DefaultDepthOfScreen(XtScreen(w)));
    XFillRectangle(XtDisplay(w), w->dclock.digit_one[1], w->dclock.backGC,
            0, 0, (int)(slope_add + digit_w), (int)digit_h);
    make_number_one(w, w->dclock.digit_one[1], gc, 1, norm_segment_pts);

    if (w->dclock.digit_one[0])
      XFreePixmap(XtDisplay(w), w->dclock.digit_one[0]);
    w->dclock.digit_one[0] =
            XCreatePixmap(XtDisplay(w), XtWindow(w), (int)(slope_add + 
            digit_w), (int)digit_h, DefaultDepthOfScreen(XtScreen(w)));
    XFillRectangle(XtDisplay(w), w->dclock.digit_one[0], w->dclock.backGC, 
            0, 0, (int)(slope_add + digit_w), (int)digit_h);
    make_number_one(w, w->dclock.digit_one[0], gc, 10, norm_segment_pts);

    /* The colon[0] area is blank (segment "off" color) */
    
    if (w->dclock.colon[0])
      XFreePixmap(XtDisplay(w), w->dclock.colon[0]);
    w->dclock.colon[0] = XCreatePixmap(XtDisplay(w), XtWindow(w),
            (int)(slope_add + 0.5 * digit_w), (int)digit_h,
            DefaultDepthOfScreen(XtScreen(w)));

    XFillRectangle(XtDisplay(w), w->dclock.colon[0],
      w->dclock.backGC, 0, 0, (int)(slope_add + 0.5 * digit_w), (int)digit_h);

    /* The additive 2 for the Arc diameter keeps the colon from looking too
       small at small display sizes. */

    XfFillArc(XtDisplay(w), w->dclock.colon[0], gc,
            (slope_add + digit_w) * 0.25 - 0.5, 0.75 * digit_h - 0.5,
            1 + seg_width/2, 0);
    XfFillArc(XtDisplay(w), w->dclock.colon[0], gc,
            slope_add * 0.75 + digit_w * 0.25 - 0.5, 0.25 * digit_h - 0.5,
            1 + seg_width/2, 0);

    /* colon[1] area has two circles */

    if (w->dclock.colon[1])
      XFreePixmap(XtDisplay(w), w->dclock.colon[1]);
    w->dclock.colon[1] = XCreatePixmap(XtDisplay(w), XtWindow(w),
            (int)(slope_add + 0.5 * digit_w), (int)digit_h,
            DefaultDepthOfScreen(XtScreen(w)));

    XFillRectangle(XtDisplay(w), w->dclock.colon[1],
      w->dclock.backGC, 0, 0, (int)(slope_add + 0.5 * digit_w), (int)digit_h);

    /* The additive 2 for the Arc diameter keeps the colon from looking too
       small at small display sizes. */

    XfFillArc(XtDisplay(w), w->dclock.colon[1], gc,
            (slope_add + digit_w) * 0.25 - 0.5, 0.75 * digit_h - 0.5,
            1 + seg_width/2, FADE_ITER);
    XfFillArc(XtDisplay(w), w->dclock.colon[1], gc,
            slope_add * 0.75 + digit_w * 0.25 - 0.5, 0.25 * digit_h - 0.5,
            1 + seg_width/2, FADE_ITER);
    XSetForeground(XtDisplay(w), gc, fadevector[FADE_ITER - 1]);

    /* to optimize scrolling information (see scroll_time()) */

    old_pix[0] = w->dclock.digits[0];
    old_pix[1] = old_pix[2] = old_pix[3] = 0;
    old_digs[0] = old_digs[1] = old_digs[2] = old_digs[3] = 0;

    if (w->dclock.date_fmt || !w->dclock.display_time || w->dclock.alarm ||
      w->dclock.bell)
      /* restore size */
      winheight = w->core.height;

    w->dclock.punt_resize = (XtIntervalId)NULL;
    Redisplay(w);
}

/* ARGSUSED */
static void
Resize  (w)
DclockWidget    w;
{
    /* Punt for 1/10 second on the resize, so that multiple events      */
    /* created by an opaque resize do not overload the processor. */

    XtAppContext app;

    app = XtWidgetToApplicationContext((Widget)w);
    if (w->dclock.punt_resize != (XtIntervalId)NULL)
      XtRemoveTimeOut(w->dclock.punt_resize);
    w->dclock.punt_resize = XtAppAddTimeOut(app,
            (unsigned long)100, ResizeNow, (XtPointer)w);
}


static void
build_segments(wi, seg_pts, w, h)
DclockWidget wi;
segment_pts seg_pts;
float w, h;
{
    XfPoint *pts;
    float spacer, hskip, fslope, bslope, midpt, seg_width, segxw;
    float invcosphi, invsinphi, invcospsi, invsinpsi, slope;
    float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy5, dy6;
    float xfactor, temp_xpts[4];

    /* define various useful constants */
 
    segxw = sxw * w;
    slope = wi->dclock.angle;
    seg_width = wi->dclock.width_factor * w;
    spacer = (float)w * wi->dclock.space_factor;
    hskip = (float)seg_width * 0.125;
    fslope = 1 / (segxw/seg_width + 1/slope);
    bslope = -1 / (segxw/seg_width - 1/slope);
    midpt = h / 2;

    /* define some trigonometric values */
    /*  phi is the forward angle separating two segments; 
      psi is the reverse angle separating two segments. */

    invsinphi = sqrt(1 + fslope * fslope) / fslope;
    invcosphi = sqrt(1 + 1/(fslope * fslope)) * fslope;
    invsinpsi = sqrt(1 + bslope * bslope) / -bslope;
    invcospsi = sqrt(1 + 1/(bslope * bslope)) * bslope;

    /* define offsets from easily-calculated points for 6 situations */

    dx1 = hskip * invsinphi / (slope/fslope - 1);
    dy1 = hskip * invcosphi / (1 - fslope/slope);
    dx2 = hskip * invsinpsi / (1 - slope/bslope);
    dy2 = hskip * invcospsi / (bslope/slope - 1);
    dx3 = hskip * invsinphi;
    dx4 = hskip * invsinpsi;
    dx5 = hskip * invsinpsi / (1 - fslope/bslope);
    dy5 = hskip * invcospsi / (bslope/fslope - 1);
    dx6 = dy5;
    dy6 = dx5;

    /* calculate some simple reference points */

    temp_xpts[0] = spacer + (h - seg_width)/slope;
    temp_xpts[1] = spacer + (h - seg_width/2)/slope + segxw/2;
    temp_xpts[2] = spacer + h/slope + segxw;
    temp_xpts[3] = temp_xpts[0] + segxw;

    xfactor = w - 2 * spacer - h / slope - segxw;

    /* calculate the digit positions */

    pts = seg_pts[TOP];
    pts[0].y = pts[1].y = 0;
    pts[0].x = temp_xpts[2] - dx3;
    pts[1].x = w - spacer - segxw + dx4;
    pts[2].y = pts[5].y = (seg_width / 2) - dy5 - dy6;
    pts[5].x = temp_xpts[1] + dx5 - dx6;
    pts[2].x = pts[5].x + xfactor;
    pts[3].y = pts[4].y = seg_width;
    pts[4].x = temp_xpts[3] + dx4;
    pts[3].x = temp_xpts[0] + xfactor - dx3; 

    pts = &(seg_pts[MIDDLE][0]);
    pts[0].y = pts[1].y = midpt - seg_width/2;
    pts[0].x = spacer + (h - pts[0].y)/slope + segxw;
    pts[1].x = pts[0].x - segxw + xfactor;
    pts[2].y = pts[5].y = midpt;
    pts[3].y = pts[4].y = midpt + seg_width/2;
    pts[5].x = spacer + (h - pts[5].y)/slope + segxw/2;
    pts[2].x = pts[5].x + xfactor;
    pts[4].x = pts[0].x - seg_width/slope;
    pts[3].x = spacer + (h - pts[3].y)/slope + xfactor;

    pts = &(seg_pts[BOTTOM][0]);
    pts[3].y = pts[4].y = h;
    pts[2].y = pts[5].y = h - (seg_width / 2) + dy5 + dy6;
    pts[0].y = pts[1].y = h - seg_width;
    pts[0].x = spacer + segxw + seg_width/slope + dx3;  
    pts[1].x = spacer + (h - pts[1].y)/slope + xfactor - dx4;
    pts[4].x = spacer + segxw - dx4;
    pts[5].x = spacer + segxw/2 + (h - pts[5].y)/slope + dx6 - dx5;
    pts[2].x = pts[5].x + xfactor;
    pts[3].x = spacer + xfactor + dx3;

    pts = &(seg_pts[TOP_LEFT][0]);
    pts[0].y = seg_width / 2 - dy6 + dy5;
    pts[1].y = seg_width + dy2;
    pts[2].y = seg_pts[MIDDLE][0].y - 2 * dy1;
    pts[3].y = seg_pts[MIDDLE][5].y - 2 * dy6;
    pts[4].y = seg_pts[MIDDLE][0].y;
    pts[5].y = seg_width - dy1;
    pts[0].x = temp_xpts[1] - dx5 - dx6;
    pts[1].x = temp_xpts[3] - dx2;
    pts[2].x = seg_pts[MIDDLE][0].x + 2 * dx1; 
    pts[3].x = seg_pts[MIDDLE][5].x - 2 * dx6;
    pts[4].x = spacer + (h - pts[4].y)/slope;
    pts[5].x = temp_xpts[0] + dx1;

    pts = &(seg_pts[BOT_LEFT][0]);
    pts[0].y = seg_pts[MIDDLE][5].y + 2 * dy5;
    pts[1].y = seg_pts[MIDDLE][4].y + 2 * dy2;
    pts[2].y = seg_pts[BOTTOM][0].y - dy1;
    pts[3].y = seg_pts[BOTTOM][5].y - 2 * dy6;
    pts[4].y = h - seg_width + dy2;
    pts[5].y = midpt + seg_width/2;
    pts[0].x = seg_pts[MIDDLE][5].x - 2 * dx5;
    pts[1].x = seg_pts[MIDDLE][4].x - 2 * dx2;
    pts[2].x = seg_pts[BOTTOM][0].x - dx3 + dx1;
    pts[3].x = seg_pts[BOTTOM][5].x - 2 * dx6;
    pts[4].x = spacer + seg_width / slope - dx2;
    pts[5].x = spacer + (midpt - seg_width/2) / slope;

    pts = &(seg_pts[TOP_RIGHT][0]);
    pts[0].y = seg_width/2 - dy5 + dy6;
    pts[1].y = seg_width - dy2;
    pts[2].y = midpt - seg_width/2;
    pts[3].y = midpt - 2 * dy5;
    pts[4].y = pts[2].y - 2 * dy2;
    pts[5].y = seg_width + dy1;
    pts[0].x = temp_xpts[1] + xfactor + dx5 + dx6;
    pts[1].x = temp_xpts[3] + xfactor + dx1;
    pts[2].x = seg_pts[MIDDLE][0].x + xfactor;
    pts[3].x = seg_pts[MIDDLE][5].x + xfactor + dx5 * 2;
    pts[4].x = seg_pts[TOP_LEFT][4].x + xfactor + dx2 * 2;
    pts[5].x = temp_xpts[0] + xfactor - dx1;

    pts = &(seg_pts[BOT_RIGHT][0]);
    pts[0].y = seg_pts[MIDDLE][2].y + 2 * dy6;
    pts[1].y = midpt + seg_width / 2;
    pts[2].y = h - seg_width + dy1;
    pts[3].y = h - (seg_width / 2) + dy6 - dy5;
    pts[4].y = h - seg_width - dy2;
    pts[5].y = seg_pts[MIDDLE][3].y + 2 * dy1;
    pts[0].x = seg_pts[MIDDLE][2].x + 2 * dx6;
    pts[1].x = seg_pts[MIDDLE][3].x + segxw;
    pts[2].x = seg_pts[BOTTOM][1].x + dx4 + segxw - dx1;
    pts[3].x = seg_pts[BOTTOM][2].x + 2 * dx5;
    pts[4].x = seg_pts[BOTTOM][1].x + dx4 + dx2;
    pts[5].x = seg_pts[MIDDLE][3].x - 2 * dx1;

}

/*------------------------------------------------------------------------*/
/* find the squared length of a wire (or distance between two points in   */
/* user space).                                                           */
/*------------------------------------------------------------------------*/
     
float sqwirelen(userpt1, userpt2)
  XfPoint *userpt1, *userpt2;
{
  float xdist, ydist;

  xdist = userpt2->x - userpt1->x;
  ydist = userpt2->y - userpt1->y;
  return (xdist * xdist + ydist * ydist);
}

/* Point-to-line segment distance measure */

float find_mindist(x, y, seglist, num_segs)
  float x, y;
  XfPoint *seglist;
  int num_segs;
{
   int i;
   double fd, mind = MAXFLOAT;
   float a, b, c, d, frac;
   float protod;
   XfPoint *pt1, *pt2, testpt;
      
   testpt.x = x;
   testpt.y = y;
      
   for (i = 0; i < num_segs; i++) {
      pt1 = seglist + i;
      pt2 = seglist + ((i + 1) % num_segs);
      c = sqwirelen(pt1, pt2);
      a = sqwirelen(pt1, &testpt);
      b = sqwirelen(pt2, &testpt);
      frac = a - b;
      if (frac >= c) d = b;
      else if (-frac >= c) d = a;
      else {
         protod = c + a - b;
         d = a - ((protod * protod) / (c * 4));
      }
      if (d < 0)  /* due to roundoff error */
       fd = 0;    
      else
       fd = sqrt((double)d);
      if (fd < mind) mind = fd;
   }  
   return mind;
}     

/*------------------------*/
/* Simple insideness test */
/*------------------------*/

int test_insideness(x, y, seglist, num_segs)
  float x, y;
  XfPoint *seglist;
  int num_segs;
{
   int i, stval = 0;
   XfPoint *pt1, *pt2;
   float stdir;
   for (i = 0; i < num_segs; i++) {
      pt1 = seglist + i;
      pt2 = seglist + ((i + 1) % num_segs);
      stdir = (pt2->x - pt1->x) * (y - pt1->y)
             - (pt2->y - pt1->y) * (x - pt1->x);
      stval += sign(stdir);
   }
   return (abs(stval) == num_segs) ? 1 : 0;
}

/*------------------------------------------------------*/
/* Antialiasing circle-filling routine                */
/*------------------------------------------------------*/

static void
XfFillArc(dpy, pix, gc, center_x, center_y, radius, fgi)
   Display *dpy;
   Drawable pix;
   GC gc;
   float center_x, center_y, radius;
   int fgi;
{
   int i, j, color;
   float minx, miny, maxx, maxy, dist, xdist, ydist, rsq;

   minx = center_x - radius;
   miny = center_y - radius;
   maxx = center_x + radius;
   maxy = center_y + radius;
   rsq = radius * radius;

   /* scan through pixel centers in region */

   for (j = (int)(miny - 1.0); j < (int)(maxy + 1.0); j++) {
      for (i = (int)(minx - 1.0); i < (int)(maxx + 1.0); i++) {
       xdist = center_x - ((float)i + 0.5);
       ydist = center_y - ((float)j + 0.5);
       dist = radius - (float)sqrt(xdist * xdist + ydist * ydist);

       if (dist > 0) {
          if ((dist >= 1.0) && (fgi > 0)) color = fadevector[fgi - 1];
          else color = fadevector[(int)(dist * fgi)];

          XSetForeground(dpy, gc, color);
          XDrawPoint(dpy, pix, gc, i, j);
       }
      }
   }
}

/*------------------------------------------------------*/
/* Wrapper for XFillPolygon, using floats for points  */
/* Antialiasing goes here, if you have a good fill    */
/* algorithm for it. . .                        */
/*------------------------------------------------------*/

static void
XfFillPolygon(dpy, pix, gc, float_pts, num_pts, fgi)
Display *dpy;
Drawable pix;
GC gc;
XfPoint *float_pts;
int num_pts, fgi;
{
   int i, j, color;
   float minx, miny, maxx, maxy, dist;
   Boolean inside;

   /* find boundaries */

   minx = miny = 100000.0;
   maxx = maxy = -100000.0;
   for (i = 0; i < num_pts; i++) {
      if (float_pts[i].x < minx) minx = float_pts[i].x;
      if (float_pts[i].x > maxx) maxx = float_pts[i].x;
      if (float_pts[i].y < miny) miny = float_pts[i].y;
      if (float_pts[i].y > maxy) maxy = float_pts[i].y;
   }

   /* scan through pixel centers in region */

   for (j = (int)(miny - 1.0); j < (int)(maxy + 1.0); j++) {
      inside = False;
      for (i = (int)(minx - 1.0); i < (int)(maxx + 1.0); i++) {
       dist = find_mindist((float)i + 0.5, (float)j + 0.5,
            float_pts, num_pts); 
       if (dist < 2.0)
          inside = test_insideness((float)i + 0.5, (float)j + 0.5,
            float_pts, num_pts);
       if (inside) {
          if ((dist >= 1.0) && (fgi > 0)) color = fadevector[fgi - 1];
          else {
             color = fadevector[(int)(dist * fgi)];
          }
          XSetForeground(dpy, gc, color);
          XDrawPoint(dpy, pix, gc, i, j);
       }
      }
   }
}

/*------------------------------------------------------*/

static void
make_number(dw, pix, gc, n, seg_pts)
DclockWidget dw;
Pixmap pix;
GC gc;
int n;
segment_pts seg_pts;
{
   Display *dpy = XtDisplay(dw);
   int i;

   for (i = 0; i != NUM_SEGS; ++i) {
      if (segmask[n] & msk(i))
       XfFillPolygon(dpy, pix, gc, seg_pts[i], num_segment_pts, FADE_ITER);
      else
       XfFillPolygon(dpy, pix, gc, seg_pts[i], num_segment_pts, 0);
   }
   XSetForeground(dpy, gc, fadevector[FADE_ITER - 1]);
}

/*----------------------------------------------------------------------*/
/* Variation of "make_number" to handle the first digit of "civilian    */
/* time", which may be the number "1" (2 segments only) or blank. */
/*----------------------------------------------------------------------*/

static void
make_number_one(dw, pix, gc, n, seg_pts)
DclockWidget dw;
Pixmap pix;
GC gc;
int n;
segment_pts seg_pts;
{
   Display *dpy = XtDisplay(dw);
   int color;

   color = (n == 1) ? FADE_ITER : 0;
   XfFillPolygon(dpy, pix, gc, seg_pts[TOP_RIGHT], num_segment_pts, color);
   XfFillPolygon(dpy, pix, gc, seg_pts[BOT_RIGHT], num_segment_pts, color);
   XSetForeground(dpy, gc, fadevector[FADE_ITER - 1]);
}

/*------------------------------------------------------*/
/*------------------------------------------------------*/

static void
make_fade_number(dw, pix, gc, on_msk, turn_on_msk, turn_off_msk, iter)
DclockWidget dw;
Pixmap pix;
GC gc;
int on_msk, turn_on_msk, turn_off_msk;
int iter;
{
    Display *dpy = XtDisplay(dw);
    Pixmap on_stipple = fade_stip[iter],
         off_stipple = fade_stip[FADE_ITER - iter];
    int i;

    if (!use_stipple) XSetFillStyle(dpy, gc, FillSolid);

    for (i = 0; i != NUM_SEGS; ++i)
    {
      if (on_msk & msk(i))
      {
          if (use_stipple)
             XSetFillStyle(dpy, gc, FillSolid);
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, FADE_ITER);
      }
      else if (turn_on_msk & msk(i))
      {
          if (use_stipple) {
             XSetStipple(dpy, gc, on_stipple);
             XSetFillStyle(dpy, gc, FillOpaqueStippled);
          }
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, iter);
      }
      else if (turn_off_msk & msk(i))
      {
          if (use_stipple) {
             XSetStipple(dpy, gc, off_stipple);
             XSetFillStyle(dpy, gc, FillOpaqueStippled);
          }
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, FADE_ITER - iter - 1);
      }
    }

    if (use_stipple) XSetFillStyle(dpy, gc, FillSolid);
    XSetForeground(dpy, gc, fadevector[FADE_ITER - 1]);
}

/*------------------------------------------------------*/
/*------------------------------------------------------*/

static void
make_fade_number_one(dw, pix, gc, on_msk, turn_on_msk, turn_off_msk, iter)
DclockWidget dw;
Pixmap pix;
GC gc;
int on_msk, turn_on_msk, turn_off_msk;
int iter;
{
    Display *dpy = XtDisplay(dw);
    Pixmap on_stipple = fade_stip[iter],
         off_stipple = fade_stip[FADE_ITER - iter];
    int i;

    if (!use_stipple) XSetFillStyle(dpy, gc, FillSolid);

    for (i = TOP_RIGHT; i < NUM_SEGS; ++i)
    {
      if (on_msk & msk(i))
      {
          if (use_stipple)
             XSetFillStyle(dpy, gc, FillSolid);
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, FADE_ITER);
      }
      else if (turn_on_msk & msk(i))
      {
          if (use_stipple) {
             XSetStipple(dpy, gc, on_stipple);
             XSetFillStyle(dpy, gc, FillOpaqueStippled);
          }
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, iter);
      }
      else if (turn_off_msk & msk(i))
      {
          if (use_stipple) {
             XSetStipple(dpy, gc, off_stipple);
             XSetFillStyle(dpy, gc, FillOpaqueStippled);
          }
          XfFillPolygon(dpy, pix, gc, norm_segment_pts[i],
                   num_segment_pts, FADE_ITER - iter - 1);
      }
    }

    if (use_stipple) XSetFillStyle(dpy, gc, FillSolid);
    XSetForeground(dpy, gc, fadevector[FADE_ITER - 1]);
}

/* Play the bell---sophisticated version, with ability to configure */
/* separate audio files for the alarm and hourly bell */

static void playbell(DclockWidget w, int alarmtype)
{
   /* Try using an audio process.  If that fails, ring the bell */
   int status = 1;

   if ((((alarmtype == 0) && (w->dclock.alarmfile != (String)NULL &&
            strcasecmp(w->dclock.alarmfile, "NULL"))) ||
            ((alarmtype == 1) && (w->dclock.bellfile != (String)NULL &&
            strcasecmp(w->dclock.bellfile, "NULL")))) &&
            w->dclock.audioplay)
   {

      pid_t cpid, bell_proc;
      char *locargv[4];
      char *proot = strrchr(w->dclock.audioplay, '/');

      if (proot == NULL) proot = w->dclock.audioplay;
      else proot++;
      locargv[0] = proot;
      if (alarmtype == 0)
         locargv[1] = w->dclock.alarmfile;
      else
         locargv[1] = w->dclock.bellfile;
      locargv[2] = NULL;

      if ((cpid = fork()) < 0) {
       fprintf(stderr, "dclock: Fork error.  Reverting to system bell.\n");
       w->dclock.audioplay = (String)NULL;
      }
      else if (cpid == 0) {
         execv(w->dclock.audioplay, locargv);
       fprintf(stderr, "dclock: Unable to exec \"%s\".\n", w->dclock.audioplay);
       exit(-1);
      }
      else {
       if (waitpid(cpid, &status, 0) != cpid) {
          fprintf(stderr, "dclock: Waitpid error (%d)\n", errno);
          exit(-1);
       }
       if (WEXITSTATUS(status) != 0) {
          fprintf(stderr, "dclock: \"%s\" returned an error.  Reverting to"
                  " system bell.\n", w->dclock.audioplay);
          w->dclock.audioplay = (String)NULL;   
       }
      }
   }

   if (WEXITSTATUS(status) != 0) {
      XBell(XtDisplay(w), 50);
      if (alarmtype == 0)
       XBell(XtDisplay(w), 50);
   }
}

/* ARGSUSED */
static void
Redisplay  (w)
DclockWidget    w;
{
    XtAppContext app;
    Boolean save_scroll = w->dclock.scroll;
    Boolean save_fade = w->dclock.fade;
    long t;

    if (!XtIsRealized((Widget)w))
      return;

    if (w->dclock.punt_resize != (XtIntervalId)NULL) return;

    if (w->dclock.interval_id != (XtIntervalId)NULL) {
      XtRemoveTimeOut(w->dclock.interval_id);
      w->dclock.interval_id = (XtIntervalId)NULL;
    }
    XFillRectangle(XtDisplay(w), XtWindow(w), w->dclock.backGC,
      0, 0, w->core.width, w->core.height);
    before.tm_min = before.tm_hour = before.tm_wday = -1;
    old_pix[0] = w->dclock.digits[0];
    old_pix[1] = old_pix[2] = old_pix[3] = 0;
    old_digs[0] = old_digs[1] = old_digs[2] = old_digs[3] = 0;
    w->dclock.scroll = FALSE;
    w->dclock.fade = FALSE;
    (void) show_time(w);
    w->dclock.scroll = save_scroll;
    w->dclock.fade = save_fade;
    app = XtWidgetToApplicationContext((Widget)w);
    if (w->dclock.display_time)
      if (w->dclock.seconds || w->dclock.blink)
          w->dclock.interval_id = XtAppAddTimeOut(app,
            (unsigned long)1000, timeout, (XtPointer)w);
      else {
          t = time(0);
          w->dclock.interval_id =
            XtAppAddTimeOut(app,
                  (unsigned long)(60 - (t % 60)) * 1000, 
                  timeout, (XtPointer)w);
      }
}

static void
draw_seconds(w, sec_val)
DclockWidget w;
int sec_val;
{
    int digitxpos, digitypos;
    float digit_w = w->dclock.digit_w;
    float digit_h = w->dclock.digit_h;
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    GC gc = w->dclock.foreGC;

    XSetRegion(dpy, gc, clip_small);
    digitxpos = (int)(winwidth - (2 * digit_w + slope_add) *
          w->dclock.small_ratio);
    digitypos = (int)(BORDER*y_ratio + (1.0 - w->dclock.small_ratio) * 
          digit_h)+TopOffset;
    XSetClipOrigin(dpy, gc, digitxpos, digitypos);
    XCopyArea(dpy, w->dclock.tiny_digits[sec_val/10], win, gc,
          0, 0, (int)((digit_w + slope_add) * w->dclock.small_ratio), 
          (int)(digit_h * w->dclock.small_ratio), digitxpos, digitypos);
    digitxpos += (int)(digit_w * w->dclock.small_ratio);
    XSetClipOrigin(dpy, gc, digitxpos, digitypos);
    XCopyArea(dpy, w->dclock.tiny_digits[sec_val%10], win, gc,
          0, 0, (int)((digit_w + slope_add) * w->dclock.small_ratio), 
          (int)(digit_h * w->dclock.small_ratio), digitxpos, digitypos);
}

static Boolean
show_time(w)
DclockWidget w;
{
    char buf[11];
    Boolean alarm_went_off = False;
    long t = time(0);
    register struct tm *l_time = localtime(&t);
    float digit_w = w->dclock.digit_w;
    float digit_h = w->dclock.digit_h;
    int digitxpos, digitypos;
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    GC gc = w->dclock.foreGC;

    if (w->dclock.utc == True) 
      l_time = gmtime(&t);

    if (w->dclock.display_time == True) {
      if (w->dclock.miltime)
          (void) sprintf(buf, "%02d%02d", l_time->tm_hour, l_time->tm_min);
      else
          (void) sprintf(buf, "%02d%02d",
             (l_time->tm_hour) ? ((l_time->tm_hour <= 12) ?
                  l_time->tm_hour : l_time->tm_hour - 12) : 12,
              l_time->tm_min);
    } else
      /* display the alarm time */
      (void) sprintf(buf, "%02d%02d", Alarm.hrs, Alarm.mins);

    /* Copy the pre-defined pixmaps onto the viewing area.*/
    /* Start with the colon. */

    XSetRegion(dpy, gc, clip_colon);
    digitxpos = cx;
    digitypos = (int)(BORDER*y_ratio)+TopOffset;
    XSetClipOrigin (dpy, gc, digitxpos, digitypos);
    XCopyArea(dpy,
      w->dclock.colon[!w->dclock.blink || l_time->tm_sec & 1],
      win, gc, 0, 0, (int)(slope_add + 0.5 * digit_w), (int)digit_h,
      digitxpos, digitypos);

    /* Next the seconds. */
    if (w->dclock.seconds)
      draw_seconds(w, l_time->tm_sec);

    /* The large digits are displayed by the scrolling/fading routine. */
    if (l_time->tm_min != before.tm_min || l_time->tm_hour != before.tm_hour)
      scroll_time(w, buf);

    XSetClipMask(dpy,gc,None);

    if ((w->dclock.date_fmt && before.tm_wday != l_time->tm_wday) ||
            (!w->dclock.display_time))
      show_date(w, l_time);
    if (w->dclock.alarm) show_alarm(w);
    if (w->dclock.bell) show_bell(w);

    before = *l_time;

    if (w->dclock.alarm && Alarm.hrs == l_time->tm_hour &&
      Alarm.mins == l_time->tm_min &&
      l_time->tm_sec < 5) {
      bsave |= 0x4;           /* set alarm_active state */
      playbell(w, 0);
      toggle_reverse_video(w);
      alarm_went_off = True;
    } else {
      /* if alarm didn't go off, check for hour/half-hour bell */
      if (w->dclock.bell && (!w->dclock.seconds || l_time->tm_sec == 0) &&
          (l_time->tm_min == 0 || l_time->tm_min == 30)) {
          playbell(w, 1);
          if (l_time->tm_min == 0)
            playbell(w, 1);
      }

      /* avoid leaving clock in reverse_video state after alarm, unless */
      /* alarmPersist is set, in which case we always leave dclock in     */
      /* reverse video after an alarm.                        */

      if (bsave & 0x4) {
          if (((bsave & 0x1) == ((bsave & 0x2) >> 1)) ^
                  ((w->dclock.alarm_persist) ? 0 : 1))
            toggle_reverse_video(w);

          bsave &= 0x3; /* clear alarm_active state */
      }
    }
    return alarm_went_off;
}


static void
scroll_time(w, p)
DclockWidget w;
register char *p;
{
    int chgd[4], J = winheight - BORDER*2*y_ratio + 1;
    register int i, j, incr;
    float digit_w = w->dclock.digit_w;
    float digit_h = w->dclock.digit_h;
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    GC gc = w->dclock.foreGC;
    Pixmap new_pix[4];
    int new_digs[4], digitxpos, digitypos;
    int cur_sec = 0;
    long t;
    register struct tm *now;

/* definitions for the window x and y positions of each of the large digits. */

#define x (int)((i>1)*(digit_w / 2) + digit_w * i - (!w->dclock.miltime) \
      *((1 - 2 * w->dclock.space_factor) * digit_w - segxwidth))
#define y (int)((BORDER * y_ratio)+TopOffset)

    for (i = 0; i < 4; i++)
      new_digs[i] = *p++ - '0';

    if (w->dclock.miltime)
      new_pix[0] = w->dclock.digits[new_digs[0]];
    else
      new_pix[0] = w->dclock.digit_one[new_digs[0]];

    for (i = 1; i < 4; i++)
      new_pix[i] = w->dclock.digits[new_digs[i]];

    digitypos = (int)(BORDER*y_ratio)+TopOffset;

    /* digit scrolling routine. */

    if (w->dclock.scroll)
    {
      for (i = 0; i < 4; i++)    /* if pixmaps don't match, scroll it */
          chgd[i] = (new_pix[i] != old_pix[i]);

      if (w->dclock.date_fmt || !w->dclock.display_time)
          J -= w->dclock.font->ascent + w->dclock.font->descent;

      if ((incr = J / 30) < 1)
          incr = 1;

        XSetRegion(dpy, gc, clip_norm);
      for (j = 0; j <= J; j += incr)
          for (i = 0; i < 4; i++)
            if (chgd[i]) {
                digitxpos = x;
                XSetClipOrigin(dpy, gc, digitxpos, digitypos);
                if (old_pix[i])
                  XCopyArea(dpy, old_pix[i], win, gc,
                      0, j, (int)(digit_w + slope_add), 
                      (int)(digit_h) - j, digitxpos, y);

                XCopyArea(dpy, new_pix[i], win, gc,
                      0, 0, (int)(digit_w + slope_add), j, 
                      digitxpos, y + (int)digit_h - j);
            }
      XSetClipMask(dpy, gc, None);
    }

    /* digit fading routine */

    else if (w->dclock.fade)
    {
      Pixmap tmp_pix[4];
      int oldmask, newmask;
      int stay_on[4], turn_on[4], turn_off[4];
      unsigned long fade_rate = w->dclock.fade_rate * 1000;

      for (i = 0; i < 4; i++)    /* if pixmaps don't match, fade it */
          if (chgd[i] = (new_pix[i] != old_pix[i]))
          {
            tmp_pix[i] = XCreatePixmap(dpy, win, (int)(digit_w + slope_add),
                  (int)digit_h, DefaultDepthOfScreen(XtScreen(w)));
            oldmask = segmask[old_digs[i]];
            newmask = segmask[new_digs[i]];
            stay_on[i] = oldmask & newmask;
            turn_on[i] = ~oldmask & newmask;
            turn_off[i] = oldmask & ~newmask;
          }
          else
            tmp_pix[i] = (Pixmap)NULL;
  
      XSetClipMask(dpy, gc, None);
      for (j = 1; j != FADE_ITER; ++j)
      {
          for (i = 0; i < 4; i++)
            if (chgd[i])
            {
                XFillRectangle(dpy, tmp_pix[i], w->dclock.backGC,
                  0, 0, (int)(digit_w + slope_add), (int)digit_h);
                if (i == 0 && !w->dclock.miltime)
                  make_fade_number_one(w, tmp_pix[i], gc, stay_on[i],
                        turn_on[i], turn_off[i], j);
                else
                  make_fade_number(w, tmp_pix[i], gc, stay_on[i],
                        turn_on[i], turn_off[i], j);
                digitxpos = x;
                XSetRegion(dpy, gc, clip_norm);
                XSetClipOrigin(dpy, gc, digitxpos, digitypos);
                XCopyArea(dpy, tmp_pix[i], win, gc, 0, 0, (int)(digit_w + 
                    slope_add), (int)digit_h, digitxpos, y);
                XSetClipMask(dpy, gc, None);
            }

          XFlush(dpy);
          usleep(fade_rate);

          /* Keep tabs on time;  it's necessary to update the seconds */
          /* if fade_rate * FADE_ITER + (overhead) > 1 second     */

          t = time(0);
          now = localtime(&t);
            if (w->dclock.seconds && (now->tm_sec != cur_sec)) {
             cur_sec = now->tm_sec;
             draw_seconds(w, cur_sec);
             XSetClipMask(dpy,gc,None);
          }
      } 

      for (i = 0; i < 4; ++i)
          if (tmp_pix[i]) XFreePixmap(dpy, tmp_pix[i]);
    }

    XSetRegion(dpy, gc, clip_norm);
    for (i = 0; i < 4; i++) {
      digitxpos = x;
      XSetClipOrigin(dpy, gc, digitxpos, digitypos);
      XCopyArea(dpy, new_pix[i], win, gc, 0,0, (int)(digit_w + 
            slope_add), (int)digit_h, digitxpos, y);
    }
    XSetClipMask(dpy, gc, None);
    if (!w->dclock.display_time) outline_digit(w, cur_position, True);

    for (i = 0; i < 4; i++) {
      old_pix[i] = new_pix[i];
      old_digs[i] = new_digs[i];
    }

#undef x
#undef y

}

static void
show_date(w, now)
DclockWidget w;
struct tm *now;
{
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    char datestr[128];
    register char *p;
    int x, datep;
#ifdef XFT_SUPPORT
    int tsize = w->core.height / 6;
    XGlyphInfo xftextents;
#else
    int tsize = w->dclock.font->ascent + w->dclock.font->descent;
#endif

    if (!w->dclock.display_time)
      datep = strlen(strcpy(datestr, "Push HERE to Set/Unset Alarm"));
    else
        datep = strftime(datestr, 128, w->dclock.date_fmt, now);

#ifdef XFT_SUPPORT
    XftTextExtents8(dpy, w->dclock.xftfont, datestr, datep, &xftextents);
    x = (w->core.width - xftextents.width) / 2;
#else
    x = (w->core.width - XTextWidth(w->dclock.font, datestr, datep)) / 2;
#endif
    if (x < 2)
      x = 2;
    if (TopOffset) {

#ifdef XFT_SUPPORT
      XftDrawRect(w->dclock.xftdraw, &w->dclock.xftbg, 0, 0, winwidth, tsize);
      XftDrawString8(w->dclock.xftdraw, &w->dclock.xftfg, w->dclock.xftfont, x,
            (BORDER/2) + tsize - 2, datestr, datep);
#else
      XFillRectangle(dpy, win, w->dclock.backGC,
          0, 0, winwidth, tsize);
      XDrawString(dpy, win, w->dclock.foreGC,
            x, ((BORDER/2)+w->dclock.xftfont->height), datestr, datep);
#endif
    } else {

#ifdef XFT_SUPPORT
      XftDrawRect(w->dclock.xftdraw, &w->dclock.xftbg, 0, winheight - tsize,
            winwidth, tsize);
      XftDrawString8(w->dclock.xftdraw, &w->dclock.xftfg, w->dclock.xftfont, x,
            winheight - BORDER - 2, datestr, datep);
#else
      XFillRectangle(dpy, win, w->dclock.backGC,
          0, winheight - tsize, winwidth, tsize);
      XDrawString(dpy, win, w->dclock.foreGC,
            x, winheight - BORDER, datestr, datep);
#endif
    }
}

static void
show_alarm(w)
DclockWidget w;
{
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    int tsize = w->dclock.font->ascent + w->dclock.font->descent;
    int ccentx = BORDER;
    int hcsize = tsize >> 1;
    int ccenty;

    if (TopOffset)
      ccenty = BORDER + (hcsize/2);
    else
      ccenty = winheight - BORDER - hcsize;

    hcsize /= 2;
    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - hcsize,
            ccenty - hcsize, hcsize << 1, hcsize << 1, -2800, 5600);
    hcsize *= 2;
    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - hcsize,
            ccenty - hcsize, hcsize << 1, hcsize << 1, -2800, 5600);
    hcsize *= 1.5;
    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - hcsize,
            ccenty - hcsize, hcsize << 1, hcsize << 1, -2800, 5600);
}

static void
show_bell(w)
DclockWidget w;
{
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    int tsize = w->dclock.font->ascent + w->dclock.font->descent;
    int hcsize = tsize >> 1;
    int ccentx = BORDER + ((w->dclock.alarm) ? (tsize * 3 / 2) : (tsize / 3));
    int ccenty;

    if (TopOffset)
      ccenty = BORDER + (hcsize/2);
    else
      ccenty = winheight - BORDER - hcsize;

    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - tsize / 3,
      ccenty - tsize / 2, tsize * 2 / 3, tsize * 2 / 3, 0, 11520);

    XDrawLine(dpy, win, w->dclock.foreGC, ccentx - tsize / 3,
      ccenty - tsize / 6, ccentx - tsize / 3, ccenty + tsize / 3);
    XDrawLine(dpy, win, w->dclock.foreGC, ccentx + tsize / 3,
      ccenty - tsize / 6, ccentx + tsize / 3, ccenty + tsize / 3);

    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - tsize * 2 / 3,
      ccenty + tsize / 6, tsize / 3, tsize / 3, 17280, 5760);
    XDrawArc(dpy, win, w->dclock.foreGC, ccentx + tsize / 3,
      ccenty + tsize / 6, tsize / 3, tsize / 3, 11520, 5760);

    XDrawLine(dpy, win, w->dclock.foreGC, ccentx - tsize / 2,
      ccenty + tsize / 2, ccentx + tsize / 2, ccenty + tsize / 2);

    XDrawArc(dpy, win, w->dclock.foreGC, ccentx - tsize / 12,
      ccenty + tsize / 2, tsize / 6, tsize / 6, 0, 23040);
}


static void
timeout(w, id)
DclockWidget w;
XtIntervalId *id;
{
    struct timeval now;
    int next_intr;
    Boolean alarm_went_off = show_time(w);
    XtAppContext app;

    /* Try to catch the next second on the second boundary. */  

    /* NO!  This is a BAD IDEA, and leads to catching the   */
    /* time sometimes before the second, sometimes after, and     */
    /* thereby skipping seconds all the time.  Instead, we  */
    /* should aim for a few milliseconds LATE (try 5ms).    */

    gettimeofday(&now, NULL);
    /* next_intr = (1e6 - now.tv_usec) / 1e3; */
    next_intr = (1e6 - now.tv_usec + 5000) / 1e3;

    app = XtWidgetToApplicationContext((Widget)w);
    w->dclock.interval_id =
      XtAppAddTimeOut(app, (unsigned long)((alarm_went_off
            || w->dclock.seconds || w->dclock.blink) ?
            next_intr : 59000 + next_intr), timeout,
            (XtPointer)w);
}

/* ARGSUSED */
static Boolean
SetValues (current, request, new)
DclockWidget current, request, new;
{
    Boolean do_redraw = False;

    if (current->dclock.display_time != new->dclock.display_time) {
      before.tm_min = before.tm_hour = before.tm_wday = -1;
      new->dclock.miltime = True; /* old state needs to be saved */
      do_redraw = True;
    }
    if (current->dclock.alarm_time != new->dclock.alarm_time) {
      if (sscanf(new->dclock.alarm_time, "%2d:%2d",
            &Alarm.hrs, &Alarm.mins) != 2 || Alarm.hrs >= 24 ||
            Alarm.mins >= 60) {
          XtWarning("Alarm Time is in incorrect format.");
          new->dclock.alarm_time = "00:00";
          Alarm.hrs = Alarm.mins = 0;
      }
      new->dclock.alarm_time =
          strcpy(XtMalloc(strlen(new->dclock.alarm_time)+1),
                           new->dclock.alarm_time);
      do_redraw = True;
    }

    if (new->dclock.foreground != current->dclock.foreground
    ||  new->dclock.background != current->dclock.background
    ||  new->dclock.tails != current->dclock.tails
    ||  new->dclock.fade != current->dclock.fade
    ||  new->dclock.miltime != current->dclock.miltime) {
      XtReleaseGC ((Widget)current, current->dclock.foreGC);
      XtReleaseGC ((Widget)current, current->dclock.backGC);
      GetGC(new);
      ResizeNow(new); /* pixmaps need to be redrawn */
      do_redraw = True;
    }
    if (new->dclock.seconds != current->dclock.seconds) {
      if (current->dclock.interval_id != (XtIntervalId)NULL) {
          XtRemoveTimeOut(current->dclock.interval_id);
          current->dclock.interval_id = (XtIntervalId)NULL;
      }
      ResizeNow(new);
      do_redraw = True;
    }
    if (new->dclock.date_fmt != current->dclock.date_fmt) {
      do_redraw = True;
      before.tm_wday = -1;
    }
    if (new->dclock.alarm != current->dclock.alarm)
      do_redraw = True;

    return do_redraw;
}

/* The following routines are called by the various keypress events. */

static void
decrease_space(w)
DclockWidget w;
{
    w->dclock.space_factor *= 0.95;
    if (w->dclock.space_factor < 0.0) w->dclock.space_factor = 0;
    ResizeNow(w);
    Redisplay(w);
}

static void
increase_space(w)
DclockWidget w;
{
    w->dclock.space_factor *= 1.05;
    if (w->dclock.space_factor > 0.25) w->dclock.space_factor = 0.25;
    ResizeNow(w);
    Redisplay(w);
}

static void
decrease_slope(w)
DclockWidget w;
{
    w->dclock.angle *= 1.05;
    if (w->dclock.angle > 2 * winheight) w->dclock.angle = 2 * winheight;
    ResizeNow(w);
    Redisplay(w);
}

static void
increase_slope(w)
DclockWidget w;
{
    w->dclock.angle *= 0.95;
    if (w->dclock.angle < 1.0) w->dclock.angle = 1.0;
    ResizeNow(w);
    Redisplay(w);
}

static void
widen_segment(w)
DclockWidget w;
{
    w->dclock.width_factor *= 1.05;
    if (w->dclock.width_factor > 0.4) w->dclock.width_factor = 0.4;
    ResizeNow(w);
    Redisplay(w);
}

static void
thin_segment(w)
DclockWidget w;
{
    w->dclock.width_factor *= 0.95;
    if (w->dclock.width_factor < 0.01) w->dclock.width_factor = 0.01;
    ResizeNow(w);
    Redisplay(w);    
}

static void
print_help(w)
DclockWidget w;
{
fprintf(stderr, "In-Window single-character commands:\n\n");
fprintf(stderr, "   r   Toggles Reverse Video.\n");
fprintf(stderr, "   s   Toggles the seconds display.\n");
fprintf(stderr, "   b   Toggles the bell attribute.\n");
fprintf(stderr, "   j   Toggles the jump/scroll attribute.\n");
fprintf(stderr, "   f   Toggles the fade attribute.\n");
fprintf(stderr, "   d   Toggles the date format.\n");
fprintf(stderr, "   u   Toggles the location of the date (top/bottom).\n");
fprintf(stderr, "   m   Toggles the military time format.\n");
fprintf(stderr, "   a   Toggles the alarm clock.\n");
fprintf(stderr, "   t   Toggles the tails attribute.\n");
fprintf(stderr, "   v   Ascii dump of the values of various attributes.\n");
fprintf(stderr, "   h   Print this help screen.\n");
fprintf(stderr, "   ?   Same as h.\n");
fprintf(stderr, "   :   Toggles the blinking colon.\n");
fprintf(stderr, "   /   Increases the slope of the digits.\n");
fprintf(stderr, "   \\  Decreases the slope of the digits.\n");
fprintf(stderr, "   +   Increases the thickness of the digit segments.\n");
fprintf(stderr, "   -   Decreases the thickness of the digit segments.\n");
fprintf(stderr, "   >   Increases spacing between the digits.\n");
fprintf(stderr, "   <   Decreases spacing between the digits.\n");
fprintf(stderr, "   q   quit the program.\n");
fprintf(stderr, " <Btn3>      Toggle Alarm-time display\n");
fprintf(stderr, " <Btn1>      Increment number in alarm-time display\n");
fprintf(stderr, " <Btn2>      Decrement number in alarm-time display\n");
fprintf(stderr, "\n\n");
}

static void
print_dump(w)
DclockWidget w;
{
fprintf(stderr, "Window attributes:\n\n");
fprintf(stderr, "   window width = %d\n", winwidth);
fprintf(stderr, "   window height = %d\n", winheight);
fprintf(stderr, "   slope = %f\n", w->dclock.angle);
fprintf(stderr, "   segment width ratio = %f\n", w->dclock.width_factor);
fprintf(stderr, "   seconds gap ratio = %f\n", w->dclock.sec_gap);
fprintf(stderr, "   small digit ratio = %f\n", w->dclock.small_ratio);
fprintf(stderr, "   digit spacing ratio = %f\n", w->dclock.space_factor);
fprintf(stderr, "   fade rate = %d\n", w->dclock.fade_rate);
fprintf(stderr, "   date format = %s\n", (w->dclock.date_fmt) ?
                               (w->dclock.date_fmt) : "<null>");
fprintf(stderr, "   date location = %s\n", (w->dclock.dateup ? "top" : "bottom"));
fprintf(stderr, "\n\n");
}

static void
toggle_date(w)
DclockWidget w;
{
    char *tmp;

    if (!w->dclock.display_time) {
      XBell(XtDisplay(w), 50);
      return;
    }
    tmp = w->dclock.date_fmt;
    w->dclock.date_fmt = saved_date;
    saved_date = tmp;

    if (w->dclock.dateup && w->dclock.date_fmt)
#ifdef XFT_SUPPORT
      TopOffset = w->core.height / 6;
#else
      TopOffset = w->dclock.font->ascent + w->dclock.font->descent;
#endif
    else
      TopOffset = 0;

    before.tm_wday = -1;
    ResizeNow(w);
    Redisplay(w);
}

static void
toggle_dateup(w)
DclockWidget w;
{
    Arg arg;
    int tmp;

    if (!w->dclock.display_time) {
      XBell(XtDisplay(w), 50);
      return;
    }

    XtSetArg(arg, XtNdateUp, !w->dclock.dateup);
    XtSetValues((Widget)w, &arg, 1);

    if (w->dclock.dateup && w->dclock.date_fmt)
#ifdef XFT_SUPPORT
      TopOffset = w->core.height / 6;
#else
      TopOffset = w->dclock.font->ascent + w->dclock.font->descent;
#endif
    else
      TopOffset = 0;

    ResizeNow(w);
    Redisplay(w);
}

static void
toggle_bell(w)
DclockWidget w;
{
    if (w->dclock.bell = !w->dclock.bell) {
      playbell(w, 1);
    }
    ResizeNow(w);
    Redisplay(w);
}

static void
toggle_scroll(w)
DclockWidget w;
{
    w->dclock.scroll = !w->dclock.scroll;
}

static void
toggle_reverse_video(w)
DclockWidget w;
{
   Display *dpy = XtDisplay(w);
   int i, itemp;

   if (!(bsave & 0x1)) {
      XSetForeground(dpy, w->dclock.backGC, w->dclock.foreground);
      bsave |= 0x1;     /* set reverse-video state */
   }
   else {
      XSetForeground(dpy, w->dclock.backGC, w->dclock.background);
      bsave &= 0x5;     /* clear reverse-video state */
   }

   if (!(bsave & 0x4))
      bsave = (bsave & 0x1) ? 0x3 : 0x0;

   for (i = 0; i < (FADE_ITER >> 1); i++) {
      itemp = fadevector[i];
      fadevector[i] = fadevector[FADE_ITER - i - 1];
      fadevector[FADE_ITER - i - 1] = itemp;
   }
   ResizeNow(w);
   Redisplay(w);
}

static void
toggle_military_time(w)
DclockWidget w;
{
    Arg arg;

    if (!w->dclock.display_time) {
      XBell(XtDisplay(w), 50);
      return;
    }
    XtSetArg(arg, XtNmilitaryTime, !w->dclock.miltime);
    XtSetValues((Widget)w, &arg, 1);
}

static void
toggle_blink(w)
DclockWidget w;
{
    Arg arg;

    if (!w->dclock.display_time) {
      XBell(XtDisplay(w), 50);
      return;
    }
    XtSetArg(arg, XtNblink, !w->dclock.blink);
    XtSetValues((Widget)w, &arg, 1);
}

static void
toggle_seconds(w)
DclockWidget w;
{
    Arg arg;

    if (!w->dclock.display_time) {
      XBell(XtDisplay(w), 50);
      return;
    }
    XtSetArg(arg, XtNseconds, !w->dclock.seconds);
    XtSetValues((Widget)w, &arg, 1);
}

static void
toggle_fade(w)
DclockWidget w;
{
    Arg arg;

    XtSetArg(arg, XtNfade, !w->dclock.fade);
    XtSetValues((Widget)w, &arg, 1);
    if (w->dclock.fade && w->dclock.scroll)
      toggle_scroll(w);
}

static void
toggle_tails(w)
DclockWidget w;
{
    Arg arg;

    XtSetArg(arg, XtNtails, !w->dclock.tails);
    XtSetValues((Widget)w, &arg, 1);
}

static void
toggle_alarm(w)
DclockWidget w;
{
    Arg arg;

    XtSetArg(arg, XtNalarm, !w->dclock.alarm);
    XtSetValues((Widget)w, &arg, 1);
}

static void
set_alarm(w, event)
DclockWidget w;
XButtonEvent *event;
{
    static saved_secs, saved_miltime, saved_fade, saved_blink;

    if (event->button == 3) {
      if (!(w->dclock.display_time = !w->dclock.display_time)) {
          XtRemoveTimeOut(w->dclock.interval_id);
          saved_secs = w->dclock.seconds, w->dclock.seconds = False;
          saved_miltime = w->dclock.miltime, w->dclock.miltime = True;
          saved_fade = w->dclock.fade, w->dclock.fade = False;
          saved_blink = w->dclock.blink, w->dclock.blink = False;
          w->dclock.interval_id = (XtIntervalId)NULL;
      } else {
          w->dclock.seconds = saved_secs;
          w->dclock.miltime = saved_miltime;
          w->dclock.fade = saved_fade;
          w->dclock.blink = saved_blink;
      }
      ResizeNow(w);
      Redisplay(w);
    } else if (!w->dclock.display_time &&
          (event->button == 1 || event->button == 2)) {
      /* get the digit under the position (1-4) the mouse is over
       * and increment (possibly wrap around) to next digit.
       */
      int i, x, y = (int)((BORDER/2)*y_ratio) + TopOffset;
      /* first check to see if user toggles the alarm */
#ifdef XFT_SUPPORT
      if (TopOffset)
            i = (BORDER + (w->core.height / 6))
                  - event->y;
      else
            i = event->y - (winheight - (w->core.height / 6));
#else
      if (TopOffset)
            i = (BORDER + (w->dclock.font->ascent + w->dclock.font->descent))
                  - event->y;
      else
            i = event->y - (winheight - (w->dclock.font->ascent
                  + w->dclock.font->descent));
#endif
      if (i >= 0)
          toggle_alarm(w);
      else for (i = 0; i < 4; i++) {
          x = i * w->dclock.digit_w + (i>1) * (w->dclock.digit_w / 2) + 
            (w->dclock.digit_h - event->y) / w->dclock.angle;
          if (event->x < x + w->dclock.digit_w) {
            if (cur_position == i) {
                int digit = w->dclock.alarm_time[i>1?i+1:i] - '0';
                int mod;
                switch (i) {
                  case 0:
                      if (Alarm.hrs > 13 && digit == 1)
                        digit++;
                      mod = 3;
                      before.tm_hour = -1;
                  when 1 :
                      mod = (Alarm.hrs < 20)? 10 : 4;
                      before.tm_hour = -1;
                  when 2:
                      mod = 6;
                      before.tm_min = -1;
                  when 3 :
                      mod = 10;
                      before.tm_min = -1;
                }
                if (event->button == 1)
                  digit = (digit + 1) % mod;
                else if (--digit < 0)
                  digit = mod-1;
                w->dclock.alarm_time[i>1?i+1:i] = digit + '0';
                (void) sscanf(w->dclock.alarm_time, "%2d:%2d",
                      &Alarm.hrs, &Alarm.mins);
                (void) show_time(w);
                outline_digit(w, cur_position, True);
            } else {
            outline_digit(w, cur_position, False);
            outline_digit(w, cur_position = i, True);
            }
            break;
          }
      }
    } else
      XBell(XtDisplay(w), 50);
}

/* Draw a box around the digit, for use with the alarm-time setting function.*/

static void
outline_digit(w, i, draw_it)
DclockWidget w;
int i;
Boolean draw_it;
{
    int xbase, y, xadd;
    XPoint rectpts[5];

    xbase = w->dclock.digit_w * i + (i>1) * (w->dclock.digit_w / 2);
    xadd = (int)(w->dclock.space_factor * w->dclock.digit_w / 4);
    y = 0.5 * BORDER * y_ratio;

    rectpts[0].x = rectpts[4].x = xbase + xadd;
    rectpts[1].x = rectpts[0].x + ((w->dclock.digit_h + 2 * y) /
      w->dclock.angle);
    rectpts[2].x = rectpts[1].x + w->dclock.digit_w - xadd;
    rectpts[3].x = rectpts[0].x + w->dclock.digit_w - xadd;
    rectpts[0].y = rectpts[4].y = rectpts[3].y = (w->dclock.digit_h + 3 * y) + TopOffset;
    rectpts[1].y = rectpts[2].y = y + TopOffset; 

    XDrawLines(XtDisplay(w), XtWindow(w),
      draw_it? w->dclock.foreGC : w->dclock.backGC,
      rectpts, 5, CoordModeOrigin);
}

Generated by  Doxygen 1.6.0   Back to index