/* -*- Mode: C; tab-width: 4 -*- */ /* dclock --- floating digital clock or message */ #if !defined( lint ) && !defined( SABER ) static const char sccsid[] = "@(#)dclock.c 5.00 2000/11/01 xlockmore"; #endif /*- * Copyright (C) 1995 by Michael Stembera . * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * Revision History: * 03-Dec-2005: Added a binary clock display, after seeing the binary clock * at thinkgeek. Petey (petey_leinonen@yahoo.com.au) * 01-Mar-2005: Added 24 hour clock (alex(at)shark-linux(dot)de) * 01-Nov-2000: Allocation checks * 07-May-1999: New "savers" added for y2k and second millennium countdowns. * Tom Schmidt * 04-Dec-1998: New "savers" added for hiv, veg, and lab. * hiv one due to Kenneth Stailey * 10-Aug-1998: Population Explosion and Tropical Forest Countdown stuff * I tried to get precise numbers but they may be off a few * percent. Whether or not, its still pretty scary IMHO. * Although I am a US citizen... I have the default for area in * metric. David Bagley * 10-May-1997: Compatible with xscreensaver * 29-Aug-1995: Written. */ /*- * Some of my calculations laid bare... (I have a little problem with * the consistency of the numbers I got at the Bronx Zoo but proportions * were figured to be 160.70344 people a minute increase not 180 and * 35.303144 hectares (87.198766 acres) a minute decrease not 247 (100 acres). * So I am going with these more conservative numbers.) * * Time 0 is 0:00:00 1 Jan 1970 at least according to hard core UNIX fans * Minutes from 1 Jan 1970 to 21 Jun 1985: 8137440 * Minutes from 21 Jun 1985 to 12 Jul 1988: 6867360 * Total: 15004800 * * Population Explosion Saver (popex) * 3,535,369,000 people (figured by extrapolation) 1 Jan 1970 * 4,843,083,596 people 21 Jun 1985 (Opening of Wild Asia in the Bronx Zoo) * 5,946,692,000 people 12 Jul 1998 (David Bagley visits zoo ;) ) * 180 people a minute increase in global population (I heard 170 also) * 260,000 people a day increase in global population * * Tropical Forest Countdown Saver (forest) * 1,184,193,000 hectares (figured by extrapolation) 1 Jan 1970 * (2,924,959,000 acres) * 896,916,700 hectares 21 Jun 1985 (Opening of Wild Asia in the Bronx Zoo) * (2,215,384,320 acres) * 654,477,300 hectares 12 Jul 1998 (David Bagley visits zoo ;) ) * (1,616,559,000 acres) * 247 hectares a minute lost forever (1 hectare = 2.47 acres) * * HIV Infection Counter Saver (hiv) (stats from http://www.unaids.org/) * 33,600,000 31 Dec 1999 living w/HIV * 16,300,000 31 Dec 1999 dead * 49,900,000 31 Dec 1999 total infections * 5,600,000 new infections in 1999 * 10.6545 infections/min * -118,195,407 virtual cases (figured by extrapolation) 1 Jan 1970 * (this is a result of applying linear tracking to a non-linear event) * * Animal Research Counter Saver (lab) * Approximately 17-22 million animals are used in research each year. * OK so assume 17,000,000 / 525960 = 32.32184957 per minute * http://www.fcs.uga.edu/~mhulsey/GDB.html * * Animal Consumation Counter Saver (veg) * Approximately 5 billion are consumed for food annually. * OK 5,000,000,000 / 525960 = 9506.426344209 per minute * http://www.fcs.uga.edu/~mhulsey/GDB.html */ #ifdef STANDALONE #define MODE_dclock #define PROGCLASS "Dclock" #define HACK_INIT init_dclock #define HACK_DRAW draw_dclock #define dclock_opts xlockmore_opts #define DEFAULTS "*delay: 10000 \n" \ "*cycles: 10000 \n" \ "*ncolors: 64 \n" #define BRIGHT_COLORS #define UNIFORM_COLORS #include "xlockmore.h" /* in xscreensaver distribution */ #include "mode.h" #else /* STANDALONE */ #include "xlock.h" /* in xlockmore distribution */ #include "util.h" #endif /* STANDALONE */ #include "iostuff.h" #ifdef MODE_dclock #ifndef METRIC #define METRIC 1 #endif #if METRIC #define AREA_MIN 35.303144 #define AREA_TIME_START 1184193000.0 #else #define AREA_MIN 87.198766 #define AREA_TIME_START 2924959000.0 #endif #define PEOPLE_MIN 160.70344 #define PEOPLE_TIME_START 3535369000.0 #define HIV_MIN 10.6545 #define HIV_TIME_START -118195407.0 #define LAB_MIN 32.32184957 #define LAB_TIME_START 0 #define VEG_MIN 9506.426344209 #define VEG_TIME_START 0 /* epoch time at midnight 1 January 2000 UTC */ #define Y2K_TIME_START (((30 * 365) + 7) * 24 * 60 * 60) #define Y2001_TIME_START (Y2K_TIME_START + 366 * 24 * 60 * 60) #define LED_LEAN 0.2 #define LED_XS 30.0 #define LED_YS 45.0 #define LED_WIDTH (0.15 * LED_YS) #define LED_INC (LED_LEAN * LED_XS) /* LEAN and INC do not have to be linked */ #define BINARY_WIDTH 10 #define BINARY_HEIGHT 10 #define BINARY_INC 5 #define DEF_BINARY "False" #define DEF_LED "False" #define DEF_POPEX "False" #define DEF_FOREST "False" #define DEF_HIV "False" #define DEF_LAB "False" #define DEF_VEG "False" #define DEF_TIME24 "False" #define DEF_Y2K "False" #define DEF_Y2001 "False" /*- If you remember your Electronics course... a _ f / / b -g e /_/ c d */ #define MAX_LEDS 7 static unsigned char digits[][MAX_LEDS]= { /* a b c d e f g */ {1, 1, 1, 1, 1, 1, 0}, /* 0 */ {0, 1, 1, 0, 0, 0, 0}, /* 1 */ {1, 1, 0, 1, 1, 0, 1}, /* 2 */ {1, 1, 1, 1, 0, 0, 1}, /* 3 */ {0, 1, 1, 0, 0, 1, 1}, /* 4 */ {1, 0, 1, 1, 0, 1, 1}, /* 5 */ {1, 0, 1, 1, 1, 1, 1}, /* 6 */ {1, 1, 1, 0, 0, 0, 0}, /* 7 */ {1, 1, 1, 1, 1, 1, 1}, /* 8 */ {1, 1, 1, 1, 0, 1, 1} /* 9 */ #if 0 , /* Completeness, we must have completeness */ {1, 1, 1, 0, 1, 1, 1}, /* A */ {0, 0, 1, 1, 1, 1, 1}, /* b */ {1, 0, 0, 1, 1, 1, 0}, /* C */ {0, 1, 1, 1, 1, 0, 1}, /* d */ {1, 0, 0, 1, 1, 1, 1}, /* E */ {1, 0, 0, 0, 1, 1, 1} /* F */ #define MAX_DIGITS 16 #else #define MAX_DIGITS 10 #endif }; static Bool led; /* Create an virtual parallelogram, normal rectangle parameters plus "lean": the amount the start of a will be shifted to the right of the start of d. */ static XPoint parallelogramUnit[4] = { {1, 0}, {2, 0}, {-1, 1}, {-2, 0} }; static Bool binary; static Bool popex; static Bool forest; static Bool hiv; static Bool lab; static Bool veg; static Bool time24; static Bool y2k; static Bool millennium; static XrmOptionDescRec opts[] = { {(char *) "-binary", (char *) ".dclock.binary", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+binary", (char *) ".dclock.binary", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-led", (char *) ".dclock.led", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+led", (char *) ".dclock.led", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-popex", (char *) ".dclock.popex", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+popex", (char *) ".dclock.popex", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-forest", (char *) ".dclock.forest", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+forest", (char *) ".dclock.forest", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-hiv", (char *) ".dclock.hiv", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+hiv", (char *) ".dclock.hiv", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-lab", (char *) ".dclock.lab", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+lab", (char *) ".dclock.lab", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-veg", (char *) ".dclock.veg", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+veg", (char *) ".dclock.veg", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-time24", (char *) ".dclock.time24", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+time24", (char *) ".dclock.time24", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-y2k", (char *) ".dclock.y2k", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+y2k", (char *) ".dclock.y2k", XrmoptionNoArg, (caddr_t) "off"}, {(char *) "-millennium", (char *) ".dclock.millennium", XrmoptionNoArg, (caddr_t) "on"}, {(char *) "+millennium", (char *) ".dclock.millennium", XrmoptionNoArg, (caddr_t) "off"} }; static argtype vars[] = { {(void *) & binary, (char *) "binary", (char *) "Binary", (char *) DEF_BINARY, t_Bool}, {(void *) & led, (char *) "led", (char *) "LED", (char *) DEF_LED, t_Bool}, {(void *) & popex, (char *) "popex", (char *) "PopEx", (char *) DEF_POPEX, t_Bool}, {(void *) & forest, (char *) "forest", (char *) "Forest", (char *) DEF_FOREST, t_Bool}, {(void *) & hiv, (char *) "hiv", (char *) "Hiv", (char *) DEF_HIV, t_Bool}, {(void *) & lab, (char *) "lab", (char *) "Lab", (char *) DEF_LAB, t_Bool}, {(void *) & veg, (char *) "veg", (char *) "Veg", (char *) DEF_VEG, t_Bool}, {(void *) & time24, (char *) "time24", (char *) "Time24", (char *) DEF_TIME24, t_Bool}, {(void *) & y2k, (char *) "y2k", (char *) "Y2K", (char *) DEF_Y2K, t_Bool}, {(void *) & millennium, (char *) "millennium", (char *) "Millennium", (char *) DEF_Y2001, t_Bool} }; static OptionStruct desc[] = { {(char *) "-/+binary", (char *) "turn on/off binary clock display"}, {(char *) "-/+led", (char *) "turn on/off Light Emitting Diode seven segment display"}, {(char *) "-/+popex", (char *) "turn on/off population explosion counter"}, {(char *) "-/+forest", (char *) "turn on/off tropical forest destruction counter"}, {(char *) "-/+hiv", (char *) "turn on/off HIV infection counter"}, {(char *) "-/+lab", (char *) "turn on/off Animal Research counter"}, {(char *) "-/+veg", (char *) "turn on/off Animal Consumation counter"}, {(char *) "-/+time24", (char *) "turn on/off 24 hour display"}, {(char *) "-/+y2k", (char *) "turn on/off Year 2000 countdown"}, {(char *) "-/+millennium", (char *) "turn on/off 3rd Millennium (1 January 2001) countdown"}, }; ModeSpecOpt dclock_opts = {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; #ifdef USE_MODULES ModStruct dclock_description = {"dclock", "init_dclock", "draw_dclock", "release_dclock", "refresh_dclock", "init_dclock", (char *) NULL, &dclock_opts, 10000, 1, 10000, 1, 64, 0.3, "", "Shows a floating digital clock or message", 0, NULL}; #endif #ifdef HAVE_SYS_PARAM_H #include #endif #include /* language depended resources */ #if defined FR #include "dclock-msg-fr.h" #elif defined NL #include "dclock-msg-nl.h" #elif defined JA #include "dclock-msg-ja.h" #else #include "dclock-msg-en.h" #endif #ifdef USE_MB static XFontSet mode_font = None; static int font_height(XFontSet f) { XRectangle ink, log; if (f == None) { return 8; } else { XmbTextExtents(mode_font, "My", strlen("My"), &ink, &log); return log.height; } } #define DELTA 0.2 extern XFontSet getFontSet(Display * display); #else static XFontStruct *mode_font = None; #define font_height(f) (f->ascent + f->descent) #define DELTA 0 extern XFontStruct *getFont(Display * display); #endif #ifdef USE_MB #define free_font(d) if (mode_font!=None){XFreeFontSet(d,mode_font); \ mode_font = None;} #else #define free_font(d) if (mode_font!=None){XFreeFont(d,mode_font); \ mode_font = None;} #endif #define STRSIZE 50 typedef struct { int color; short height, width; char *str, str1[STRSIZE], str2[STRSIZE], str1old[STRSIZE], str2old[STRSIZE]; char *str1pta, *str2pta, *str1ptb, *str2ptb; time_t timenew, timeold; int tzoffset; short maxx, maxy, clockx, clocky; short text_height, text_width, text_width1, text_width2; short text_start1, text_start2; short text_ascent, text_descent; short hour; short dx, dy; int done; int pixw, pixh; Pixmap pixmap; GC fgGC, bgGC; Bool popex, forest, hiv, lab, veg, time24, y2k, millennium, led, binary; XPoint parallelogram[4]; } dclockstruct; static dclockstruct *dclocks = (dclockstruct *) NULL; static unsigned long timeAtLastNewYear(long timeNow) { struct tm *t; t = localtime((const time_t *) &timeNow); return (unsigned long)(t->tm_year); } #ifndef HAVE_SNPRINTF static double logbase; #define BASE 10.0 #define GROUP 3 #endif static void convert(double x, char *string) { #ifdef HAVE_SNPRINTF /* Also old C compiler can not accept this syntax, but this syntax awares locale. Known to work with gcc-2.95.2 and glibc-2.1.3. */ (void) snprintf(string, STRSIZE, "%'.0f", x); #else int i, j, k = 0; int place = (int) (log(x) / logbase); double divisor = 1.0; for (i = 0; i < place; i++) divisor *= BASE; for (i = place; i >= 0; i--) { j = (int) (x / divisor); string[k++] = (char) j + '0'; x -= j * divisor; divisor /= BASE; if ((i > 0) && (i % GROUP == 0)) { string[k++] = ','; } } string[k] = '\0'; #endif } static void dayhrminsec(long timeCount, int tzoffset, char *string) { int days, hours, minutes, secs; int bufsize, i; timeCount = ABS(timeCount); days = (int) (timeCount / 86400); hours = (int) ((timeCount / 3600) % 24); minutes = (int) ((timeCount / 60) % 60); secs = (int) (timeCount % 60); /* snprintf would make this easier but its not always available */ bufsize = 16 + strlen((days==1) ? DAY : DAYS); if (bufsize >= STRSIZE) return; (void) sprintf(string, "%d %s", days, (days==1) ? DAY : DAYS); i = strlen(string); bufsize = 4 + strlen((hours==1) ? HOUR : HOURS); if (i + bufsize >= STRSIZE) return; (void) sprintf(&string[i], " %d %s", hours, (hours==1) ? HOUR : HOURS); i = strlen(string); bufsize = 4 + strlen((minutes==1) ? MINUTE : MINUTES); if (i + bufsize >= STRSIZE) return; (void) sprintf(&string[i], " %d %s", minutes, (minutes==1) ? MINUTE : MINUTES); i = strlen(string); bufsize += 4 + strlen((secs==1) ? SECOND : SECONDS); if (i + bufsize >= STRSIZE) return; (void) sprintf(&string[i], " %d %s", secs, (secs==1) ? SECOND : SECONDS); if (!tzoffset) { i = strlen(string); bufsize += 6; /* strlen(" (UTC)"); */ if (i + bufsize >= STRSIZE) return; (void) strcat(string, " (UTC)"); } } static void drawaled(ModeInfo * mi, int startx, int starty, int aled) { Display *display = MI_DISPLAY(mi); dclockstruct *dp = &dclocks[MI_SCREEN(mi)]; int x_1, y_1, x_2, y_2; int offset = (int) LED_WIDTH; int offset2 = (int) (LED_WIDTH / 2.0); int leanoffset = (int) (offset2 * LED_LEAN); switch (aled) { case 0: /* a */ x_1 = startx + dp->parallelogram[0].x; y_1 = starty + dp->parallelogram[0].y; x_2 = x_1 + dp->parallelogram[1].x - offset; y_2 = y_1 + dp->parallelogram[1].y; x_1 = x_1 + offset; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 1: /* b */ x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[1].x; y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[1].y; x_2 = x_1 + dp->parallelogram[2].x / 2 + leanoffset; y_2 = y_1 + dp->parallelogram[2].y / 2 - offset2; x_1 = x_1 - leanoffset; y_1 = y_1 + offset2; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 2: /* c */ x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[1].x + dp->parallelogram[2].x; y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[1].y + dp->parallelogram[2].y; x_2 = x_1 - dp->parallelogram[2].x / 2 - leanoffset; y_2 = y_1 - dp->parallelogram[2].y / 2 + offset2; x_1 = x_1 + leanoffset; y_1 = y_1 - offset2; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 3: /* d */ x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[2].x; y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y; x_2 = x_1 + dp->parallelogram[1].x - offset; y_2 = y_1 + dp->parallelogram[1].y; x_1 = x_1 + offset; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 4: /* e */ x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[2].x; y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y; x_2 = x_1 - dp->parallelogram[2].x / 2 - leanoffset; y_2 = y_1 - dp->parallelogram[2].y / 2 + offset2; x_1 = x_1 + leanoffset; y_1 = y_1 - offset2; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 5: /* f */ x_1 = startx + dp->parallelogram[0].x; y_1 = starty + dp->parallelogram[0].y; x_2 = x_1 + dp->parallelogram[2].x / 2 + leanoffset; y_2 = y_1 + dp->parallelogram[2].y / 2 - offset2; x_1 = x_1 - leanoffset; y_1 = y_1 + offset2; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); break; case 6: /* g */ x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[2].x / 2; y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y / 2; x_2 = x_1 + dp->parallelogram[1].x - offset; y_2 = y_1 + dp->parallelogram[1].y; x_1 = x_1 + offset; XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); } } static void drawacolon(ModeInfo * mi, int startx, int starty) { Display *display = MI_DISPLAY(mi); dclockstruct *dp = &dclocks[MI_SCREEN(mi)]; int x_1, y_1, x_2, y_2; int offset2 = (int) (LED_WIDTH / 2.0); int leanoffset = (int) (offset2 * LED_LEAN); x_1 = startx + dp->parallelogram[0].x + (int) (dp->parallelogram[2].x / 2 - 2.0 * leanoffset); y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y / 2 + (int) (2.0 * offset2); x_2 = x_1 - (int) (2.0 * leanoffset); y_2 = y_1 + (int) (2.0 * offset2); XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); x_1 = startx + dp->parallelogram[0].x + dp->parallelogram[2].x / 2 + (int) (2.0 * leanoffset); y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y / 2 - (int) (2.0 * offset2); x_2 = x_1 + (int) (2.0 * leanoffset); y_2 = y_1 - (int) (2.0 * offset2); XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2); } static void drawanumber(ModeInfo * mi, int startx, int starty, int digit) { int aled; for (aled = 0; aled < MAX_LEDS; aled++) { if (digits[digit][aled]) drawaled(mi, startx, starty, aled); } } static void drawadot(ModeInfo * mi, int startx, int starty, int filled) { Display *display = MI_DISPLAY(mi); dclockstruct *dp = &dclocks[MI_SCREEN(mi)]; if (filled) XFillArc(display, dp->pixmap, dp->fgGC, startx, starty, BINARY_WIDTH, BINARY_HEIGHT, 0, 23040); else XDrawArc(display, dp->pixmap, dp->fgGC, startx, starty, BINARY_WIDTH, BINARY_HEIGHT, 0, 23040); } static void drawabinary(ModeInfo * mi, int startx, int starty, int dotcount, int digit) { int newy; int filled; int i; for (i=0; i < dotcount; i++) { newy = starty + ((BINARY_HEIGHT + BINARY_INC) * (3 - i)); filled = (digit >> i) & 0x01; drawadot(mi, startx, newy, filled); } } static void free_dclock(Display *display, dclockstruct *dp) { if (dp->fgGC != None) { XFreeGC(display, dp->fgGC); dp->fgGC = None; } if (dp->bgGC) { XFreeGC(display, dp->bgGC); dp->bgGC = None; } if (dp->pixmap) { XFreePixmap(display, dp->pixmap); dp->pixmap = None; } } static void drawDclock(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); dclockstruct *dp = &dclocks[MI_SCREEN(mi)]; short xold, yold; if (dp->led || dp->binary) { dp->timeold = dp->timenew = time((time_t *) NULL); dp->str = ctime(&dp->timeold); } else if (!dp->popex && !dp->forest && !dp->hiv && !dp->lab && !dp->veg && !dp->y2k && !dp->millennium) { if (dp->timeold != (dp->timenew = time((time_t *) NULL))) { /* only parse if time has changed */ dp->timeold = dp->timenew; if (!dp->popex && !dp->forest && !dp->hiv && !dp->lab && !dp->veg && !dp->y2k && !dp->millennium) { if (dp->time24) (void) strftime(dp->str1pta, STRSIZE, "%H:%M:%S", localtime(&(dp->timeold))); else (void) strftime(dp->str1pta, STRSIZE, "%I:%M:%S %p", localtime(&(dp->timeold))); } (void) strftime(dp->str2pta, STRSIZE, "%a %b %d %Y", localtime(&(dp->timeold))); } } else { long timeNow, timeLocal; timeNow = seconds(); timeLocal = timeNow - dp->tzoffset; if (dp->popex) { convert(PEOPLE_TIME_START + (PEOPLE_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, PEOPLE_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->forest) { convert(AREA_TIME_START - (AREA_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, TROPICAL_STRING, STRSIZE-strlen(dp->str2)); (void) strncat(dp->str2, AREA_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->hiv) { convert(HIV_TIME_START + (HIV_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, CASES_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->lab) { convert((LAB_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)), dp->str2); (void) strncat(dp->str2, YEAR_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->veg) { convert((VEG_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)), dp->str2); (void) strncat(dp->str2, YEAR_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->y2k) { if (Y2K_TIME_START >= timeLocal) dp->str1pta = (char *) Y2K_STRING; else dp->str1pta = (char *) POST_Y2K_STRING; dp->str1ptb = dp->str1pta; dayhrminsec(Y2K_TIME_START - timeLocal, dp->tzoffset, dp->str2); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->millennium) { if (Y2001_TIME_START >= timeLocal) dp->str1pta = (char *) Y2001_STRING; else dp->str1pta = (char *) POST_Y2001_STRING; dp->str1ptb = dp->str1pta; dayhrminsec(Y2001_TIME_START - timeLocal, dp->tzoffset, dp->str2); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } } /* Recalculate string width since it can change */ xold = dp->clockx; yold = dp->clocky; if (!dp->led && !dp->binary) { #ifdef USE_MB { XRectangle ink, logical; XmbTextExtents(mode_font, dp->str1pta, strlen(dp->str1pta), &ink, &logical); dp->text_width1 = logical.width; XmbTextExtents(mode_font, dp->str2pta, strlen(dp->str2pta), &ink, &logical); dp->text_width2 = logical.width; } #else dp->text_width1 = XTextWidth(mode_font, dp->str1pta, strlen(dp->str1pta)); dp->text_width2 = XTextWidth(mode_font, dp->str2pta, strlen(dp->str2pta)); #endif if (dp->text_width1 > dp->text_width2) { dp->text_width = dp->text_width1; dp->text_start1 = 0; dp->text_start2 = (dp->text_width - dp->text_width2) / 2; } else { dp->text_width = dp->text_width2; dp->text_start1 = (dp->text_width - dp->text_width1) / 2; dp->text_start2 = 0; } } dp->width = MI_WIDTH(mi); dp->height = MI_HEIGHT(mi); dp->maxx = dp->width - dp->text_width; dp->maxy = dp->height - dp->text_height - dp->text_descent; dp->clockx += dp->dx; dp->clocky += dp->dy; if (dp->maxx < dp->text_start1) { if (dp->clockx < dp->maxx + dp->text_start1 || dp->clockx > dp->text_start1) { dp->dx = -dp->dx; dp->clockx += dp->dx; } } else if (dp->maxx > dp->text_start1) { if (dp->clockx >= dp->maxx + dp->text_start1 || dp->clockx <= dp->text_start1) { dp->dx = -dp->dx; dp->clockx += dp->dx; } } if (dp->maxy < dp->text_ascent) { if (dp->clocky > dp->text_ascent || dp->clocky < dp->maxy) { dp->dy = -dp->dy; dp->clocky += dp->dy; } } else if (dp->maxy > dp->text_ascent) { if (dp->clocky > dp->maxy || dp->clocky < dp->text_ascent) { dp->dy = -dp->dy; dp->clocky += dp->dy; } } if (dp->pixw != dp->text_width || dp->pixh != (1 + !dp->led) * dp->text_height) { XGCValues gcv; if (dp->pixmap) MI_CLEARWINDOWCOLORMAPFAST(mi, gc, MI_BLACK_PIXEL(mi)); free_dclock(display, dp); dp->pixw = dp->text_width; if (dp->led) dp->pixh = dp->text_height; else dp->pixh = (2 + DELTA) * dp->text_height; if ((dp->pixmap = XCreatePixmap(display, window, dp->pixw, dp->pixh, 1)) == None) { free_dclock(display, dp); dp->pixw = 0; dp->pixh = 0; return; } #ifndef USE_MB gcv.font = mode_font->fid; #endif gcv.background = 0; gcv.foreground = 1; gcv.graphics_exposures = False; if ((dp->fgGC = XCreateGC(display, dp->pixmap, GCForeground | GCBackground | GCGraphicsExposures #ifndef USE_MB | GCFont #endif , &gcv)) == None) { free_dclock(display, dp); dp->pixw = 0; dp->pixh = 0; return; } gcv.foreground = 0; if ((dp->bgGC = XCreateGC(display, dp->pixmap, GCForeground | GCBackground | GCGraphicsExposures #ifndef USE_MB | GCFont #endif , &gcv)) == None) { free_dclock(display, dp); dp->pixw = 0; dp->pixh = 0; return; } if (!dp->binary) XSetLineAttributes(display, dp->fgGC, (unsigned int) (LED_WIDTH), LineSolid, CapButt, JoinMiter); } XFillRectangle(display, dp->pixmap, dp->bgGC, 0, 0, dp->pixw, dp->pixh); if (dp->led) { int startx = (int) (LED_WIDTH / 2.0); int starty = (int) (LED_WIDTH / 2.0); drawanumber(mi, startx, starty, dp->str[11] - '0'); startx += (int) (LED_XS + LED_WIDTH + LED_INC); drawanumber(mi, startx, starty, dp->str[12] - '0'); startx += (int) (LED_XS + LED_WIDTH + LED_INC); drawacolon(mi, startx, starty); startx += (int) (LED_WIDTH + LED_INC); drawanumber(mi, startx, starty, dp->str[14] - '0'); startx += (int) (LED_XS + LED_WIDTH + LED_INC); drawanumber(mi, startx, starty, dp->str[15] - '0'); startx += (int) (LED_XS + LED_WIDTH + LED_INC); drawacolon(mi, startx, starty); startx += (int) (LED_WIDTH + LED_INC); drawanumber(mi, startx, starty, dp->str[17] - '0'); startx += (int) (LED_XS + LED_WIDTH + LED_INC); drawanumber(mi, startx, starty, dp->str[18] - '0'); } else if (dp->binary) { int startx = BINARY_WIDTH / 2; int starty = BINARY_HEIGHT / 2; /* hour - top number, 0, 1 or 2 */ drawabinary(mi, startx, starty, 2, dp->str[11] - '0'); startx += (BINARY_WIDTH + BINARY_INC); /* hour - bottom number 0 - 9 */ drawabinary(mi, startx, starty, 4, dp->str[12] - '0'); startx += (BINARY_WIDTH + BINARY_INC); /* minute - top number, 0 - 5 */ drawabinary(mi, startx, starty, 3, dp->str[14] - '0'); startx += (BINARY_WIDTH + BINARY_INC); /* minute - bottom number, 0 - 9 */ drawabinary(mi, startx, starty, 4, dp->str[15] - '0'); startx += (BINARY_WIDTH + BINARY_INC); /* second - top number, 0 - 5 */ drawabinary(mi, startx, starty, 3, dp->str[17] - '0'); startx += (BINARY_WIDTH + BINARY_INC); /* second - bottom number, 0 - 9 */ drawabinary(mi, startx, starty, 4, dp->str[18] - '0'); startx += (BINARY_WIDTH + BINARY_INC); } else { #ifdef USE_MB (void) XmbDrawString(display, dp->pixmap, mode_font, dp->fgGC, dp->text_start1, dp->text_ascent, dp->str1pta, strlen(dp->str1pta)); (void) XmbDrawString(display, dp->pixmap, mode_font, dp->fgGC, dp->text_start2, dp->text_ascent + dp->text_height, dp->str2pta, strlen(dp->str2pta)); #else (void) XDrawString(display, dp->pixmap, dp->fgGC, dp->text_start1, dp->text_ascent, dp->str1pta, strlen(dp->str1pta)); (void) XDrawString(display, dp->pixmap, dp->fgGC, dp->text_start2, dp->text_ascent + dp->text_height, dp->str2pta, strlen(dp->str2pta)); #endif } XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); /* This could leave screen dust on the screen if the width changes But that only happens once a day... ... this is solved by the ClearWindow above */ ERASE_IMAGE(display, window, gc, (dp->clockx - dp->text_start1), (dp->clocky - dp->text_ascent), (xold - dp->text_start1), (yold - dp->text_ascent), dp->pixw, dp->pixh); if (MI_NPIXELS(mi) > 2) XSetForeground(display, gc, MI_PIXEL(mi, dp->color)); else XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); XCopyPlane(display, dp->pixmap, window, gc, 0, 0, dp->text_width, (2 + DELTA) * dp->text_height, dp->clockx - dp->text_start1, dp->clocky - dp->text_ascent, 1L); } void release_dclock(ModeInfo * mi) { if (dclocks != NULL) { int screen; for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) free_dclock(MI_DISPLAY(mi), &dclocks[screen]); free(dclocks); dclocks = (dclockstruct *) NULL; } free_font(MI_DISPLAY(mi)); } #if defined(HAVE_TZSET) && !(defined(BSD) && BSD >= 199306) && !(defined(__CYGWIN__)) extern long timezone; #endif void init_dclock(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); dclockstruct *dp; long timeNow, timeLocal; if (dclocks == NULL) { #ifndef HAVE_SNPRINTF logbase = log(BASE); #endif if ((dclocks = (dclockstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (dclockstruct))) == NULL) return; } dp = &dclocks[MI_SCREEN(mi)]; dp->width = MI_WIDTH(mi); dp->height = MI_HEIGHT(mi); MI_CLEARWINDOW(mi); dp->binary = False; dp->led = False; dp->popex = False; dp->forest = False; dp->hiv = False; dp->lab = False; dp->veg = False; dp->time24 = False; dp->y2k = False; dp->millennium = False; #if defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) #define NUM_DCLOCK_MODES 11 #endif #if defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) #define NUM_DCLOCK_MODES 10 #endif #if !defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) #define NUM_DCLOCK_MODES 10 #endif #if !defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) #define NUM_DCLOCK_MODES 9 #endif if (MI_IS_FULLRANDOM(mi)) { switch (NRAND(NUM_DCLOCK_MODES)) { case 0: break; case 1: dp->led = True; break; case 2: dp->popex = True; break; case 3: dp->forest = True; break; case 4: dp->hiv = True; break; case 5: dp->lab = True; break; case 6: dp->veg = True; break; case 7: dp->time24 = True; break; case 8: dp->binary = True; break; #if defined(MODE_dclock_y2k) || defined(MODE_dclock_millennium) case 9: #ifdef MODE_dclock_y2k dp->y2k = True; #else dp->millennium = True; #endif break; #if defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) case 10: dp->millennium = True; break; #endif #endif default: break; } } else { /* first come, first served */ dp->binary = binary; dp->led = led; dp->popex = popex; dp->forest = forest; dp->hiv = hiv; dp->lab = lab; dp->veg = veg; dp->time24 = time24; dp->y2k = y2k; dp->millennium = millennium; } if (mode_font == None) { #ifdef USE_MB mode_font = getFontSet(display); #else mode_font = getFont(display); #endif if (mode_font == None) { release_dclock(mi); return; } } if (!dp->done) { dp->done = 1; #ifndef USE_MB if (mode_font != None) XSetFont(display, MI_GC(mi), mode_font->fid); #endif } /* (void)time(&dp->timenew); */ #if defined(HAVE_TZSET) && (!defined(HAVE_TIMELOCAL) || (defined(BSD) && BSD >= 199306)) (void) tzset(); #endif dp->timeold = dp->timenew = time((time_t *) NULL); #if defined(HAVE_TIMELOCAL) && !(defined(BSD) && BSD >= 199306) dp->tzoffset = mktime(localtime(&dp->timeold)) - mktime(gmtime(&dp->timeold)); #else #if defined(HAVE_TZSET) dp->tzoffset = (int)timezone; #else dp->tzoffset = 0; #endif #endif if (dp->tzoffset > 86400 || dp->tzoffset < -86400) dp->tzoffset = 0; dp->str = ctime(&dp->timeold); dp->dx = (LRAND() & 1) ? 1 : -1; dp->dy = (LRAND() & 1) ? 1 : -1; timeNow = seconds(); timeLocal = timeNow - dp->tzoffset; if (dp->led) { int i; dp->text_descent = 0; dp->text_ascent = 0; for (i = 0; i < 4; i++) { if (parallelogramUnit[i].x == 1) dp->parallelogram[i].x = (short) (LED_XS * LED_LEAN); else if (parallelogramUnit[i].x == 2) dp->parallelogram[i].x = (short) LED_XS; else if (parallelogramUnit[i].x == -1) dp->parallelogram[i].x = (short) (-LED_XS * LED_LEAN); else if (parallelogramUnit[i].x == -2) dp->parallelogram[i].x = (short) (-LED_XS); else dp->parallelogram[i].x = 0; dp->parallelogram[i].y = (short) (LED_YS * parallelogramUnit[i].y); } dp->parallelogram[0].x = (short) ((LED_XS * LED_LEAN) + LED_INC); dp->parallelogram[0].y = (short) LED_INC; dp->text_width = (short) (6 * (LED_XS + LED_WIDTH + LED_INC) + 2 * (LED_WIDTH + LED_INC) + LED_XS * LED_LEAN - LED_INC); dp->text_height = (short) (LED_YS + LED_WIDTH + LED_INC); dp->maxy = dp->height - dp->text_height; if (dp->maxy == 0) dp->clocky = 0; else if (dp->maxy < 0) dp->clocky = -NRAND(-dp->maxy); else dp->clocky = NRAND(dp->maxy); } else if (dp->binary) { dp->text_width = (6 * (BINARY_WIDTH + BINARY_INC)) + BINARY_WIDTH; dp->text_height = (4 * (BINARY_HEIGHT + BINARY_INC)) + BINARY_HEIGHT; dp->maxy = dp->height - dp->text_height; if (dp->maxy == 0) dp->clocky = 0; else if (dp->maxy < 0) dp->clocky = -NRAND(-dp->maxy); else dp->clocky = NRAND(dp->maxy); } else { #ifdef USE_MB dp->text_descent = 0; dp->text_ascent = font_height(mode_font); #else dp->text_descent = mode_font->descent; dp->text_ascent = mode_font->ascent; #endif if (dp->popex) { dp->str1pta = (char *) POPEX_STRING; dp->str1ptb = dp->str1pta; } else if (dp->forest) { dp->str1pta = (char *) FOREST_STRING; dp->str1ptb = dp->str1pta; } else if (dp->hiv) { dp->str1pta = (char *) HIV_STRING; dp->str1ptb = dp->str1pta; } else if (dp->lab) { dp->str1pta = (char *) LAB_STRING; dp->str1ptb = dp->str1pta; } else if (dp->veg) { dp->str1pta = (char *) VEG_STRING; dp->str1ptb = dp->str1pta; } else if (dp->y2k) { if (Y2K_TIME_START >= timeLocal) dp->str1pta = (char *) Y2K_STRING; else dp->str1pta = (char *) POST_Y2K_STRING; dp->str1ptb = dp->str1pta; } else if (dp->millennium) { if (Y2001_TIME_START >= timeLocal) dp->str1pta = (char *) Y2001_STRING; else dp->str1pta = (char *) POST_Y2001_STRING; dp->str1ptb = dp->str1pta; } else { struct tm *t = localtime((const time_t *) &timeLocal); if (dp->time24) (void) strftime(dp->str1, STRSIZE, "%H:%M:%S", t); else (void) strftime(dp->str1, STRSIZE, "%I:%M:%S %p", t); dp->hour = t->tm_hour; (void) strftime(dp->str2, STRSIZE, "%a %b %d %Y", t); dp->str1pta = dp->str1; dp->str1ptb = dp->str1old; } if (dp->popex) { convert(PEOPLE_TIME_START + (PEOPLE_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, PEOPLE_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->forest) { convert(AREA_TIME_START - (AREA_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, TROPICAL_STRING, STRSIZE-strlen(dp->str2)); (void) strncat(dp->str2, AREA_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->hiv) { convert(HIV_TIME_START + (HIV_MIN / 60.0) * timeNow, dp->str2); (void) strncat(dp->str2, CASES_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->lab) { convert((LAB_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)), dp->str2); (void) strncat(dp->str2, YEAR_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; dp->str2ptb = dp->str2pta; } else if (dp->veg) { convert((VEG_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)), dp->str2); (void) strncat(dp->str2, YEAR_STRING, STRSIZE-strlen(dp->str2)); dp->str2pta = dp->str2; } else if (dp->y2k) { dayhrminsec(Y2K_TIME_START - timeLocal, dp->tzoffset, dp->str2); dp->str2pta = dp->str2; } else if (dp->millennium) { dayhrminsec(Y2001_TIME_START - timeLocal, dp->tzoffset, dp->str2); dp->str2pta = dp->str2; } else { dp->str2pta = dp->str2; dp->str2ptb = dp->str2old; } dp->text_height = font_height(mode_font); #ifdef USE_MB { XRectangle ink, logical; XmbTextExtents(mode_font, dp->str1pta, strlen(dp->str1pta), &ink, &logical); dp->text_width1 = logical.width; XmbTextExtents(mode_font, dp->str2pta, strlen(dp->str2pta), &ink, &logical); dp->text_width2 = logical.width; } #else dp->text_width1 = XTextWidth(mode_font, dp->str1pta, strlen(dp->str1pta)); dp->text_width2 = XTextWidth(mode_font, dp->str2pta, strlen(dp->str2pta)); #endif if (dp->text_width1 > dp->text_width2) { dp->text_width = dp->text_width1; dp->text_start1 = 0; dp->text_start2 = (dp->text_width - dp->text_width2) / 2; } else { dp->text_width = dp->text_width2; dp->text_start1 = (dp->text_width - dp->text_width1) / 2; dp->text_start2 = 0; } dp->maxy = dp->height - dp->text_height - dp->text_descent; if (dp->maxy - dp->text_ascent == 0) dp->clocky = dp->text_ascent; else if (dp->maxy - dp->text_ascent < 0) dp->clocky = -NRAND(dp->text_ascent - dp->maxy) + dp->text_ascent; else dp->clocky = NRAND(dp->maxy - dp->text_ascent) + dp->text_ascent; } dp->maxx = dp->width - dp->text_width; if (dp->maxx == 0) dp->clockx = dp->text_start1; else if (dp->maxx < 0) dp->clockx = -NRAND(-dp->maxx) + dp->text_start1; else dp->clockx = NRAND(dp->maxx) + dp->text_start1; if (MI_NPIXELS(mi) > 2) dp->color = NRAND(MI_NPIXELS(mi)); /* don't want any exposure events from XCopyPlane */ XSetGraphicsExposures(display, MI_GC(mi), False); } void draw_dclock(ModeInfo * mi) { dclockstruct *dp; if (dclocks == NULL) return; dp = &dclocks[MI_SCREEN(mi)]; if (mode_font == None) return; MI_IS_DRAWN(mi) = True; drawDclock(mi); if (MI_NPIXELS(mi) > 2) { if (++dp->color >= MI_NPIXELS(mi)) dp->color = 0; } } void refresh_dclock(ModeInfo * mi) { MI_CLEARWINDOW(mi); } #endif /* MODE_dclock */