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