1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* dclock --- floating digital clock or message */
3 
4 #if 0
5 static const char sccsid[] = "@(#)dclock.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (C) 1995 by Michael Stembera <mrbig@fc.net>.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 03-Dec-2005: Added a binary clock display, after seeing the binary clock
26  *              at thinkgeek. Petey (petey_leinonen AT yahoo.com.au)
27  * 01-Mar-2005: Added 24 hour clock (alex(at)shark-linux(dot)de)
28  * 01-Nov-2000: Allocation checks
29  * 07-May-1999: New "savers" added for y2k and second millennium countdowns.
30  *              Tom Schmidt <tschmidt AT micron.com>
31  * 04-Dec-1998: New "savers" added for hiv, veg, and lab.
32  *              hiv one due to Kenneth Stailey <kstailey@disclosure.com>
33  * 10-Aug-1998: Population Explosion and Tropical Forest Countdown stuff
34  *              I tried to get precise numbers but they may be off a few
35  *              percent.  Whether or not, its still pretty scary IMHO.
36  *              Although I am a US citizen... I have the default for area in
37  *              metric.  David Bagley <bagleyd AT verizon.net>
38  * 10-May-1997: Compatible with xscreensaver
39  * 29-Aug-1995: Written.
40  */
41 
42 /*-
43  *  Some of my calculations laid bare...  (I have a little problem with
44  *  the consistency of the numbers I got at the Bronx Zoo but proportions
45  *  were figured to be 160.70344 people a minute increase not 180 and
46  *  35.303144 hectares (87.198766 acres) a minute decrease not 247 (100 acres).
47  *  So I am going with these more conservative numbers.)
48  *
49  *  Time 0 is 0:00:00 1 Jan 1970 at least according to hard core UNIX fans
50  *  Minutes from 1  Jan 1970 to 21 Jun 1985:  8137440
51  *  Minutes from 21 Jun 1985 to 12 Jul 1998:  6867360
52  *                                    Total: 15004800
53  *
54  *  Population Explosion Saver (popex)
55  *  3,535,369,000 people (figured by extrapolation) 1 Jan 1970
56  *  4,843,083,596 people 21 Jun 1985 (Opening of Wild Asia in the Bronx Zoo)
57  *  5,946,692,000 people 12 Jul 1998 (David Bagley visits zoo ;) )
58  *  180 people a minute increase in global population (I heard 170 also)
59  *  260,000 people a day increase in global population
60  *
61  *  Tropical Forest Countdown Saver (forest)
62  *  1,184,193,000 hectares (figured by extrapolation) 1 Jan 1970
63  *    (2,924,959,000 acres)
64  *  896,916,700 hectares 21 Jun 1985 (Opening of Wild Asia in the Bronx Zoo)
65  *    (2,215,384,320 acres)
66  *  654,477,300 hectares 12 Jul 1998 (David Bagley visits zoo ;) )
67  *    (1,616,559,000 acres)
68  *  247 hectares a minute lost forever (1 hectare = 2.47 acres)
69  *
70  *  HIV Infection Counter Saver (hiv) (stats from http://www.unaids.org/)
71  *  33,600,000 31 Dec 1999 living w/HIV
72  *  16,300,000 31 Dec 1999 dead
73  *  49,900,000 31 Dec 1999 total infections
74  *   5,600,000 new infections in 1999
75  *  10.6545 infections/min
76  *  -118,195,407 virtual cases (figured by extrapolation) 1 Jan 1970
77  *   (this is a result of applying linear tracking to a non-linear event)
78  *
79  *  Animal Research Counter Saver (lab)
80  *  Approximately 17-22 million animals are used in research each year.
81  *  OK so assume 17,000,000 / 525960 = 32.32184957 per minute
82  *  http://www.fcs.uga.edu/~mhulsey/GDB.html
83  *
84  *  Animal Consumation Counter Saver (veg)
85  *  Approximately 5 billion are consumed for food annually.
86  *  OK 5,000,000,000 / 525960 = 9506.426344209 per minute
87  *  http://www.fcs.uga.edu/~mhulsey/GDB.html
88  */
89 
90 #ifdef STANDALONE
91 #define MODE_dclock
92 #define DEFAULTS "*delay: 10000 \n" \
93 	"*cycles: 10000 \n" \
94 	"*ncolors: 64 \n" \
95 
96 # define free_dclock 0
97 # define reshape_dclock 0
98 # define dclock_handle_event 0
99 #define BRIGHT_COLORS
100 #define UNIFORM_COLORS
101 #include "xlockmore.h"		/* in xscreensaver distribution */
102 #else /* STANDALONE */
103 #include "xlock.h"		/* in xlockmore distribution */
104 #include "iostuff.h"
105 #include "util.h"
106 #endif /* STANDALONE */
107 
108 #ifdef MODE_dclock
109 
110 #ifndef METRIC
111 #define METRIC 1
112 #endif
113 
114 #ifdef METRIC
115 #define AREA_MIN 35.303144
116 #define AREA_TIME_START 1184193000.0
117 #else
118 #define AREA_MIN 87.198766
119 #define AREA_TIME_START 2924959000.0
120 #endif
121 
122 #define PEOPLE_MIN 160.70344
123 #define PEOPLE_TIME_START 3535369000.0
124 #define HIV_MIN 10.6545
125 #define HIV_TIME_START -118195407.0
126 #define LAB_MIN 32.32184957
127 #define LAB_TIME_START 0
128 #define VEG_MIN 9506.426344209
129 #define VEG_TIME_START 0
130 /* epoch time at midnight 1 January 2000 UTC */
131 #define Y2K_TIME_START (((30 * 365) + 7) * 24 * 60 * 60)
132 #define Y2001_TIME_START (Y2K_TIME_START + 366 * 24 * 60 * 60)
133 #define MAYAN_TIME_START (((42 * 365) + 10) * 24 * 60 * 60  + (366 - 11) * 24 * 60 * 60)
134 
135 #define LED_LEAN 0.2
136 #define LED_XS 30.0
137 #define LED_YS 45.0
138 #define LED_WIDTH (0.15 * LED_YS)
139 #define LED_INC (LED_LEAN * LED_XS) /* LEAN and INC do not have to be linked */
140 
141 #define BINARY_WIDTH 10
142 #define BINARY_HEIGHT 10
143 #define BINARY_INC 5
144 
145 #define DEF_BINARY "False"
146 #define DEF_LED    "False"
147 #define DEF_POPEX  "False"
148 #define DEF_FOREST "False"
149 #define DEF_HIV    "False"
150 #define DEF_LAB    "False"
151 #define DEF_VEG    "False"
152 #define DEF_TIME24 "False"
153 #define DEF_Y2K    "False"
154 #define DEF_Y2001  "False"
155 #define DEF_MAYAN  "False"
156 
157 /*- If you remember your Electronics course...
158         a
159         _
160     f / / b
161       - g
162   e /_/ c
163      d
164  */
165 
166 #define MAX_LEDS 7
167 static unsigned char digits[][MAX_LEDS]=
168 {
169 /* a  b  c  d  e  f  g */
170   {1, 1, 1, 1, 1, 1, 0},  /* 0 */
171   {0, 1, 1, 0, 0, 0, 0},  /* 1 */
172   {1, 1, 0, 1, 1, 0, 1},  /* 2 */
173   {1, 1, 1, 1, 0, 0, 1},  /* 3 */
174   {0, 1, 1, 0, 0, 1, 1},  /* 4 */
175   {1, 0, 1, 1, 0, 1, 1},  /* 5 */
176   {1, 0, 1, 1, 1, 1, 1},  /* 6 */
177   {1, 1, 1, 0, 0, 0, 0},  /* 7 */
178   {1, 1, 1, 1, 1, 1, 1},  /* 8 */
179   {1, 1, 1, 1, 0, 1, 1}  /* 9 */
180 #if 0
181   , /* Completeness, we must have completeness */
182   {1, 1, 1, 0, 1, 1, 1},  /* A */
183   {0, 0, 1, 1, 1, 1, 1},  /* b */
184   {1, 0, 0, 1, 1, 1, 0},  /* C */
185   {0, 1, 1, 1, 1, 0, 1},  /* d */
186   {1, 0, 0, 1, 1, 1, 1},  /* E */
187   {1, 0, 0, 0, 1, 1, 1}   /* F */
188 #define MAX_DIGITS 16
189 #else
190 #define MAX_DIGITS 10
191 #endif
192 };
193 
194 static Bool led;
195 
196 /* Create an virtual parallelogram, normal rectangle parameters plus "lean":
197    the amount the start of a will be shifted to the right of the start of d.
198  */
199 
200 static XPoint parallelogramUnit[4] =
201 {
202 	{1, 0},
203 	{2, 0},
204 	{-1, 1},
205 	{-2, 0}
206 };
207 
208 static Bool binary;
209 static Bool popex;
210 static Bool forest;
211 static Bool hiv;
212 static Bool lab;
213 static Bool veg;
214 static Bool time24;
215 static Bool y2k;
216 static Bool millennium;
217 static Bool mayan;
218 
219 static XrmOptionDescRec opts[] =
220 {
221 	{(char *) "-binary", (char *) ".dclock.binary", XrmoptionNoArg, (caddr_t) "on"},
222 	{(char *) "+binary", (char *) ".dclock.binary", XrmoptionNoArg, (caddr_t) "off"},
223 	{(char *) "-led", (char *) ".dclock.led", XrmoptionNoArg, (caddr_t) "on"},
224 	{(char *) "+led", (char *) ".dclock.led", XrmoptionNoArg, (caddr_t) "off"},
225 	{(char *) "-popex", (char *) ".dclock.popex", XrmoptionNoArg, (caddr_t) "on"},
226 	{(char *) "+popex", (char *) ".dclock.popex", XrmoptionNoArg, (caddr_t) "off"},
227 	{(char *) "-forest", (char *) ".dclock.forest", XrmoptionNoArg, (caddr_t) "on"},
228 	{(char *) "+forest", (char *) ".dclock.forest", XrmoptionNoArg, (caddr_t) "off"},
229 	{(char *) "-hiv", (char *) ".dclock.hiv", XrmoptionNoArg, (caddr_t) "on"},
230 	{(char *) "+hiv", (char *) ".dclock.hiv", XrmoptionNoArg, (caddr_t) "off"},
231 	{(char *) "-lab", (char *) ".dclock.lab", XrmoptionNoArg, (caddr_t) "on"},
232 	{(char *) "+lab", (char *) ".dclock.lab", XrmoptionNoArg, (caddr_t) "off"},
233 	{(char *) "-veg", (char *) ".dclock.veg", XrmoptionNoArg, (caddr_t) "on"},
234 	{(char *) "+veg", (char *) ".dclock.veg", XrmoptionNoArg, (caddr_t) "off"},
235 	{(char *) "-time24", (char *) ".dclock.time24", XrmoptionNoArg, (caddr_t) "on"},
236 	{(char *) "+time24", (char *) ".dclock.time24", XrmoptionNoArg, (caddr_t) "off"},
237 	{(char *) "-y2k", (char *) ".dclock.y2k", XrmoptionNoArg, (caddr_t) "on"},
238 	{(char *) "+y2k", (char *) ".dclock.y2k", XrmoptionNoArg, (caddr_t) "off"},
239 	{(char *) "-millennium", (char *) ".dclock.millennium", XrmoptionNoArg, (caddr_t) "on"},
240 	{(char *) "+millennium", (char *) ".dclock.millennium", XrmoptionNoArg, (caddr_t) "off"},
241 	{(char *) "-mayan", (char *) ".dclock.mayan", XrmoptionNoArg, (caddr_t) "on"},
242 	{(char *) "+mayan", (char *) ".dclock.mayan", XrmoptionNoArg, (caddr_t) "off"}
243 };
244 static argtype vars[] =
245 {
246 	{(void *) & binary, (char *) "binary", (char *) "Binary", (char *) DEF_BINARY, t_Bool},
247 	{(void *) & led, (char *) "led", (char *) "LED", (char *) DEF_LED, t_Bool},
248 	{(void *) & popex, (char *) "popex", (char *) "PopEx", (char *) DEF_POPEX, t_Bool},
249 	{(void *) & forest, (char *) "forest", (char *) "Forest", (char *) DEF_FOREST, t_Bool},
250 	{(void *) & hiv, (char *) "hiv", (char *) "Hiv", (char *) DEF_HIV, t_Bool},
251 	{(void *) & lab, (char *) "lab", (char *) "Lab", (char *) DEF_LAB, t_Bool},
252 	{(void *) & veg, (char *) "veg", (char *) "Veg", (char *) DEF_VEG, t_Bool},
253 	{(void *) & time24, (char *) "time24", (char *) "Time24", (char *) DEF_TIME24, t_Bool},
254 	{(void *) & y2k, (char *) "y2k", (char *) "Y2K", (char *) DEF_Y2K, t_Bool},
255 	{(void *) & millennium, (char *) "millennium", (char *) "Millennium", (char *) DEF_Y2001, t_Bool},
256 	{(void *) & mayan, (char *) "mayan", (char *) "Mayan", (char *) DEF_MAYAN, t_Bool}
257 };
258 static OptionStruct desc[] =
259 {
260 	{(char *) "-/+binary", (char *) "turn on/off binary clock display"},
261 	{(char *) "-/+led", (char *) "turn on/off Light Emitting Diode seven segment display"},
262 	{(char *) "-/+popex", (char *) "turn on/off population explosion counter"},
263 	{(char *) "-/+forest", (char *) "turn on/off tropical forest destruction counter"},
264 	{(char *) "-/+hiv", (char *) "turn on/off HIV infection counter"},
265 	{(char *) "-/+lab", (char *) "turn on/off Animal Research counter"},
266 	{(char *) "-/+veg", (char *) "turn on/off Animal Consumation counter"},
267 	{(char *) "-/+time24", (char *) "turn on/off 24 hour display"},
268 	{(char *) "-/+y2k", (char *) "turn on/off Year 2000 countdown"},
269 	{(char *) "-/+millennium", (char *) "turn on/off 3rd Millennium (1 January 2001) countdown"},
270 	{(char *) "-/+mayan", (char *) "turn on/off 13 bak'tun (21 December 2012) countdown"},
271 };
272 
273 ENTRYPOINT ModeSpecOpt dclock_opts =
274 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
275 
276 #ifdef USE_MODULES
277 ModStruct dclock_description =
278 {"dclock", "init_dclock", "draw_dclock", "release_dclock",
279  "refresh_dclock", "init_dclock", (char *) NULL, &dclock_opts,
280  10000, 1, 10000, 1, 64, 0.3, "",
281  "Shows a floating digital clock or message", 0, NULL};
282 
283 #endif
284 
285 #ifdef HAVE_SYS_PARAM_H
286 #include <sys/param.h>
287 #endif
288 #include <time.h>
289 
290 /* language depended resources */
291 #if defined FR
292 #include "dclock-msg-fr.h"
293 #elif defined NL
294 #include "dclock-msg-nl.h"
295 #elif defined JA
296 #include "dclock-msg-ja.h"
297 #else
298 #include "dclock-msg-en.h"
299 #endif
300 
301 #ifdef USE_MB
302 static XFontSet mode_font = None;
getFontHeight(XFontSet f)303 static int getFontHeight(XFontSet f)
304 {
305 	XRectangle ink, log;
306 
307 	if (f == None) {
308 		return 8;
309 	} else {
310 		XmbTextExtents(mode_font, "My", strlen("My"), &ink, &log);
311 		return log.height;
312 	}
313 }
getTextWidth(char * string)314 static int getTextWidth(char *string)
315 {
316 	XRectangle ink, logical;
317 
318 	XmbTextExtents(mode_font, string, strlen(string), &ink, &logical);
319 	return logical.width;
320 }
321 #define DELTA 0.2
322 extern XFontSet getFontSet(Display * display);
323 #define DrawString(d, p, gc, start, ascent, string, len) (void) XmbDrawString(\
324 	d, p, mode_font, gc, start, ascent, string, len)
325 #else
326 static XFontStruct *mode_font = None;
327 #define getFontHeight(f) ((f == None) ? 8 : f->ascent + f->descent)
getTextWidth(char * string)328 static int getTextWidth(char *string)
329 {
330 	return XTextWidth(mode_font, string, strlen(string));
331 }
332 #define DELTA 0
333 extern XFontStruct *getFont(Display * display);
334 #define DrawString(d, p, gc, start, ascent, string, len) (void) XDrawString(\
335 	d, p, gc, start, ascent, string, len)
336 #endif
337 
338 #if 0
339 #define MAXWIDTH BUFSIZ
340 #else
341 #define MAXWIDTH 170
342 #endif
343 #if 0
344 #define STRSIZE 50
345 #define MAXLINES 2
346 #else
347 #define STRSIZE BUFSIZ
348 #define MAXLINES 40
349 #endif
350 
351 typedef struct {
352 	int         color;
353 	short       height, width;
354 	char       *str;
355 	int         lines;
356 	char        strnew[MAXLINES][STRSIZE], strold[MAXLINES][STRSIZE];
357 	char       *strpta[MAXLINES], *strptb[MAXLINES];
358 	short       textWidth[MAXLINES], textStart[MAXLINES];
359 	time_t      timenew, timeold;
360 	int         tzoffset;
361 	short       maxx, maxy, clockx, clocky;
362 	short       text_height, text_width, text_ascent, text_descent;
363 	short       hour;
364 	short       dx, dy;
365 	int         pixw, pixh;
366 	Pixmap      pixmap;
367 	GC          fgGC, bgGC;
368 	Bool        popex, forest, hiv, lab, veg;
369 	Bool        time24, y2k, millennium, mayan, led, binary;
370 	XPoint      parallelogram[4];
371 } dclockstruct;
372 
373 static dclockstruct *dclocks = (dclockstruct *) NULL;
374 
375 extern char *message;
376 
377 #ifdef STANDALONE
378 char * message = NULL;
379 #endif
380 
381 static time_t
timeAtLastNewYear(time_t timeNow)382 timeAtLastNewYear(time_t timeNow)
383 {
384 	struct tm *t;
385 
386 	t = localtime(&timeNow);
387 	t->tm_mon = 0;
388 	t->tm_mday = 1;
389 	t->tm_hour = 0;
390 	t->tm_min = 0;
391 	t->tm_sec = 0;
392 	t->tm_isdst = -1; /* mktime shall decide itself */
393 	return mktime(t);
394 }
395 
396 #ifndef HAVE_SNPRINTF
397 static double logbase = 0.0;
398 #define BASE 10.0
399 #define GROUP 3
400 #endif
401 
402 static void
convert(double x,char * string)403 convert(double x, char *string)
404 {
405 #ifdef HAVE_SNPRINTF
406 /* Also old C compiler can not accept this syntax, but this syntax awares
407    locale.  Known to work with gcc-2.95.2 and glibc-2.1.3. */
408 	(void) snprintf(string, STRSIZE, "%'.0f", x);
409 #else
410 
411 	int i, j, k = 0;
412 	int place = (int) (log(x) / logbase);
413 	double divisor = 1.0;
414 
415 	for (i = 0; i < place; i++)
416 		divisor *= BASE;
417 
418 	for (i = place; i >= 0; i--) {
419 		j = (int) (x / divisor);
420 		string[k++] = (char) j + '0';
421 		x -= j * divisor;
422 		divisor /= BASE;
423 		if ((i > 0) && (i % GROUP == 0)) {
424 			string[k++] = ',';
425 		}
426 	}
427 	string[k] = '\0';
428 #endif
429 }
430 
431 static void
dayhrminsec(time_t timeCount,int tzoffset,char * string)432 dayhrminsec(time_t timeCount, int tzoffset, char *string)
433 {
434 	int days, hours, minutes, secs;
435 	int bufsize, i;
436 
437 	timeCount = ABS(timeCount);
438 	days = (int) (timeCount / 86400);
439 	hours = (int) ((timeCount / 3600) % 24);
440 	minutes = (int) ((timeCount / 60) % 60);
441 	secs = (int) (timeCount % 60);
442 
443 	/* snprintf would make this easier but its not always available */
444 	bufsize = 16 + strlen((days==1) ? DAY : DAYS);
445 	if (bufsize >= STRSIZE)
446 		return;
447 	(void) sprintf(string, "%d %s", days, (days==1) ? DAY : DAYS);
448 
449 	i = strlen(string);
450 	bufsize = 4 + strlen((hours==1) ? HOUR : HOURS);
451 	if (i + bufsize >= STRSIZE)
452 		return;
453 	(void) sprintf(&string[i], " %d %s", hours, (hours==1) ? HOUR : HOURS);
454 
455 	i = strlen(string);
456 	bufsize = 4 + strlen((minutes==1) ? MINUTE : MINUTES);
457 	if (i + bufsize >= STRSIZE)
458 		return;
459 	(void) sprintf(&string[i], " %d %s", minutes,
460 		(minutes==1) ? MINUTE : MINUTES);
461 
462 	i = strlen(string);
463 	bufsize += 4 + strlen((secs==1) ? SECOND : SECONDS);
464 	if (i + bufsize >= STRSIZE)
465 		return;
466 	(void) sprintf(&string[i], " %d %s", secs,
467 		(secs==1) ? SECOND : SECONDS);
468 
469 	if (!tzoffset) {
470 		i = strlen(string);
471 		bufsize += 6; /* strlen(" (UTC)"); */
472 		if (i + bufsize >= STRSIZE)
473 			return;
474 		(void) strcat(string, " (UTC)");
475 	}
476 }
477 
478 static void
drawaled(ModeInfo * mi,int startx,int starty,int aled)479 drawaled(ModeInfo * mi, int startx, int starty, int aled)
480 {
481 	Display *display = MI_DISPLAY(mi);
482 	dclockstruct *dp = &dclocks[MI_SCREEN(mi)];
483  	int x_1, y_1, x_2, y_2;
484 
485 	int offset = (int) LED_WIDTH;
486 	int offset2 = (int) (LED_WIDTH / 2.0);
487 	int leanoffset = (int) (offset2 * LED_LEAN);
488 
489 	switch (aled) {
490 		case 0: /* a */
491 			x_1 = startx + dp->parallelogram[0].x;
492 			y_1 = starty + dp->parallelogram[0].y;
493 			x_2 = x_1 + dp->parallelogram[1].x - offset;
494 			y_2 = y_1 + dp->parallelogram[1].y;
495 			x_1 = x_1 + offset;
496 			XDrawLine(display, dp->pixmap, dp->fgGC,
497 				x_1, y_1, x_2, y_2);
498 			break;
499 		case 1: /* b */
500 			x_1 = startx + dp->parallelogram[0].x +
501 				dp->parallelogram[1].x;
502 			y_1 = starty + dp->parallelogram[0].y +
503 				dp->parallelogram[1].y;
504 			x_2 = x_1 + dp->parallelogram[2].x / 2 + leanoffset;
505 			y_2 = y_1 + dp->parallelogram[2].y / 2 - offset2;
506 			x_1 = x_1 - leanoffset;
507 			y_1 = y_1 + offset2;
508 			XDrawLine(display, dp->pixmap, dp->fgGC,
509 				x_1, y_1, x_2, y_2);
510 			break;
511 		case 2: /* c */
512 			x_1 = startx + dp->parallelogram[0].x +
513 				dp->parallelogram[1].x +
514 				dp->parallelogram[2].x;
515 			y_1 = starty + dp->parallelogram[0].y +
516 				dp->parallelogram[1].y +
517 				dp->parallelogram[2].y;
518 			x_2 = x_1 - dp->parallelogram[2].x / 2 - leanoffset;
519 			y_2 = y_1 - dp->parallelogram[2].y / 2 + offset2;
520 			x_1 = x_1 + leanoffset;
521 			y_1 = y_1 - offset2;
522 			XDrawLine(display, dp->pixmap, dp->fgGC,
523 				x_1, y_1, x_2, y_2);
524 			break;
525 		case 3: /* d */
526 			x_1 = startx + dp->parallelogram[0].x +
527 				dp->parallelogram[2].x;
528 			y_1 = starty + dp->parallelogram[0].y +
529 				dp->parallelogram[2].y;
530 			x_2 = x_1 + dp->parallelogram[1].x - offset;
531 			y_2 = y_1 + dp->parallelogram[1].y;
532 			x_1 = x_1 + offset;
533 			XDrawLine(display, dp->pixmap, dp->fgGC,
534 				x_1, y_1, x_2, y_2);
535 			break;
536 		case 4: /* e */
537 			x_1 = startx + dp->parallelogram[0].x +
538 				dp->parallelogram[2].x;
539 			y_1 = starty + dp->parallelogram[0].y +
540 				dp->parallelogram[2].y;
541 			x_2 = x_1 - dp->parallelogram[2].x / 2 - leanoffset;
542 			y_2 = y_1 - dp->parallelogram[2].y / 2 + offset2;
543 			x_1 = x_1 + leanoffset;
544 			y_1 = y_1 - offset2;
545 			XDrawLine(display, dp->pixmap, dp->fgGC,
546 				x_1, y_1, x_2, y_2);
547 			break;
548 		case 5: /* f */
549 			x_1 = startx + dp->parallelogram[0].x;
550 			y_1 = starty + dp->parallelogram[0].y;
551 			x_2 = x_1 + dp->parallelogram[2].x / 2 + leanoffset;
552 			y_2 = y_1 + dp->parallelogram[2].y / 2 - offset2;
553 			x_1 = x_1 - leanoffset;
554 			y_1 = y_1 + offset2;
555 			XDrawLine(display, dp->pixmap, dp->fgGC,
556 				x_1, y_1, x_2, y_2);
557 			break;
558 		case 6: /* g */
559 			x_1 = startx + dp->parallelogram[0].x +
560 				dp->parallelogram[2].x / 2;
561 			y_1 = starty + dp->parallelogram[0].y +
562 				dp->parallelogram[2].y / 2;
563 			x_2 = x_1 + dp->parallelogram[1].x - offset;
564 			y_2 = y_1 + dp->parallelogram[1].y;
565 			x_1 = x_1 + offset;
566 			XDrawLine(display, dp->pixmap, dp->fgGC,
567 				x_1, y_1, x_2, y_2);
568 
569 	}
570 }
571 
572 static void
drawacolon(ModeInfo * mi,int startx,int starty)573 drawacolon(ModeInfo * mi, int startx, int starty)
574 {
575 	Display *display = MI_DISPLAY(mi);
576 	dclockstruct *dp = &dclocks[MI_SCREEN(mi)];
577  	int x_1, y_1, x_2, y_2;
578 
579 	int offset2 = (int) (LED_WIDTH / 2.0);
580 	int leanoffset = (int) (offset2 * LED_LEAN);
581 
582 	x_1 = startx + dp->parallelogram[0].x +
583 		(int) (dp->parallelogram[2].x / 2 - 2.0 * leanoffset);
584 	y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y / 2 +
585 		(int) (2.0 * offset2);
586 	x_2 = x_1 - (int) (2.0 * leanoffset);
587 	y_2 = y_1 + (int) (2.0 * offset2);
588 	XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2);
589 	x_1 = startx + dp->parallelogram[0].x +
590 		dp->parallelogram[2].x / 2 + (int) (2.0 * leanoffset);
591 	y_1 = starty + dp->parallelogram[0].y + dp->parallelogram[2].y / 2 -
592 		(int) (2.0 * offset2);
593 	x_2 = x_1 + (int) (2.0 * leanoffset);
594 	y_2 = y_1 - (int) (2.0 * offset2);
595 	XDrawLine(display, dp->pixmap, dp->fgGC, x_1, y_1, x_2, y_2);
596 }
597 
598 static void
drawanumber(ModeInfo * mi,int startx,int starty,int digit)599 drawanumber(ModeInfo * mi, int startx, int starty, int digit)
600 {
601 	int aled;
602 
603 	for (aled = 0; aled < MAX_LEDS; aled++) {
604 		if (digits[digit][aled])
605 			drawaled(mi, startx, starty, aled);
606 	}
607 }
608 
609 static void
drawadot(ModeInfo * mi,int startx,int starty,int filled)610 drawadot(ModeInfo * mi, int startx, int starty, int filled)
611 {
612 	Display *display = MI_DISPLAY(mi);
613 	dclockstruct *dp = &dclocks[MI_SCREEN(mi)];
614 
615 	if (filled)
616 		XFillArc(display, dp->pixmap, dp->fgGC, startx, starty,
617 			BINARY_WIDTH, BINARY_HEIGHT, 0, 23040);
618 	else
619 		XDrawArc(display, dp->pixmap, dp->fgGC, startx, starty,
620 			BINARY_WIDTH, BINARY_HEIGHT, 0, 23040);
621 }
622 
623 static void
drawabinary(ModeInfo * mi,int startx,int starty,int dotcount,int digit)624 drawabinary(ModeInfo * mi, int startx, int starty, int dotcount, int digit)
625 {
626 	int newy;
627 	int filled;
628 	int i;
629 
630 	for (i=0; i < dotcount; i++) {
631 		newy = starty + ((BINARY_HEIGHT + BINARY_INC) * (3 - i));
632 		filled = (digit >> i) & 0x01;
633 		drawadot(mi, startx, newy, filled);
634 	}
635 }
636 
637 static void
free_dclock_screen(Display * display,dclockstruct * dp)638 free_dclock_screen(Display *display, dclockstruct *dp)
639 {
640 	if (dp == NULL) {
641 		return;
642 	}
643 	if (dp->fgGC != None) {
644 		XFreeGC(display, dp->fgGC);
645 		dp->fgGC = None;
646 	}
647 	if (dp->bgGC) {
648 		XFreeGC(display, dp->bgGC);
649 		dp->bgGC = None;
650 	}
651 	if (dp->pixmap) {
652 		XFreePixmap(display, dp->pixmap);
653 		dp->pixmap = None;
654 	}
655 	dp = NULL;
656 }
657 
658 
659 static void
drawDclock(ModeInfo * mi)660 drawDclock(ModeInfo * mi)
661 {
662 	Display *display = MI_DISPLAY(mi);
663 	Window window = MI_WINDOW(mi);
664 	GC gc = MI_GC(mi);
665 	dclockstruct *dp = &dclocks[MI_SCREEN(mi)];
666 	short xold, yold;
667 	int i, j;
668 
669 	if (!(message && *message)) {
670 	  if (dp->led || dp->binary) {
671 		dp->timeold = dp->timenew = time((time_t *) NULL);
672 		dp->str = ctime(&dp->timeold);
673 	  } else if (!dp->popex && !dp->forest && !dp->hiv &&
674 	    !dp->lab && !dp->veg && !dp->y2k && !dp->millennium && !dp->mayan) {
675 		if (dp->timeold != (dp->timenew = time((time_t *) NULL))) {
676 			/* only parse if time has changed */
677 			dp->timeold = dp->timenew;
678 
679 			if (!dp->popex && !dp->forest && !dp->hiv && !dp->lab &&
680 			    !dp->veg && !dp->y2k && !dp->millennium && !dp->mayan) {
681 			  if (dp->time24)
682 				(void) strftime(dp->strpta[0], STRSIZE,
683 					"%H:%M:%S", localtime(&(dp->timeold)));
684 			  else
685 				(void) strftime(dp->strpta[0], STRSIZE,
686 					"%I:%M:%S %p", localtime(&(dp->timeold)));
687 			}
688 			(void) strftime(dp->strpta[1], STRSIZE,
689 				"%a %b %d %Y", localtime(&(dp->timeold)));
690 		}
691 	  } else {
692 		time_t timeNow, timeLocal;
693 		timeNow = seconds();
694 		timeLocal = timeNow + dp->tzoffset;
695 
696 		if (dp->popex) {
697 			convert(PEOPLE_TIME_START + (PEOPLE_MIN / 60.0) * timeNow, dp->strnew[1]);
698 			(void) strncat(dp->strnew[1], PEOPLE_STRING,
699 				STRSIZE-strlen(dp->strnew[1]));
700 			dp->strpta[1] = dp->strnew[1];
701 			dp->strptb[1] = dp->strpta[1];
702 		} else if (dp->forest) {
703 			convert(AREA_TIME_START - (AREA_MIN / 60.0) * timeNow, dp->strnew[1]);
704 			(void) strncat(dp->strnew[1], TROPICAL_STRING,
705 				STRSIZE-strlen(dp->strnew[1]));
706 			(void) strncat(dp->strnew[1], AREA_STRING,
707 				STRSIZE-strlen(dp->strnew[1]));
708 			dp->strpta[1] = dp->strnew[1];
709 			dp->strptb[1] = dp->strpta[1];
710 		} else if (dp->hiv) {
711 			convert(HIV_TIME_START + (HIV_MIN / 60.0) * timeNow, dp->strnew[1]);
712 			(void) strncat(dp->strnew[1], CASES_STRING,
713 				STRSIZE-strlen(dp->strnew[1]));
714 			dp->strpta[1] = dp->strnew[1];
715 			dp->strptb[1] = dp->strpta[1];
716 		} else if (dp->lab) {
717 			convert((LAB_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)),
718 				dp->strnew[1]);
719 			(void) strncat(dp->strnew[1], YEAR_STRING,
720 				STRSIZE-strlen(dp->strnew[1]));
721 			dp->strpta[1] = dp->strnew[1];
722 			dp->strptb[1] = dp->strpta[1];
723 		} else if (dp->veg) {
724 			convert((VEG_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)),
725 				dp->strnew[1]);
726 			(void) strncat(dp->strnew[1], YEAR_STRING,
727 				STRSIZE-strlen(dp->strnew[1]));
728 			dp->strpta[1] = dp->strnew[1];
729 			dp->strptb[1] = dp->strpta[1];
730 		} else if (dp->y2k) {
731 			if (Y2K_TIME_START >= timeLocal)
732 				dp->strpta[0] = (char *) Y2K_STRING;
733 			else
734 				dp->strpta[0] = (char *) POST_Y2K_STRING;
735 			dp->strptb[0] = dp->strpta[0];
736 			dayhrminsec(Y2K_TIME_START - timeLocal,
737 				dp->tzoffset, dp->strnew[1]);
738 			dp->strpta[1] = dp->strnew[1];
739 			dp->strptb[1] = dp->strpta[1];
740 		} else if (dp->millennium) {
741 			if (Y2001_TIME_START >= timeLocal)
742 				dp->strpta[0] = (char *) Y2001_STRING;
743 			else
744 				dp->strpta[0] = (char *) POST_Y2001_STRING;
745 			dp->strptb[0] = dp->strpta[0];
746 			dayhrminsec(Y2001_TIME_START - timeLocal,
747 				dp->tzoffset, dp->strnew[1]);
748 			dp->strpta[1] = dp->strnew[1];
749 			dp->strptb[1] = dp->strpta[1];
750 		} else if (dp->mayan) {
751 			if (MAYAN_TIME_START >= timeLocal)
752 				dp->strpta[0] = (char *) MAYAN_STRING;
753 			else
754 				dp->strpta[0] = (char *) POST_MAYAN_STRING;
755 			dp->strptb[0] = dp->strpta[0];
756 			dayhrminsec(MAYAN_TIME_START - timeLocal,
757 				dp->tzoffset, dp->strnew[1]);
758 			dp->strpta[1] = dp->strnew[1];
759 			dp->strptb[1] = dp->strpta[1];
760 		}
761 	  }
762 	}
763 	/* Recalculate string width since it can change */
764 	xold = dp->clockx;
765 	yold = dp->clocky;
766 	if (!dp->led && !dp->binary) {
767 		j = 0;
768 		for (i = 0; i < dp->lines; i++) {
769 			if (dp->strpta[i] && *(dp->strpta[i]))
770 				dp->textWidth[i] = getTextWidth(dp->strpta[i]);
771 			if (dp->textWidth[i] > dp->textWidth[j]) {
772 				j = i;
773 			}
774 		}
775 		dp->text_width = dp->textWidth[j];
776 		for (i = 0; i < dp->lines; i++) {
777 			dp->textStart[i] = (dp->text_width -
778 				dp->textWidth[i]) / 2;
779 		}
780 	}
781 	dp->width = MI_WIDTH(mi);
782 	dp->height = MI_HEIGHT(mi);
783 	dp->maxx = dp->width - dp->text_width;
784 	dp->maxy = dp->height - (dp->lines - 1) * dp->text_height -
785 		dp->text_descent;
786 	dp->clockx += dp->dx;
787 	dp->clocky += dp->dy;
788 	if (dp->maxx < dp->textStart[0]) {
789 		if (dp->clockx < dp->maxx + dp->textStart[0] ||
790 				dp->clockx > dp->textStart[0]) {
791 			dp->dx = -dp->dx;
792 			dp->clockx += dp->dx;
793 		}
794 	} else if (dp->maxx > dp->textStart[0]) {
795 		if (dp->clockx >= dp->maxx + dp->textStart[0] ||
796 				dp->clockx <= dp->textStart[0]) {
797 			dp->dx = -dp->dx;
798 			dp->clockx += dp->dx;
799 		}
800 	}
801 	if (dp->maxy < dp->text_ascent) {
802 		if (dp->clocky > dp->text_ascent || dp->clocky < dp->maxy) {
803 			dp->dy = -dp->dy;
804 			dp->clocky += dp->dy;
805 		}
806 	} else if (dp->maxy > dp->text_ascent) {
807 		if (dp->clocky > dp->maxy || dp->clocky < dp->text_ascent) {
808 			dp->dy = -dp->dy;
809 			dp->clocky += dp->dy;
810 		}
811 	}
812 	if (dp->pixw != dp->text_width ||
813 			dp->pixh != dp->lines * dp->text_height) {
814 		XGCValues gcv;
815 
816 		if (dp->pixmap)
817 			MI_CLEARWINDOWCOLORMAPFAST(mi, gc, MI_BLACK_PIXEL(mi));
818 		free_dclock_screen(display, dp);
819 		dp->pixw = dp->text_width;
820 		if (dp->led)
821 			dp->pixh = dp->text_height;
822 		else
823 			dp->pixh = (dp->lines + DELTA) * dp->text_height;
824 		if ((dp->pixmap = XCreatePixmap(display, window,
825 				dp->pixw, dp->pixh, 1)) == None) {
826 			free_dclock_screen(display, dp);
827 			dp->pixw = 0;
828 			dp->pixh = 0;
829 			return;
830 		}
831 #ifndef USE_MB
832 		gcv.font = mode_font->fid;
833 #endif
834 		gcv.background = 0;
835 		gcv.foreground = 1;
836 		gcv.graphics_exposures = False;
837 		if ((dp->fgGC = XCreateGC(display, dp->pixmap,
838 			GCForeground | GCBackground | GCGraphicsExposures
839 #ifndef USE_MB
840 			| GCFont
841 #endif
842 			, &gcv)) == None) {
843 			free_dclock_screen(display, dp);
844 			dp->pixw = 0;
845 			dp->pixh = 0;
846 			return;
847 		}
848 		gcv.foreground = 0;
849 		if ((dp->bgGC = XCreateGC(display, dp->pixmap,
850 			GCForeground | GCBackground | GCGraphicsExposures
851 #ifndef USE_MB
852 			| GCFont
853 #endif
854 			, &gcv)) == None) {
855 			free_dclock_screen(display, dp);
856 			dp->pixw = 0;
857 			dp->pixh = 0;
858 			return;
859 		}
860 		if (!dp->binary)
861 			XSetLineAttributes(display, dp->fgGC,
862 				(unsigned int) (LED_WIDTH),
863 				LineSolid, CapButt, JoinMiter);
864 	}
865 	XFillRectangle(display, dp->pixmap, dp->bgGC,
866 		0, 0, dp->pixw, dp->pixh);
867 	if (dp->led) {
868 		int startx = (int) (LED_WIDTH / 2.0);
869 		int starty = (int) (LED_WIDTH / 2.0);
870 
871 		drawanumber(mi, startx, starty, dp->str[11] - '0');
872 		startx += (int) (LED_XS + LED_WIDTH + LED_INC);
873 		drawanumber(mi, startx, starty, dp->str[12] - '0');
874 		startx += (int) (LED_XS + LED_WIDTH + LED_INC);
875 		drawacolon(mi, startx, starty);
876 		startx += (int) (LED_WIDTH + LED_INC);
877 		drawanumber(mi, startx, starty, dp->str[14] - '0');
878 		startx += (int) (LED_XS + LED_WIDTH + LED_INC);
879 		drawanumber(mi, startx, starty, dp->str[15] - '0');
880 		startx += (int) (LED_XS + LED_WIDTH + LED_INC);
881 		drawacolon(mi, startx, starty);
882 		startx += (int) (LED_WIDTH + LED_INC);
883 		drawanumber(mi, startx, starty, dp->str[17] - '0');
884 		startx += (int) (LED_XS + LED_WIDTH + LED_INC);
885 		drawanumber(mi, startx, starty, dp->str[18] - '0');
886 	} else if (dp->binary) {
887 		int startx = BINARY_WIDTH / 2;
888 		int starty = BINARY_HEIGHT / 2;
889 
890 		/* hour - top number, 0, 1 or 2 */
891 		drawabinary(mi, startx, starty, 2, dp->str[11] - '0');
892 		startx += (BINARY_WIDTH + BINARY_INC);
893 		/* hour - bottom number 0 - 9 */
894 		drawabinary(mi, startx, starty, 4, dp->str[12] - '0');
895 		startx += (BINARY_WIDTH + BINARY_INC);
896 		/* minute - top number, 0 - 5 */
897 		drawabinary(mi, startx, starty, 3, dp->str[14] - '0');
898 		startx += (BINARY_WIDTH + BINARY_INC);
899 		/* minute - bottom number, 0 - 9 */
900 		drawabinary(mi, startx, starty, 4, dp->str[15] - '0');
901 		startx += (BINARY_WIDTH + BINARY_INC);
902 		/* second - top number, 0 - 5 */
903 		drawabinary(mi, startx, starty, 3, dp->str[17] - '0');
904 		startx += (BINARY_WIDTH + BINARY_INC);
905 		/* second - bottom number, 0 - 9 */
906 		drawabinary(mi, startx, starty, 4, dp->str[18] - '0');
907 		startx += (BINARY_WIDTH + BINARY_INC);
908 	} else {
909 		for (i = 0; i < dp->lines; i++) {
910 			DrawString(display, dp->pixmap, dp->fgGC,
911 				dp->textStart[i],
912 				dp->text_ascent + i * dp->text_height,
913 				dp->strpta[i], strlen(dp->strpta[i]));
914 		}
915 	}
916 
917 	XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
918 	/* This could leave screen dust on the screen if the width changes
919 	   But that only happens once a day... (well maybe not for counts)
920 	   ... this is solved by the ClearWindow above
921 	 */
922 	ERASE_IMAGE(display, window, gc,
923 		(dp->clockx - dp->textStart[0]),
924 		(dp->clocky - dp->text_ascent),
925 		(xold - dp->textStart[0]), (yold - dp->text_ascent),
926 		dp->pixw, dp->pixh);
927 	if (MI_NPIXELS(mi) > 2)
928 		XSetForeground(display, gc, MI_PIXEL(mi, dp->color));
929 	else
930 		XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
931 	XCopyPlane(display, dp->pixmap, window, gc,
932 		0, 0, dp->text_width, (dp->lines + DELTA) * dp->text_height,
933 		dp->clockx - dp->textStart[0], dp->clocky - dp->text_ascent,
934 		1L);
935 }
936 
937 ENTRYPOINT void
release_dclock(ModeInfo * mi)938 release_dclock(ModeInfo * mi)
939 {
940 	if (dclocks != NULL) {
941 		int screen;
942 
943 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
944 			free_dclock_screen(MI_DISPLAY(mi), &dclocks[screen]);
945 		free(dclocks);
946 		dclocks = (dclockstruct *) NULL;
947 	}
948 	if (mode_font != None) {
949 #ifdef USE_MB
950 		XFreeFontSet(MI_DISPLAY(mi), mode_font);
951 #else
952 		XFreeFont(MI_DISPLAY(mi), mode_font);
953 #endif
954 		mode_font = None;
955 	}
956 }
957 
958 #if defined(HAVE_TZSET) && !(defined(BSD) && BSD >= 199306) && !(defined(__CYGWIN__))
959 extern long timezone;
960 #endif
961 
962 ENTRYPOINT void
init_dclock(ModeInfo * mi)963 init_dclock(ModeInfo * mi)
964 {
965 	Display *display = MI_DISPLAY(mi);
966 	dclockstruct *dp;
967 	time_t timeNow, timeLocal;
968 	int i, j;
969 
970 	MI_INIT(mi, dclocks);
971 	dp = &dclocks[MI_SCREEN(mi)];
972 
973 #ifndef HAVE_SNPRINTF
974 	if (logbase == 0.0)
975 		logbase = log(BASE);
976 #endif
977 	dp->width = MI_WIDTH(mi);
978 	dp->height = MI_HEIGHT(mi);
979 
980 	MI_CLEARWINDOW(mi);
981 
982 	dp->binary = False;
983 	dp->led = False;
984 	dp->popex = False;
985 	dp->forest = False;
986 	dp->hiv = False;
987 	dp->lab = False;
988 	dp->veg = False;
989 	dp->time24 = False;
990 	dp->y2k = False;
991 	dp->millennium = False;
992 	dp->mayan = False;
993 	dp->lines = 2;
994 #if defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan)
995 #define NUM_DCLOCK_MODES 12
996 #endif
997 #if (defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) && !defined(MODE_dclock_mayan)) || (defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan)) || (!defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan))
998 #define NUM_DCLOCK_MODES 11
999 #endif
1000 #if (!defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan)) || (!defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) && !defined(MODE_dclock_mayan)) || (defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) && !defined(MODE_dclock_mayan))
1001 #define NUM_DCLOCK_MODES 10
1002 #endif
1003 #if (!defined(MODE_dclock_y2k) && !defined(MODE_dclock_millennium) && !defined(MODE_dclock_mayan))
1004 #define NUM_DCLOCK_MODES 9
1005 #endif
1006 #ifdef WIN32
1007 	if (NRAND(2)) {
1008 				dp->led = True;
1009 	} else {
1010 				dp->binary = True;
1011 	}
1012 #else
1013 	if (!(message && *message)) {
1014 	    if (MI_IS_FULLRANDOM(mi)) {
1015 		switch (NRAND(NUM_DCLOCK_MODES)) {
1016 			case 0:
1017 				break;
1018 			case 1:
1019 				dp->led = True;
1020 				break;
1021 			case 2:
1022 				dp->popex = True;
1023 				break;
1024 			case 3:
1025 				dp->forest = True;
1026 				break;
1027 			case 4:
1028 				dp->hiv = True;
1029 				break;
1030 			case 5:
1031 				dp->lab = True;
1032 				break;
1033 			case 6:
1034 				dp->veg = True;
1035 				break;
1036 			case 7:
1037 				dp->time24 = True;
1038 				break;
1039 			case 8:
1040 				dp->binary = True;
1041 				break;
1042 #if defined(MODE_dclock_y2k) || defined(MODE_dclock_millennium) || defined(MODE_dclock_mayan)
1043 			case 9:
1044 #ifdef MODE_dclock_y2k
1045 				dp->y2k = True;
1046 #else
1047 #ifdef MODE_dclock_millennium
1048 				dp->millennium = True;
1049 #else
1050 				dp->mayan = True;
1051 #endif
1052 #endif
1053 				break;
1054 #if (defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium)) || (defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan)) || (defined(MODE_dclock_mayan) && defined(MODE_dclock_y2k))
1055 			case 10:
1056 #if (defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium))
1057 				dp->millennium = True;
1058 #else
1059 				dp->mayan = True;
1060 #endif
1061 				break;
1062 #if (defined(MODE_dclock_y2k) && defined(MODE_dclock_millennium) && defined(MODE_dclock_mayan))
1063 			case 11:
1064 				dp->mayan = True;
1065 				break;
1066 #endif
1067 #endif
1068 #endif
1069 			default:
1070 				break;
1071 		}
1072 	    } else { /* first come, first served */
1073 		dp->binary = binary;
1074 		dp->led = led;
1075 		dp->popex = popex;
1076 		dp->forest = forest;
1077 		dp->hiv = hiv;
1078 		dp->lab = lab;
1079 		dp->veg = veg;
1080 		dp->time24 = time24;
1081 		dp->y2k = y2k;
1082 		dp->millennium = millennium;
1083 		dp->mayan = mayan;
1084 	    }
1085 	}
1086 #endif
1087 
1088 	if (mode_font == None) {
1089 #ifdef USE_MB
1090 		mode_font = getFontSet(display);
1091 #else
1092 		mode_font = getFont(display);
1093 #endif
1094 		if (mode_font == None) {
1095 			release_dclock(mi);
1096 			return;
1097 		}
1098 	}
1099 	/* (void)time(&dp->timenew); */
1100 #if defined(HAVE_TZSET) && (!defined(HAVE_TIMELOCAL) || (defined(BSD) && BSD >= 199306))
1101 	(void) tzset();
1102 #endif
1103 	dp->timeold = dp->timenew = time((time_t *) NULL);
1104 #if defined(HAVE_TIMELOCAL) && !(defined(BSD) && BSD >= 199306)
1105 	dp->tzoffset = mktime(localtime(&dp->timeold)) -
1106 		mktime(gmtime(&dp->timeold));
1107 #else
1108 #if defined(HAVE_TZSET)
1109 	dp->tzoffset = (int)timezone;
1110 #else
1111 	dp->tzoffset = 0;
1112 #endif
1113 #endif
1114 	if (dp->tzoffset > 86400 || dp->tzoffset < -86400)
1115 		dp->tzoffset = 0;
1116 	dp->str = ctime(&dp->timeold);
1117 	dp->dx = (LRAND() & 1) ? 1 : -1;
1118 	dp->dy = (LRAND() & 1) ? 1 : -1;
1119 
1120 	timeNow = seconds();
1121 	timeLocal = timeNow + dp->tzoffset;
1122 	if (dp->led) {
1123 		dp->lines = 2;
1124 		/*dp->text_descent = 0;
1125 		dp->text_ascent = 0;*/
1126 		for (i = 0; i < 4; i++) {
1127 			if (parallelogramUnit[i].x == 1)
1128 				dp->parallelogram[i].x = (short) (LED_XS *
1129 					LED_LEAN);
1130 			else if (parallelogramUnit[i].x == 2)
1131 				dp->parallelogram[i].x = (short) LED_XS;
1132 			else if (parallelogramUnit[i].x == -1)
1133 				dp->parallelogram[i].x = (short) (-LED_XS *
1134 					LED_LEAN);
1135 			else if (parallelogramUnit[i].x == -2)
1136 				dp->parallelogram[i].x = (short) (-LED_XS);
1137 			else
1138 				dp->parallelogram[i].x = 0;
1139 			dp->parallelogram[i].y = (short) (LED_YS *
1140 					parallelogramUnit[i].y);
1141 		}
1142 		dp->parallelogram[0].x = (short) ((LED_XS * LED_LEAN) +
1143 			LED_INC);
1144 		dp->parallelogram[0].y = (short) LED_INC;
1145 		dp->text_width = (short) (6 * (LED_XS + LED_WIDTH + LED_INC) +
1146 			2 * (LED_WIDTH + LED_INC) + LED_XS * LED_LEAN - LED_INC);
1147 		dp->text_height = (short) (LED_YS + LED_WIDTH + LED_INC);
1148 		dp->maxy = dp->height - (dp->lines - 1) * dp->text_height;
1149 		if (dp->maxy == 0)
1150 			dp->clocky = 0;
1151 		else if (dp->maxy < 0)
1152 			dp->clocky = -NRAND(-dp->maxy);
1153 		else
1154 			dp->clocky = NRAND(dp->maxy);
1155 	} else if (dp->binary) {
1156 		dp->text_width = (6 * (BINARY_WIDTH + BINARY_INC)) +
1157 			BINARY_WIDTH;
1158 		dp->text_height = (4 * (BINARY_HEIGHT + BINARY_INC)) +
1159 			BINARY_HEIGHT;
1160 		dp->maxy = dp->height - (dp->lines - 1) * dp->text_height;
1161 		if (dp->maxy == 0)
1162 			dp->clocky = 0;
1163 		else if (dp->maxy < 0)
1164 			dp->clocky = -NRAND(-dp->maxy);
1165 		else
1166 			dp->clocky = NRAND(dp->maxy);
1167 	} else {
1168 #ifdef USE_MB
1169 		dp->text_descent = 0;
1170 		dp->text_ascent = getFontHeight(mode_font);
1171 #else
1172 		dp->text_descent = mode_font->descent;
1173 		dp->text_ascent = mode_font->ascent;
1174 #endif
1175 		if (message && *message) {
1176 			char *p, *p2, *p3, buf[BUFSIZ];
1177 			int height, w;
1178 
1179 			p = strncpy(buf, message, BUFSIZ - 1);
1180 			while (strlen(p) > 0) {
1181 				p2 = p + strlen(p) - 1;
1182 				if (*p2 == '\n')
1183 					*p2 = 0;
1184 				else
1185 					break;
1186 			}
1187 			for (height = 0; p && height < MAXLINES; height++) {
1188 				if (!(p2 = (char *) strchr(p, '\n')) ||
1189 						!p2[1]) {
1190 					p2 = p + strlen(p);
1191 				}
1192 				/* p2 now points to the first '\n' */
1193 				*p2 = 0;
1194 				for (w = 0; w < p2 - p; w++) {
1195 					p3 = p + w;
1196 					if (*p3 == '\t') /* this should be improved */
1197 						*p3 = ' ';
1198 				}
1199 				(void) strncpy(dp->strnew[height], p,
1200 					MAXWIDTH - 1);
1201 				dp->strpta[height] = dp->strnew[height];
1202 				dp->strptb[height] = dp->strpta[height];
1203 				dp->strpta[height][MAXWIDTH - 1] = '\0';
1204 				if (p == p2)
1205 					break;
1206 				p = p2 + 1;
1207 			}
1208 			dp->lines = height;
1209 		} else if (dp->popex) {
1210 			dp->strpta[0] = (char *) POPEX_STRING;
1211 			dp->strptb[0] = dp->strpta[0];
1212 			convert(PEOPLE_TIME_START + (PEOPLE_MIN / 60.0) * timeNow, dp->strnew[1]);
1213 			(void) strncat(dp->strnew[1], PEOPLE_STRING, STRSIZE-strlen(dp->strnew[1]));
1214 			dp->strpta[1] = dp->strnew[1];
1215 			dp->strptb[1] = dp->strpta[1];
1216 		} else if (dp->forest) {
1217 			dp->strpta[0] = (char *) FOREST_STRING;
1218 			dp->strptb[0] = dp->strpta[0];
1219 			convert(AREA_TIME_START - (AREA_MIN / 60.0) * timeNow, dp->strnew[1]);
1220 			(void) strncat(dp->strnew[1], TROPICAL_STRING, STRSIZE-strlen(dp->strnew[1]));
1221 			(void) strncat(dp->strnew[1], AREA_STRING, STRSIZE-strlen(dp->strnew[1]));
1222 			dp->strpta[1] = dp->strnew[1];
1223 			dp->strptb[1] = dp->strpta[1];
1224 		} else if (dp->hiv) {
1225 			dp->strpta[0] = (char *) HIV_STRING;
1226 			dp->strptb[0] = dp->strpta[0];
1227 			convert(HIV_TIME_START + (HIV_MIN / 60.0) * timeNow, dp->strnew[1]);
1228 			(void) strncat(dp->strnew[1], CASES_STRING, STRSIZE-strlen(dp->strnew[1]));
1229 			dp->strpta[1] = dp->strnew[1];
1230 			dp->strptb[1] = dp->strpta[1];
1231 		} else if (dp->lab) {
1232 			dp->strpta[0] = (char *) LAB_STRING;
1233 			dp->strptb[0] = dp->strpta[0];
1234 			convert((LAB_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)),
1235 				dp->strnew[1]);
1236 			(void) strncat(dp->strnew[1], YEAR_STRING, STRSIZE-strlen(dp->strnew[1]));
1237 			dp->strpta[1] = dp->strnew[1];
1238 			dp->strptb[1] = dp->strpta[1];
1239 		} else if (dp->veg) {
1240 			dp->strpta[0] = (char *) VEG_STRING;
1241 			dp->strptb[0] = dp->strpta[0];
1242 			convert((VEG_MIN / 60.0) * (timeNow - timeAtLastNewYear(timeNow)),
1243 				dp->strnew[1]);
1244 			(void) strncat(dp->strnew[1], YEAR_STRING, STRSIZE-strlen(dp->strnew[1]));
1245 			dp->strpta[1] = dp->strnew[1];
1246 		} else if (dp->y2k) {
1247 			if (Y2K_TIME_START >= timeLocal)
1248 				dp->strpta[0] = (char *) Y2K_STRING;
1249 			else
1250 				dp->strpta[0] = (char *) POST_Y2K_STRING;
1251 			dp->strptb[0] = dp->strpta[0];
1252 			dayhrminsec(Y2K_TIME_START - timeLocal, dp->tzoffset, dp->strnew[1]);
1253 			dp->strpta[1] = dp->strnew[1];
1254 		} else if (dp->millennium) {
1255 			if (Y2001_TIME_START >= timeLocal)
1256 				dp->strpta[0] = (char *) Y2001_STRING;
1257 			else
1258 				dp->strpta[0] = (char *) POST_Y2001_STRING;
1259 			dp->strptb[0] = dp->strpta[0];
1260 			dayhrminsec(Y2001_TIME_START - timeLocal, dp->tzoffset, dp->strnew[1]);
1261 			dp->strpta[1] = dp->strnew[1];
1262 		} else if (dp->mayan) {
1263 			if (MAYAN_TIME_START >= timeLocal)
1264 				dp->strpta[0] = (char *) MAYAN_STRING;
1265 			else
1266 				dp->strpta[0] = (char *) POST_MAYAN_STRING;
1267 			dp->strptb[0] = dp->strpta[0];
1268 			dayhrminsec(MAYAN_TIME_START - timeLocal, dp->tzoffset, dp->strnew[1]);
1269 			dp->strpta[1] = dp->strnew[1];
1270 		} else {
1271 			struct tm *t = localtime(&timeLocal);
1272 
1273 			if (dp->time24)
1274 			  (void) strftime(dp->strnew[0], STRSIZE, "%H:%M:%S", t);
1275 			else
1276 			  (void) strftime(dp->strnew[0], STRSIZE, "%I:%M:%S %p", t);
1277 			dp->hour = t->tm_hour;
1278 			(void) strftime(dp->strnew[1], STRSIZE, "%a %b %d %Y", t);
1279 
1280 			dp->strpta[0] = dp->strnew[0];
1281 			dp->strptb[0] = dp->strold[0];
1282 			dp->strpta[1] = dp->strnew[1];
1283 			dp->strptb[1] = dp->strold[1];
1284 		}
1285 		dp->text_height = getFontHeight(mode_font);
1286 		j = 0;
1287 		for (i = 0; i < dp->lines; i++) {
1288 			if (dp->strpta[i] && *(dp->strpta[i]))
1289 				dp->textWidth[i] = getTextWidth(dp->strpta[i]);
1290 			if (dp->textWidth[i] > dp->textWidth[j]) {
1291 				j = i;
1292 			}
1293 		}
1294 		dp->text_width = dp->textWidth[j];
1295 		for (i = 0; i < dp->lines; i++) {
1296 			dp->textStart[i] = (dp->text_width -
1297 				dp->textWidth[i]) / 2;
1298 		}
1299 		dp->maxy = dp->height - (dp->lines - 1) * dp->text_height -
1300 			dp->text_descent;
1301 		if (dp->maxy - dp->text_ascent == 0)
1302 			dp->clocky = dp->text_ascent;
1303 		else if (dp->maxy - dp->text_ascent < 0)
1304 			dp->clocky = -NRAND(dp->text_ascent - dp->maxy) +
1305 				dp->text_ascent;
1306 		else
1307 			dp->clocky = NRAND(dp->maxy - dp->text_ascent) +
1308 				dp->text_ascent;
1309 	}
1310 	dp->maxx = dp->width - dp->text_width;
1311 	if (dp->maxx == 0)
1312 		dp->clockx = dp->textStart[0];
1313 	else if (dp->maxx < 0)
1314 		dp->clockx = -NRAND(-dp->maxx) + dp->textStart[0];
1315 	else
1316 		dp->clockx = NRAND(dp->maxx) + dp->textStart[0];
1317 
1318 	if (MI_NPIXELS(mi) > 2)
1319 		dp->color = NRAND(MI_NPIXELS(mi));
1320 
1321 	/* don't want any exposure events from XCopyPlane */
1322 	XSetGraphicsExposures(display, MI_GC(mi), False);
1323 }
1324 
1325 ENTRYPOINT void
draw_dclock(ModeInfo * mi)1326 draw_dclock(ModeInfo * mi)
1327 {
1328 	dclockstruct *dp;
1329 
1330 	if (dclocks == NULL)
1331 		return;
1332 	dp = &dclocks[MI_SCREEN(mi)];
1333 	if (mode_font == None)
1334 		return;
1335 
1336 	MI_IS_DRAWN(mi) = True;
1337 	drawDclock(mi);
1338 	if (MI_NPIXELS(mi) > 2) {
1339 		if (++dp->color >= MI_NPIXELS(mi))
1340 			dp->color = 0;
1341 	}
1342 }
1343 
1344 #ifndef STANDALONE
1345 ENTRYPOINT void
refresh_dclock(ModeInfo * mi)1346 refresh_dclock(ModeInfo * mi)
1347 {
1348 	MI_CLEARWINDOW(mi);
1349 }
1350 #endif
1351 
1352 XSCREENSAVER_MODULE ("Dclock", dclock)
1353 
1354 #endif /* MODE_dclock */
1355