v01i044: dclock: A digital clock widget and driver, Part01/01

Mike Wexler mikew at wyse.wyse.com
Fri Sep 16 05:24:59 AEST 1988


Submitted-by: dheller at cory (Dan Heller)
Posting-number: Volume 1, Issue 44
Archive-name: dclock/part01

Here's the latest dclock with patchlevel.h and everything.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	dclock.man
#	Makefile
#	Dclock.c
#	Dclock.h
#	DclockP.h
#	Patchlevel.h
#	dclock.c
# This archive created: Wed Sep 14 23:36:04 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(391 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \!Funky!Stuff! > 'README'
To compile, just run make and watch it go.

When the program is running and the mouse is in the window, you can
type the following keys:
    
    r -- toggle reverse video
    s -- toggle seconds display
    b -- toggle the bell to ring on half hours
    j -- toggle jump or smooth scrolling

This code was written by Dan Heller <island!argv at sun.com> for use by
those who find it useful :-)
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'dclock.man'" '(5033 characters)'
if test -f 'dclock.man'
then
	echo shar: "will not over-write existing file 'dclock.man'"
else
cat << \!Funky!Stuff! > 'dclock.man'
.TH DCLOCK 1 "1 March 1988" "X Version 11"
.SH NAME
dclock - digital clock for X
.SH SYNOPSIS
.B dclock
[-\fItoolkitoption\fP ...] [-option ...]
.SH DESCRIPTION
The
.I dclock 
program displays the time in digital format only.  The time is
updated on a per second basis or on a per minute basis.  This program is
nothing more than a wrapper around the dclock widget not associated with
the Athena Widget Set.
.sp
When the clock is running, the user may change attributes by typing:
.in +2
.nf
\fBr\fP\ \ Toggles \fBReverse Video\fP.
\fBs\fP\ \ Toggles the \fBseconds\fP display.
\fBb\fP\ \ Toggles the \fBbell\fP attribute (see below).
\fBj\fP\ \ Toggles the \fBjump/scroll\fP attribute (see below).
.in -2
.fi
.SH OPTIONS
.I Dclock
accepts all of the standard X Toolkit command line options along with the 
additional options listed below:
.TP 8
.B \-help
This option indicates that a brief summary of the allowed options should be
printed on the standard error.
.TP 8
.B \-bell
This option indicates that the beel will beep
once on the half hour and twice on the hour.
.TP 8
.B \-scroll
.br
.B \-noscroll
When the time changes, the digits scroll from the previous digit to the
next digit.  Since this is on by default, the -noscroll option can turn
it off.
.TP 8
.B \-date "format"
The date is printed under the time in the specified font.  The string
displayed is in the "format" argument.  If the string contains a formatting
character (%), then the next character is examined and a value is inserted
into the string.  Example:
.sp
.ti +2
dclock -date "Today is %W"
.sp
The date string will print "Today is Friday" if the weekday name happens
to be friday.  The formatting characters that are understood are:
.in +2
.nf
%W	Full weekday name
%w	Three-char weekday name (Sun, Mon, Tue...)
%M	Full month name
%m      Three-char abbreviation for that month (Jan, Feb, Mar...)
%d	The date (numerical day number of the month)
%Y	Full year (4 digits)
%y	2-digit year number
.fi
.in -2
.TP 8
.B \-seconds
This option will update the clock every second and display the time
including the seconds.
.TP 8
.B \-bg \fIcolor\fP
This option specifies the color to use for the background of the window.  
The default is ``white.''
.TP 8
.B \-bd \fIcolor\fP
This option specifies the color to use for the border of the window.
The default is ``black.''
.TP 8
.B \-bw \fInumber\fP
This option specifies the width in pixels of the border surrounding the window.
.TP 8
.B \-fg \fIcolor\fP
This option specifies the color to use for displaying text.  The default is 
``black''.
.TP 8
.B \-fn \fIfont\fP
This option specifies the font to be used for displaying normal text.  The
default is ``Fixed.''
.TP 8
.B \-rv
This option indicates that reverse video should be simulated by swapping
the foreground and background colors.
.TP 8
.B \-geometry \fIgeometry\fP
This option specifies the prefered size and position of the clock window.
.TP 8
.B \-display \fIhost\fP:\fIdisplay\fP
This option specifies the X server to contact.
.TP 8
.B \-xrm \fIresourcestring\fP
This option specifies a resource string to be used.  This is especially
useful for setting resources that do not have separate command line options.
.SH X DEFAULTS
It understands all of the core resource names and
classes as well as:
.PP
.TP 8
.B width (\fPclass\fB Width)
Specifies the width of the clock.
.TP 8
.B height (\fPclass\fB Height)
Specifies the height of the clock.
.TP 8
.B foreground (\fPclass\fB Foreground)
Specifies the color for the tic marks.  Using the class specifies the
color for all things that normally would appear in the foreground color.
The default is ``black'' since the core default for background is ``white.''
.TP 8
.B bell (\fPclass\fB Boolean)
Specifies whether or not a bell should be rung on the hour and half hour.
.TP 8
.B font (\fPclass\fB Font)
Specifies the font to be used for the date.
.TP 8
.B reverseVideo (\fPclass\fB ReverseVideo)
Specifies that the foreground and background colors should be reversed.
.TP 8
.B scroll (\fPclass\fB Boolean)
Specifies whether the digits should scroll or not.
.TP 8
.B seconds (\fPclass\fB Boolean)
Specifies whether the seconds should be displayed or not.
.TP 8
.B bell (\fPclass\fB Boolean)
Specifies whether the bell should sound on the half hour and on the hour.
.SH ENVIRONMENT
.PP
.TP 8
.B DISPLAY
to get the default host and display number.
.TP 8
.B XENVIRONMENT
to get the name of a resource file that overrides the global resources
stored in the RESOURCE_MANAGER property.
.SH "SEE ALSO"
X(1), xrdb(1), time(3C).
.SH BUGS
.I Dclock
believes the system clock.
.PP
Scrolling from 9 to 10 O'Clock seems weird, but chances are you won't
notice it.
.PP
If the window is too small, the seconds are tough to read.  This should
be recognized by the program and should display seconds using a font
rather than the bitmaps used by the clock itself.
.PP
Color has been untested.
.SH COPYRIGHT
Copyright (c) 1988, Dan Heller.
.SH AUTHOR
.nf
Dan Heller -- <island!argv at sun.com> or <dheller at cory.berkeley.edu>
.fi
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'Makefile'" '(310 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
# Please read the accompanying README file before running Make
SRCS= Dclock.c dclock.c
OBJS= Dclock.o dclock.o

CFLAGS= -O
LDFLAGS= -s
LIBS= -lXaw -lXt -lX

dclock: ${OBJS}
	cc ${LDFLAGS} ${OBJS} ${LIBS} -o dclock

clean: ; rm ${OBJS} core dclock

shar: ; shar README Makefile dclock.man ${SRCS} > dclock.shar
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'Dclock.c'" '(18921 characters)'
if test -f 'Dclock.c'
then
	echo shar: "will not over-write existing file 'Dclock.c'"
else
cat << \!Funky!Stuff! > 'Dclock.c'
/*
 * Dclock.c -- a digital clock widget.
 * Author: Dan Heller <island!argv at sun.com>
 */
#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/Xos.h>
#include <X11/StringDefs.h>
#include "DclockP.h"

static void
    Initialize(), Resize(), Realize(), Destroy(), Redisplay(),
    timeout(), toggle_bell(), toggle_reverse_video(), toggle_scroll(),
    toggle_seconds(), show_dialog_box(), GetGC(), make_number(), show_time(),
    show_date(), scroll_time();

#define BORDER		5
#define CLOCK_WIDTH	256
#define CLOCK_HEIGHT	80
#define when		break;case
#define otherwise	break;default

static Boolean SetValues();
static int winwidth = CLOCK_WIDTH;
static int winheight = CLOCK_HEIGHT;
static Boolean false = False;
static Boolean true = True;
static double x_ratio, y_ratio;
static Pixmap old_pix[4];
static struct tm before;

extern int exit();

static char defaultTranslations[] =
    "<Key>b:		toggle-bell()		\n\
     <Key>j:		toggle-scroll()		\n\
     <Key>r:		toggle-reverse-video()	\n\
     <Key>s:		toggle-seconds()	\n\
     <Btn3Down>:	dialog-box()";

static XtActionsRec actionsList[] = {
    { "toggle-bell",		toggle_bell		},
    { "toggle-scroll",		toggle_scroll		},
    { "toggle-reverse-video",	toggle_reverse_video	},
    { "toggle-seconds",		toggle_seconds		},
    { "dialog-box",		show_dialog_box		},
};

static XtResource resources[] = {
    { XtNwidth, XtCWidth, XtRInt, sizeof(int),
	XtOffset(Widget,core.width), XtRInt, (caddr_t)&winwidth },
    { XtNheight, XtCHeight, XtRInt, sizeof(int),
	XtOffset(Widget,core.height), XtRInt, (caddr_t)&winheight },
    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
        XtOffset(DclockWidget,dclock.foreground), XtRString, "Black"},
    { XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
	XtOffset(DclockWidget,dclock.reverse), XtRBoolean, (caddr_t)&false},
    { XtNscroll, XtCBoolean, XtRBoolean, sizeof (Boolean),
	XtOffset(DclockWidget,dclock.scroll), XtRBoolean, (caddr_t)&true},
    { 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},
    { XtNdate, XtCString, XtRString, sizeof (String),
	XtOffset(DclockWidget,dclock.date_fmt), XtRString, NULL},
    { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
	XtOffset(DclockWidget,dclock.font), XtRString, "Fixed"},
};

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		*/	NULL,
    /* 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;

/* ARGSUSED */
static void
Initialize (request, new)
DclockWidget   request;
DclockWidget   new;
{
    GetGC(new);
}

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

#ifdef NOT_NOW
    if (w->dclock.reverse) {
	Pixel fg = w->dclock.foreground;
	Pixel bg = w->core.background_pixel;

	if (w->core.border_pixel == fg)
	    w->core.border_pixel = bg;
	w->dclock.foreground = bg;
	w->core.background_pixel = fg;
	xgcv.function = GXcopyInverted;        gc_mask |= GCFunction;
    } else
	xgcv.function = GXcopy;        gc_mask |= GCFunction;
#endif /* NOT_NOW */

    xgcv.font = w->dclock.font->fid;
    xgcv.foreground = BlackPixel(XtDisplay(w), DefaultScreen(XtDisplay(w)));
    xgcv.background = WhitePixel(XtDisplay(w), DefaultScreen(XtDisplay(w)));
    /*
    xgcv.foreground = w->dclock.foreground;
    xgcv.background = w->core.background_pixel;
    */

    w->dclock.foreGC = XtGetGC ((Widget) w, gc_mask, &xgcv);
    xgcv.foreground = w->core.background_pixel;
    xgcv.background = w->dclock.foreground;
    w->dclock.backGC = XtGetGC ((Widget) w, gc_mask, &xgcv);
}

static void
Realize (w, valueMask, attrs)
Widget w;
XtValueMask *valueMask;
XSetWindowAttributes *attrs;
{
    *valueMask |= CWBitGravity;
    attrs->bit_gravity = ForgetGravity;
    XtCreateWindow (w, InputOutput, (Visual *) CopyFromParent,
		    *valueMask, attrs);
    Resize(w);
}

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

    XtRemoveTimeOut(w->dclock.interval_id);
    XtDestroyGC (w->dclock.foreGC);
    XtDestroyGC (w->dclock.backGC);
    for (n = 0; n < 10; n++) {
	XFreePixmap(XtDisplay(w), w->dclock.digits[n]);
	XFreePixmap(XtDisplay(w), w->dclock.tiny_digits[n]);
    }
    if (w->dclock.colon[0])
	XFreePixmap(XtDisplay(w), w->dclock.colon[0]);
    if (w->dclock.colon[1])
	XFreePixmap(XtDisplay(w), w->dclock.colon[1]);
}
 
/* ARGSUSED */
static void
Resize  (w)
DclockWidget    w;
{
    int i, digit_w, digit_h;
    Pixmap pix;
    GC gc;

    if (!XtIsRealized(w))
	return;

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

    x_ratio = (double)winwidth / CLOCK_WIDTH;
    y_ratio =  (double)winheight / CLOCK_HEIGHT;

    if (w->dclock.date_fmt)
	/* make win temporarily shorter so digits will fit on top of date */
	winheight -= w->dclock.font->ascent + w->dclock.font->descent;

    digit_w = winwidth/(4 - !w->dclock.seconds) - (int)(x_ratio*BORDER*5);
    digit_h = winheight - (int)(y_ratio * BORDER*2);
    w->dclock.digit_w = digit_w;
    w->dclock.digit_h = digit_h;

    gc = w->dclock.reverse? w->dclock.backGC : w->dclock.foreGC;

    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), digit_w, digit_h, 1);
	make_number(w, w->dclock.digits[i], gc, i, digit_w, digit_h);

	/* make smaller version of this digit for use by "seconds" */
	if (w->dclock.tiny_digits[i])
	    XFreePixmap(XtDisplay(w), w->dclock.tiny_digits[i]);
	w->dclock.tiny_digits[i] =
	      XCreatePixmap(XtDisplay(w), XtWindow(w), digit_w/2,digit_h/2,1);
	make_number(w, w->dclock.tiny_digits[i], gc, i, digit_w/2, digit_h/2);
    }
    /* The colon[0] area is blank */
    if (w->dclock.colon[0])
	XFreePixmap(XtDisplay(w), w->dclock.colon[0]);
    w->dclock.colon[0] =
	XCreatePixmap(XtDisplay(w), XtWindow(w), digit_w, digit_h, 1);
    if (w->dclock.reverse)
	XFillRectangle(XtDisplay(w), w->dclock.colon[0], w->dclock.foreGC,
		       0, 0, digit_w,digit_h);
    else
	XFillRectangle(XtDisplay(w), w->dclock.colon[0], w->dclock.backGC,
		       0, 0, digit_w,digit_h);

    /* colon[1] area has two squares */
    if (w->dclock.colon[1])
	XFreePixmap(XtDisplay(w), w->dclock.colon[1]);
    w->dclock.colon[1] = XCreatePixmap(XtDisplay(w), XtWindow(w),
				       (int)(30*x_ratio), digit_h, 1);
    if (w->dclock.reverse)
	/* black background with white squres */
        XFillRectangle(XtDisplay(w), w->dclock.colon[1], w->dclock.foreGC,
		       0, 0, (int)(30*x_ratio), digit_h);
    else
        XFillRectangle(XtDisplay(w), w->dclock.colon[1], w->dclock.backGC,
		       0, 0, (int)(30*x_ratio), digit_h);
    XFillArc(XtDisplay(w), w->dclock.colon[1], gc,
	    (int)(15*x_ratio), digit_h/3, digit_w/7, digit_w/7,
	    0, 360 * 64);
    XFillArc(XtDisplay(w), w->dclock.colon[1], gc,
	    (int)(15*x_ratio), (2*digit_h)/3, digit_w/7, digit_w/7,
	    0, 360 * 64);

    /* to optimize scrolling information (see scroll_time()) */
    old_pix[0] = w->dclock.digits[0];
    old_pix[1] = old_pix[2] = old_pix[3] = 0;

    if (w->dclock.date_fmt)
	/* restore size */
	winheight += w->dclock.font->ascent + w->dclock.font->descent;
}

/* Defines to draw the (simulated) LED bars for each light in the digit */
#define TOP    (pts[0].x = 2, pts[0].y = pts[1].y = 0, pts[1].x = w-2, \
                pts[3].x = 2+6*x_ratio, pts[3].y = pts[2].y = 6*y_ratio, \
		pts[2].x = w - pts[3].x, \
		XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

#define MIDDLE (pts[0].x = 2, pts[0].y = h/2 - 1, \
		pts[1].x = 6*x_ratio, pts[1].y = h/2 - 3*y_ratio, \
                pts[2].x = w-pts[1].x, pts[2].y = pts[1].y, \
                pts[3].x = w-2, pts[3].y = h/2 - 1, \
		pts[4].x = pts[2].x, pts[4].y = h/2 + 3*y_ratio, \
		pts[5].x = pts[1].x, pts[5].y = pts[4].y, \
		XFillPolygon(dpy, pix, gc, pts, 6, Convex, CoordModeOrigin));

#define BOTTOM (pts[0].x = 2, pts[0].y = pts[1].y = h, pts[1].x = w-2, \
                pts[3].x = 6*x_ratio, pts[3].y = pts[2].y = h - 6*y_ratio, \
		pts[2].x = w - pts[3].x, \
		XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

#define T_LEFT (pts[0].x = pts[1].x = 0, pts[0].y = 2, pts[1].y = h/2-2, \
                pts[2].x = pts[3].x = 6*x_ratio, \
		pts[2].y = h/2 - 5*y_ratio, pts[3].y = 8*y_ratio, \
		XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

#define B_LEFT (pts[0].x = pts[1].x = 0, pts[0].y = h/2, pts[1].y = h, \
                pts[2].x = pts[3].x = 6*x_ratio, \
		pts[3].y = h/2 + 5*y_ratio, pts[2].y = h - 8*y_ratio, \
		XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

#define T_RIGHT (pts[0].x = pts[1].x = w, pts[0].y = 2, pts[1].y = h/2-2, \
                 pts[2].x = pts[3].x = w-6*x_ratio, \
		 pts[2].y = h/2 - 5*y_ratio, pts[3].y = 8*y_ratio, \
		 XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

#define B_RIGHT (pts[0].x = pts[1].x = w, pts[0].y = h/2, pts[1].y = h, \
                 pts[2].x = pts[3].x = w-6*x_ratio, \
		 pts[3].y = h/2 + 5*y_ratio, pts[2].y = h - 8*y_ratio, \
		 XFillPolygon(dpy, pix, gc, pts, 4, Convex, CoordModeOrigin));

static void
make_number(dw, pix, gc, n, w, h)
DclockWidget dw;
Pixmap pix;
GC gc;
int n, w, h;
{
    XPoint pts[6];
    Display *dpy = XtDisplay(dw);

    if (dw->dclock.reverse)
	XFillRectangle(dpy, pix, dw->dclock.foreGC, 0, 0, w, h);
    else
	XFillRectangle(dpy, pix, dw->dclock.backGC, 0, 0, w, h);
    switch(n) {
	when 0: TOP  T_RIGHT  B_RIGHT  BOTTOM  B_LEFT  T_LEFT
	when 1: T_RIGHT  B_RIGHT
	when 2: TOP  T_RIGHT  MIDDLE  B_LEFT  BOTTOM
	when 3: TOP  T_RIGHT  MIDDLE  B_RIGHT  BOTTOM
	when 4: T_LEFT  MIDDLE  T_RIGHT  B_RIGHT
	when 5: TOP  T_LEFT  MIDDLE  B_RIGHT  BOTTOM
	when 6: T_LEFT  B_LEFT  MIDDLE BOTTOM B_RIGHT
	when 7: TOP  T_RIGHT  B_RIGHT
	when 8: T_LEFT B_LEFT MIDDLE TOP BOTTOM T_RIGHT B_RIGHT
	when 9: TOP T_LEFT T_RIGHT MIDDLE B_RIGHT
	otherwise: MIDDLE
    }
}

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

    if (!XtIsRealized(w))
	return;

    if (w->dclock.interval_id)
	XtRemoveTimeOut(w->dclock.interval_id);
    if (w->dclock.reverse)
	XFillRectangle(XtDisplay(w), XtWindow(w), w->dclock.foreGC,
	    0, 0, w->core.width, w->core.height);
    else
	XClearWindow(XtDisplay(w), XtWindow(w));
    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;
    w->dclock.scroll = FALSE;
    show_time(w);
    w->dclock.scroll = save_scroll;
    if (w->dclock.seconds)
	w->dclock.interval_id = XtAddTimeOut(1000, timeout, w);
    else {
	t = time(0);
	w->dclock.interval_id =
	    XtAddTimeOut((unsigned long)(60 - (t % 60)) * 1000, timeout, w);
    }
}

static void
show_time(w)
DclockWidget w;
{
    char buf[11];
    long t = time(0);
    register struct tm *l_time = localtime(&t);
    int digit_w = w->dclock.digit_w;
    int digit_h = w->dclock.digit_h;
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    GC gc = w->dclock.reverse ? w->dclock.backGC : w->dclock.foreGC;

    (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);

    if (l_time->tm_min != before.tm_min || l_time->tm_hour != before.tm_hour)
	scroll_time(w, buf);

    if (w->dclock.seconds) {
	XCopyArea(dpy, w->dclock.tiny_digits[l_time->tm_sec/10], win, gc, 0, 0,
		  digit_w/2, digit_h/2,
		  winwidth - 2*(digit_w/2 + (int)(BORDER*x_ratio)),
		  (int)(BORDER*y_ratio));
	XCopyArea(dpy, w->dclock.tiny_digits[l_time->tm_sec%10], win, gc, 0, 0,
		  digit_w/2, digit_h/2,
		  winwidth - digit_w/2 - (int)(BORDER*x_ratio),
		  (int)(BORDER*y_ratio));
    }

    XCopyArea(dpy, w->dclock.colon[(!w->dclock.seconds || l_time->tm_sec & 1)],
	    win, gc, 0, 0,
	    (int)(30*x_ratio), digit_h,
	    (int)(-digit_w*.75 + 2*BORDER*x_ratio) + 2*digit_w,
	    (int)(BORDER*y_ratio));

    if (w->dclock.date_fmt && before.tm_wday != l_time->tm_wday)
	show_date(w, l_time);

    if (w->dclock.bell && (!w->dclock.seconds || l_time->tm_sec == 0) &&
	(l_time->tm_min == 0 || l_time->tm_min == 30)) {
	XBell(dpy, 50);
	if (l_time->tm_min == 0)
	    XBell(dpy, 50);
    }
    before = *l_time;
}

static void
scroll_time(w, p)
DclockWidget w;
register char *p;
{
    int scroll_me[4], J = winheight - BORDER*2*y_ratio + 1;
    register int i, j, incr;
    int digit_w = w->dclock.digit_w;
    int digit_h = w->dclock.digit_h;
    Display *dpy = XtDisplay(w);
    Window win = XtWindow(w);
    GC gc = w->dclock.reverse? w->dclock.backGC : w->dclock.foreGC;
    Pixmap tmp[4];

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

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

#define x ((int)(-digit_w*.75 + ((i+1)*BORDER + (i>1)*30)*x_ratio) + i*digit_w)
#define y (int)(BORDER * y_ratio)

    for (i = 0; i < 4; i++)    /* if pixrects don't match, scroll it */
	scroll_me[i] = ((tmp[i] = w->dclock.digits[*p++ - '0']) != old_pix[i]);
    if (w->dclock.scroll &&
	(scroll_me[0] || scroll_me[1] || scroll_me[2] || scroll_me[3]))
	for (j = 0; j <= J; j += incr)
	    for (i = 0; i < 4; i++)
		if (scroll_me[i]) {
		    if (old_pix[i])
			XCopyArea(dpy, old_pix[i], win, gc,
			    0, j, digit_w, digit_h - j, x, y);
		    if (i || tmp[i] == w->dclock.digits[1])
			XCopyArea(dpy, tmp[i], win, gc,
			    0, 0, digit_w, j, x, y + digit_h - j);
		    else
			XCopyArea(dpy, w->dclock.colon[0], win, gc,
			    0, 0, x+5, y + digit_h - j, digit_w, j);
		}

    for (i = 0; i < 4; i++)
	if (i || tmp[0] == w->dclock.digits[1])
	    XCopyArea(dpy, tmp[i], win, gc, 0,0, digit_w, digit_h, x,y);
	else
	    XCopyArea(dpy, w->dclock.colon[0], win, gc,
		0,0, digit_w,digit_h, x+5,y);
#undef x
#undef y
    for (i = 0; i < 4; i++)
	old_pix[i] = tmp[i];
}

static char *months[] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
    "Aug", "Sep", "Oct", "Nov", "Dec"
};
static char *Months[] = {
    "January", "February", "March", "April", "May", "June", "July",
    "August", "September", "October", "November", "December"
};
static char *days[] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
};
static char *Days[] = {
    "Sunday", "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday", "Sunday"
};

static void
show_date(w, now)
DclockWidget w;
struct tm *now;
{
    char datestr[128];
    register char *datep = datestr, *p;
    int x;

    if (!w->dclock.date_fmt)
	return;

#if 0
    if (set_alarm)
	sprintf(datestr, "Alarm is %s.", alarm_time.tm_sec < 0? "off" : "on");
    else
#endif /* 0 */
    {
	for (p = w->dclock.date_fmt; *p; p++) {
	    if (*p != '%')
		*datep++ = *p;
	    else switch (*++p) {
		when 'M':
		    datep += strlen(strcpy(datep, Months[now->tm_mon]));
		when 'm':
		    datep += strlen(strcpy(datep, months[now->tm_mon]));
		when 'W':
		    datep += strlen(strcpy(datep, Days[now->tm_wday]));
		when 'w':
		    datep += strlen(strcpy(datep, days[now->tm_wday]));
		when 'd':
		    if (now->tm_mday >= 10)
			*datep++ = (now->tm_mday / 10 + '0');
		    *datep++ = now->tm_mday % 10 + '0';
		when 'Y':
		    *datep++ = '1', *datep++ = '9';
		    /* fall thru */
		case 'y':
		    *datep++ = now->tm_year / 10 + '0';
		    *datep++ = now->tm_year % 10 + '0';
		when '%':
		    *datep++ = *p;
		otherwise: ; /* nothing */
	    }
	}
	*datep = 0;
    }
    x = (w->core.width - XTextWidth(w->dclock.font, datestr, datep-datestr))/2;
    if (x < 2)
	x = 2;

    /* remove what was there in case the whole thing isn't overwritten */
    if (w->dclock.reverse)
	XFillRectangle(XtDisplay(w), XtWindow(w), w->dclock.foreGC,
	   0, winheight - (w->dclock.font->ascent + w->dclock.font->descent),
	   winwidth, w->dclock.font->ascent + w->dclock.font->descent);
    else
	XClearArea(XtDisplay(w), XtWindow(w),
	   0, winheight - (w->dclock.font->ascent + w->dclock.font->descent),
	   winwidth, w->dclock.font->ascent + w->dclock.font->descent, False);

    XDrawString(XtDisplay(w), XtWindow(w),
	w->dclock.reverse? w->dclock.backGC : w->dclock.foreGC,
	x, winheight - BORDER, datestr, (int)(datep - datestr));
}


static void
timeout(w, id)
DclockWidget w;
XtIntervalId *id;
{
    show_time(w);
    w->dclock.interval_id =
	XtAddTimeOut(w->dclock.seconds? 1000 : 60000, timeout, w);
}

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

    if (new->dclock.foreground != current->dclock.foreground
    ||  new->core.background_pixel != current->core.background_pixel
    ||  new->dclock.reverse != current->dclock.reverse) {
	XtDestroyGC (current->dclock.foreGC);
	XtDestroyGC (current->dclock.backGC);
	GetGC(new);
	Resize(new); /* pixmaps need to be redrawn */
	do_redraw = True;
    }
    if (new->dclock.seconds != current->dclock.seconds) {
	XtRemoveTimeOut(current->dclock.interval_id);
	Resize(new);
	do_redraw = True;
    }
    if (new->dclock.date_fmt != current->dclock.date_fmt) {
	do_redraw = True;
	before.tm_wday = -1;
    }

    return do_redraw;
}

static void
toggle_bell(w)
DclockWidget w;
{
    if (w->dclock.bell = !w->dclock.bell)
	XBell(XtDisplay(w), 50);
}

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

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

    XtSetArg(arg, XtNreverseVideo, !w->dclock.reverse);
    XtSetValues(w, &arg, 1);
}

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

    XtSetArg(arg, XtNseconds, !w->dclock.seconds);
    XtSetValues(w, &arg, 1);
}

static void
show_dialog_box(w)
Widget w;
{
    XBell(XtDisplay(w), 50);
}
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'Dclock.h'" '(1430 characters)'
if test -f 'Dclock.h'
then
	echo shar: "will not over-write existing file 'Dclock.h'"
else
cat << \!Funky!Stuff! > 'Dclock.h'
/*
 * Dclock.c -- a digital clock widget.
 * Author: Dan Heller <island!argv at sun.com>
 */
#ifndef _XtDclock_h
#define _XtDclock_h

/* Parameters:

 Name                Class              RepType         Default Value
 ----                -----              -------         -------------
 background          Background         pixel           White
 bell                Boolean            Boolean         False
 border              BorderColor        pixel           Black      
 borderWidth         BorderWidth        int             1
 date                String             String          NULL
 destroyCallback     Callback           Pointer         NULL
 foreground          Foreground         Pixel           Black 
 height              Height             int             80
 mappedWhenManaged   MappedWhenManaged  Boolean         True
 reverseVideo        ReverseVideo       Boolean         False
 seconds             Boolean            Boolean         False
 scroll              Boolean            Boolean         True
 x                   Position           int             0 
 y                   Position           int             0

*/

#define XtNseconds      "seconds"
#define XtNbell         "bell"
#define XtNscroll       "scroll"
#define XtNdate         "date"

typedef struct _DclockRec *DclockWidget;
typedef struct _DclockClassRec *DclockWidgetClass;

extern WidgetClass dclockWidgetClass;

#endif _XtDclock_h
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'DclockP.h'" '(882 characters)'
if test -f 'DclockP.h'
then
	echo shar: "will not over-write existing file 'DclockP.h'"
else
cat << \!Funky!Stuff! > 'DclockP.h'
/*
 * Dclock.c -- a digital clock widget.
 * Author: Dan Heller <island!argv at sun.com>
 */
#ifndef _XtDclockP_h
#define _XtDclockP_h

#include <X11/CoreP.h>
#include "Dclock.h"

typedef struct {
    Pixel      		foreground;
    Boolean    		reverse;
    Boolean		scroll;
    Boolean		seconds;
    Boolean		bell;
    String		date_fmt;
    XFontStruct		*font;

    /* non-resources (e.g. user can't set) */
    XtIntervalId	interval_id;
    GC			foreGC, backGC;
    int			digit_w, digit_h;
    Pixmap		digits[10];
    Pixmap		tiny_digits[10];
    Pixmap		colon[2];
} DclockPart;

typedef struct _DclockRec {
    CorePart	core;
    DclockPart	dclock;
} DclockRec;

typedef struct {int dummy;} DclockClassPart;

typedef struct _DclockClassRec {
    CoreClassPart	core_class;
    DclockClassPart	dclock_class;
} DclockClassRec;

extern DclockClassRec dclockClassRec;

#endif _XtDclockP_h
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'Patchlevel.h'" '(21 characters)'
if test -f 'Patchlevel.h'
then
	echo shar: "will not over-write existing file 'Patchlevel.h'"
else
cat << \!Funky!Stuff! > 'Patchlevel.h'
#define PATCHLEVEL 0
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'dclock.c'" '(2421 characters)'
if test -f 'dclock.c'
then
	echo shar: "will not over-write existing file 'dclock.c'"
else
cat << \!Funky!Stuff! > 'dclock.c'
/*
 * dclock -- program to demonstrate how to use the digital-clock widget.
 * To specify a date, the date format is a string of characters.  If a
 * character in the string is a %-sign, the next character is examined
 * and a value is inserted into the string.  Example:
 *    dclock -date "Today is %W"
 * The date string will print "Today is" and then the %W will be replaced
 * by the current weekday name.  The parameters are:
 *    %W	full weekday name
 *    %w	three-char weekday name (sun, mon, tue, wed...)
 *    %M	full month name
 *    %m        three-char abbreviation for that month (jan, feb, mar...)
 *    %d	The date (numerical number of the month)
 *    %Y	full year (4 digits)
 *    %y	2-digit year number
 *
 * To specify seconds to be displayed, use "-seconds" or use the resource
 * manager: *Dclock.seconds: on
 */
#include <stdio.h>
#include <X11/Intrinsic.h>
#include "Dclock.h"

static XrmOptionDescRec options[] = {
    {"-date",	 "*Dclock.date",	XrmoptionSepArg, NULL },
    {"-seconds", "*Dclock.seconds",	XrmoptionNoArg, "TRUE" },
    {"-bell",	 "*Dclock.bell",	XrmoptionNoArg, "TRUE" },
    {"-scroll",  "*Dclock.scroll",	XrmoptionNoArg, "TRUE" },
    {"-noscroll","*Dclock.scroll",	XrmoptionNoArg, "FALSE" },
};

static void
Usage(name)
String name;
{
    static char *help_message[] = {
	"where options include:",
	"    -bg color                  background color",
	"    -fg color                  foreground color",
	"    -fn font			font name",
	"    -rv                        reverse video",
	"    -geometry geom             size of mailbox",
	"    -display host:dpy          X server to contact",
	"    -seconds [on/off]		display seconds",
	"    -bell [on/off]		ring bell each half hour",
	"    -scroll [on/off]		turn off scrolling",
	"    -date \"date format\"	show the date in specified format",
	NULL
    };
    char **cpp;

    fprintf(stderr, "usage: %s [-options ...]\n", name);
    for (cpp = help_message; *cpp; cpp++)
	fprintf(stderr, "%s\n", *cpp);
    exit(1);
}

main(argc, argv)
char *argv[];
{
    Widget toplevel;
    char *name, *rindex();

    if (name = rindex(argv[0], '/'))
	name++;
    else
	name = argv[0];

    toplevel = XtInitialize(name, "DClock", options, XtNumber(options),
			    &argc,argv);

    if (argc != 1)
	Usage(name);

    XtCreateManagedWidget("dclock", dclockWidgetClass, toplevel, NULL, 0);

    XtRealizeWidget(toplevel);
    XtMainLoop();
}
!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive
-- 
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330



More information about the Comp.sources.x mailing list