/* * Dclock.c (v.2.0) -- a digital clock widget. * Copyright (c) 1988 Dan Heller * Modifications 2/93 by Tim Edwards */ #include #include #include #include #include #include #include #include #include #include #include #include #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 int 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[] = "b: toggle-bell() \n\ j: toggle-scroll() \n\ f: toggle-fade() \n\ s: toggle-seconds() \n\ r: toggle-reverse-video() \n\ colon: toggle-blink() \n\ m: toggle-military-time() \n\ d: toggle-date() \n\ u: toggle-dateup() \n\ t: toggle-tails() \n\ a: toggle-alarm() \n\ h: print-help() \n\ Shiftslash: print-help() \n\ v: print-dump() \n\ +: widen-segment() \n\ -: thin-segment() \n\ slash: slope-increase() \n\ backslash: slope-decrease() \n\ Shiftcomma: space-decrease() \n\ Shiftperiod: space-increase() \n\ : 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, NULL}, #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/local/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 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 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 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 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]; 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; #ifdef XFT_SUPPORT #define XFT_COND(dclock) ((dclock).xftfontname) #else #define XFT_COND(dclock) (0) #endif /* 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 if (XFT_COND(new->dclock)) { 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) if (XFT_COND(new->dclock)) { TopOffset = new->core.height / 6; } else { TopOffset = new->dclock.font->ascent + new->dclock.font->descent; } 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) 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 (XFT_COND(dw->dclock) && 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 if (XFT_COND(w->dclock)) 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 if(XFT_COND(w->dclock)) { 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 */ { if(XFT_COND(w->dclock)) { winheight -= w->core.height / 6; } else { winheight -= w->dclock.font->ascent + w->dclock.font->descent; } } /* * 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; time_t 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; time_t 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; time_t 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; int tsize; #ifdef XFT_SUPPORT XGlyphInfo xftextents; #endif if (XFT_COND(w->dclock)) { tsize = w->core.height / 6; } else { tsize = w->dclock.font->ascent + w->dclock.font->descent; } 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); if (XFT_COND(w->dclock)) { #ifdef XFT_SUPPORT XftTextExtents8(dpy, w->dclock.xftfont, (FcChar8*)datestr, datep, &xftextents); x = (w->core.width - xftextents.width) / 2; #endif } else { x = (w->core.width - XTextWidth(w->dclock.font, datestr, datep)) / 2; } if (x < 2) x = 2; if (TopOffset) { if (XFT_COND(w->dclock)) { #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, (FcChar8*)datestr, datep); #endif } else { XFillRectangle(dpy, win, w->dclock.backGC, 0, 0, winwidth, tsize); XDrawString(dpy, win, w->dclock.foreGC, x, ((BORDER/2)+tsize), datestr, datep); } } else { if (XFT_COND(w->dclock)) { #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, (FcChar8*)datestr, datep); #endif } else { XFillRectangle(dpy, win, w->dclock.backGC, 0, winheight - tsize, winwidth, tsize); XDrawString(dpy, win, w->dclock.foreGC, x, winheight - BORDER, datestr, datep); } } } 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, " Toggle Alarm-time display\n"); fprintf(stderr, " Increment number in alarm-time display\n"); fprintf(stderr, " 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) : ""); 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) { if (XFT_COND(w->dclock)) { TopOffset = w->core.height / 6; } else { TopOffset = w->dclock.font->ascent + w->dclock.font->descent; } } 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) { if (XFT_COND(w->dclock)) { TopOffset = w->core.height / 6; } else { TopOffset = w->dclock.font->ascent + w->dclock.font->descent; } } 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 int 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 */ if (XFT_COND(w->dclock)) { 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)); } 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); }