wmtime - increase version number to 1.1
[dockapps.git] / wmtime / wmtime / wmtime.c
blobd5cc8b2a07e691ee15bfca8f42d20f28cfa5c146
1 /*
2 Code based on wmppp/wmifs
4 [Orig WMMON comments]
6 This code was mainly put together by looking at the
7 following programs:
9 asclock
10 A neat piece of equip, used to display the date
11 and time on the screen.
12 Comes with every AfterStep installation.
14 Source used:
15 How do I create a not so solid window?
16 How do I open a window?
17 How do I use pixmaps?
19 ------------------------------------------------------------
21 Author: Martijn Pieterse (pieterse@xs4all.nl)
23 This program is distributed under the GPL license.
24 (as were asclock and pppstats)
26 ----
27 Changes:
28 ----
29 15/07/2008 (Paul Harris, harris.pc@gmail.com)
30 * Minor changes to correct build warnings
31 09/10/2003 (Simon Law, sfllaw@debian.org)
32 * Add -geometry support
33 * Add -noseconds support
34 * Make the digital clock fill the space provided
35 * Eliminated exploitable static buffers
36 17/05/1998 (Antoine Nulle, warp@xs4all.nl)
37 * Updated version number and some other minor stuff
38 16/05/1998 (Antoine Nulle, warp@xs4all.nl)
39 * Added Locale support, based on original diff supplied
40 by Alen Salamun (snowman@hal9000.medinet.si)
41 04/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
42 * Moved the hands one pixel down.
43 * Removed the RedrawWindow out of the main loop
44 02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
45 * Removed a lot of code that was in the wmgeneral dir.
46 02/05/1998 (Antoine Nulle, warp@xs4all.nl)
47 * Updated master-xpm, hour dots where a bit 'off'
48 30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
49 * Added anti-aliased hands
50 23/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
51 * Changed the hand lengths.. again! ;)
52 * Zombies were created, so added wait code
53 21/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
54 * Added digital/analog switching support
55 18/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
56 * Started this project.
57 * Copied the source from wmmon.
60 #define _GNU_SOURCE
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <time.h>
64 #include <string.h>
65 #include <fcntl.h>
66 #include <unistd.h>
67 #include <math.h>
68 #include <locale.h>
69 #include <langinfo.h>
70 #include <iconv.h>
71 #include <ctype.h>
73 #include <sys/wait.h>
74 #include <sys/param.h>
75 #include <sys/types.h>
77 #include <X11/Xlib.h>
78 #include <X11/xpm.h>
79 #include <X11/extensions/shape.h>
81 #include "../wmgeneral/wmgeneral.h"
82 #include "../wmgeneral/misc.h"
84 #include "wmtime-master.xpm"
85 #include "wmtime-mask.xbm"
87 /***********/
88 /* Defines */
89 /***********/
91 const char* default_left_action = NULL;
92 const char* default_middle_action = NULL;
93 const char* default_right_action = NULL;
95 #define WMMON_VERSION "1.1"
97 /********************/
98 /* Global Variables */
99 /********************/
101 int digital = 0;
102 int noseconds = 0;
103 char day_of_week[7][3] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
104 char mon_of_year[12][4] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
106 /* functions */
107 void usage(char *);
108 void printversion(void);
110 void wmtime_routine(int, char **);
111 void get_lang();
113 int main(int argc, char *argv[]) {
115 int i;
116 char *name = argv[0];
118 for (i=1; i<argc; i++) {
119 char *arg = argv[i];
121 if (*arg=='-') {
122 switch (arg[1]) {
123 case 'd' :
124 if (strcmp(arg+1, "display")
125 && strcmp(arg+1, "digital") && strcmp(arg+1, "d")) {
126 usage(name);
127 return 1;
129 if (!strcmp(arg+1, "digital") || !(strcmp(arg+1, "d")))
130 digital = 1;
131 break;
132 case 'g' :
133 if (strcmp(arg+1, "geometry")) {
134 usage(name);
135 return 1;
137 break;
138 case 'n' :
139 if (strcmp(arg+1, "noseconds") && strcmp(arg+1, "n")) {
140 usage(name);
141 return 1;
142 } else {
143 noseconds = 1;
145 break;
146 case 'v' :
147 printversion();
148 return 0;
149 default:
150 usage(name);
151 return 1;
156 if (setlocale(LC_ALL, "") != NULL)
157 get_lang();
159 wmtime_routine(argc, argv);
160 return 0;
163 /************/
164 /* get_lang */
165 /************/
166 void get_lang(void)
168 char langbuf[10], outbuf[10];
169 char *inp, *outp;
170 iconv_t icd;
171 int i, ret;
172 size_t insize, outsize;
174 icd = iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET));
175 if (icd < 0)
176 return;
178 for (i = 0; i < 7; i++) {
179 strncpy(langbuf, nl_langinfo(ABDAY_1 + i), 10);
180 insize = outsize = 10;
181 inp = langbuf;
182 outp = outbuf;
183 do {
184 ret = iconv(icd, &inp, &insize, &outp, &outsize);
185 } while (outsize > 0 && ret > 0);
186 if (strstr(outbuf,"?") != NULL) return;
187 for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 2;
188 outp++, outsize++)
189 day_of_week[i][outsize] = toupper(*outp);
191 for (i = 0; i < 12; i++) {
192 strncpy(langbuf, nl_langinfo(ABMON_1 + i), 10);
193 insize = outsize = 10;
194 inp = langbuf;
195 outp = outbuf;
196 do {
197 ret = iconv(icd, &inp, &insize, &outp, &outsize);
198 } while (outsize > 0 && ret > 0);
199 if (strstr(outbuf,"?") != NULL) return;
200 for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 3;
201 outp++, outsize++)
202 mon_of_year[i][outsize] = toupper(*outp);
205 iconv_close(icd);
208 /*******************************************************************************\
209 |* wmtime_routine *|
210 \*******************************************************************************/
212 char *left_action = NULL;
213 char *right_action = NULL;
214 char *middle_action = NULL;
216 void DrawTime(int, int, int);
217 void DrawWijzer(int, int, int);
218 void DrawDate(int, int, int);
220 void wmtime_routine(int argc, char **argv) {
222 rckeys wmtime_keys[] = {
223 { "left", &left_action },
224 { "right", &right_action },
225 { "middle", &middle_action },
226 { NULL, NULL }
229 int i;
230 XEvent Event;
231 int but_stat = -1;
233 struct tm *time_struct;
234 struct tm old_time_struct;
236 long starttime;
237 long curtime;
238 long nexttime;
240 char *conffile = NULL;
242 /* Scan through ~/.wmtimerc for the mouse button actions. */
243 if (default_left_action) left_action = strdup(default_left_action);
244 if (default_middle_action) middle_action = strdup(default_middle_action);
245 if (default_right_action) right_action = strdup(default_right_action);
247 /* Scan through the .rc files */
248 if (asprintf(&conffile, "/etc/wmtimerc") >= 0) {
249 parse_rcfile(conffile, wmtime_keys);
250 free(conffile);
253 if (asprintf(&conffile, "%s/.wmtimerc", getenv("HOME")) >= 0) {
254 parse_rcfile(conffile, wmtime_keys);
255 free(conffile);
258 if (asprintf(&conffile, "/etc/wmtimerc.fixed") >= 0) {
259 parse_rcfile(conffile, wmtime_keys);
260 free(conffile);
263 openXwindow(argc, argv, wmtime_master_xpm, wmtime_mask_bits, 128, 64);
265 /* Mask out the right parts of the clock */
266 copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */
267 copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */
268 copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */
269 setMaskXY(0, 0);
271 /* add mouse region */
272 AddMouseRegion(0, 5, 48, 58, 60);
273 AddMouseRegion(1, 5, 5, 58, 46);
275 starttime = time(0);
276 nexttime = starttime + 1;
278 curtime = time(0);
279 time_struct = localtime(&curtime);
281 while (1) {
282 curtime = time(0);
284 waitpid(0, NULL, WNOHANG);
286 old_time_struct = *time_struct;
287 time_struct = localtime(&curtime);
290 if (curtime >= starttime) {
291 if (!digital) {
292 /* Now to update the seconds */
294 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
296 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
298 } else {
300 DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
302 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
304 RedrawWindow();
308 while (XPending(display)) {
309 XNextEvent(display, &Event);
310 switch (Event.type) {
311 case Expose:
312 RedrawWindow();
313 break;
314 case DestroyNotify:
315 XCloseDisplay(display);
316 exit(0);
317 break;
318 case ButtonPress:
319 but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
320 break;
321 case ButtonRelease:
322 i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
323 if (but_stat == i && but_stat >= 0) {
324 switch (but_stat) {
325 case 0:
326 digital = 1-digital;
328 if (digital) {
329 copyXPMArea(64, 98, 64, 64, 0, 0);
330 DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
331 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
332 } else {
333 copyXPMArea(0, 98, 64, 64, 0, 0);
334 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
335 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
337 RedrawWindow();
338 break;
339 case 1:
340 switch (Event.xbutton.button) {
341 case 1:
342 if (left_action)
343 execCommand(left_action);
344 break;
345 case 2:
346 if (middle_action)
347 execCommand(middle_action);
348 break;
349 case 3:
350 if (right_action)
351 execCommand(right_action);
352 break;
356 break;
360 /* Sleep 0.3 seconds */
361 usleep(300000L);
365 /*******************************************************************************\
366 |* DrawTime *|
367 \*******************************************************************************/
369 void DrawTime(int hr, int min, int sec) {
370 const int time_size = 16;
371 char time[time_size];
372 char *p = time;
373 int i,j,k=6;
374 int numfields;
376 /* 7x13 */
378 if (noseconds) {
379 snprintf(time, time_size, "%02d:%02d ", hr, min);
380 numfields = 2;
382 else {
383 snprintf(time, time_size, "%02d:%02d:%02d ", hr, min, sec);
384 numfields = 3;
387 for (i=0; i < numfields; i++) {
388 for (j=0; j<2; j++) {
389 copyXPMArea((*p-'0')*7 + 1, 84, 8, 13, k, 18);
390 k += 7;
391 p++;
393 if (*p == ':') {
394 copyXPMArea(71, 84, 5, 13, k, 18);
395 k += 4;
396 p++;
401 /*******************************************************************************\
402 |* DrawDate *|
403 \*******************************************************************************/
405 void DrawDate(int wkday, int dom, int month) {
406 const int date_size = 16;
407 char date[date_size];
408 char *p = date;
409 int i,k;
411 /* 7x13 */
413 snprintf(date, date_size,
414 "%.2s%02d%.3s ", day_of_week[wkday], dom, mon_of_year[month]);
416 k = 5;
417 for (i=0; i<2; i++) {
418 if (*p < 'A')
419 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
420 else
421 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
422 k += 6;
423 p++;
425 k = 23;
426 for (i=0; i<2; i++) {
427 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
428 k += 6;
429 p++;
431 copyXPMArea(61, 64, 4, 9, k, 49);
432 k += 4;
433 for (i=0; i<3; i++) {
434 if (*p < 'A')
435 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
436 else
437 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
438 k += 6;
439 p++;
443 /*******************************************************************************\
444 |* DrawWijzer *|
445 \*******************************************************************************/
447 void DrawWijzer(int hr, int min, int sec) {
449 double psi;
450 int dx,dy;
451 int x,y;
452 int ddx,ddy;
453 int adder;
454 int k;
456 int i;
458 hr %= 12;
460 copyXPMArea(5+64, 5, 54, 40, 5, 5);
462 /**********************************************************************/
463 psi = hr * (M_PI / 6.0);
464 psi += min * (M_PI / 360);
466 dx = floor(sin(psi) * 22 * 0.7 + 0.5);
467 dy = floor(-cos(psi) * 16 * 0.7 + 0.5);
469 // dx, dy is het punt waar we naar toe moeten.
470 // Zoek alle punten die ECHT op de lijn liggen:
472 ddx = 1;
473 ddy = 1;
474 if (dx < 0) ddx = -1;
475 if (dy < 0) ddy = -1;
477 x = 0;
478 y = 0;
480 if (abs(dx) > abs(dy)) {
481 if (dy != 0)
482 adder = abs(dx) / 2;
483 else
484 adder = 0;
485 for (i=0; i<abs(dx); i++) {
486 // laat de kleur afhangen van de adder.
487 // adder loopt van abs(dx) tot 0
489 k = 12 - adder / (abs(dx) / 12.0);
490 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
492 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
494 k = 12-k;
495 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
498 x += ddx;
500 adder -= abs(dy);
501 if (adder < 0) {
502 adder += abs(dx);
503 y += ddy;
506 } else {
507 if (dx != 0)
508 adder = abs(dy) / 2;
509 else
510 adder = 0;
511 for (i=0; i<abs(dy); i++) {
512 k = 12 - adder / (abs(dy) / 12.0);
513 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
515 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
517 k = 12-k;
518 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
520 y += ddy;
522 adder -= abs(dx);
523 if (adder < 0) {
524 adder += abs(dy);
525 x += ddx;
529 /**********************************************************************/
530 psi = min * (M_PI / 30.0);
531 psi += sec * (M_PI / 1800);
533 dx = floor(sin(psi) * 22 * 0.55 + 0.5);
534 dy = floor(-cos(psi) * 16 * 0.55 + 0.5);
536 // dx, dy is het punt waar we naar toe moeten.
537 // Zoek alle punten die ECHT op de lijn liggen:
539 dx += dx;
540 dy += dy;
542 ddx = 1;
543 ddy = 1;
544 if (dx < 0) ddx = -1;
545 if (dy < 0) ddy = -1;
547 x = 0;
548 y = 0;
550 if (abs(dx) > abs(dy)) {
551 if (dy != 0)
552 adder = abs(dx) / 2;
553 else
554 adder = 0;
555 for (i=0; i<abs(dx); i++) {
556 // laat de kleur afhangen van de adder.
557 // adder loopt van abs(dx) tot 0
559 k = 12 - adder / (abs(dx) / 12.0);
560 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
562 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
564 k = 12-k;
565 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
568 x += ddx;
570 adder -= abs(dy);
571 if (adder < 0) {
572 adder += abs(dx);
573 y += ddy;
576 } else {
577 if (dx != 0)
578 adder = abs(dy) / 2;
579 else
580 adder = 0;
581 for (i=0; i<abs(dy); i++) {
582 k = 12 - adder / (abs(dy) / 12.0);
583 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
585 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
587 k = 12-k;
588 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
590 y += ddy;
592 adder -= abs(dx);
593 if (adder < 0) {
594 adder += abs(dy);
595 x += ddx;
599 /**********************************************************************/
600 if (noseconds)
601 return; /* Skip drawing the seconds. */
603 psi = sec * (M_PI / 30.0);
605 dx = floor(sin(psi) * 22 * 0.9 + 0.5);
606 dy = floor(-cos(psi) * 16 * 0.9 + 0.5);
608 // dx, dy is het punt waar we naar toe moeten.
609 // Zoek alle punten die ECHT op de lijn liggen:
611 ddx = 1;
612 ddy = 1;
613 if (dx < 0) ddx = -1;
614 if (dy < 0) ddy = -1;
616 if (dx == 0) ddx = 0;
617 if (dy == 0) ddy = 0;
619 x = 0;
620 y = 0;
623 if (abs(dx) > abs(dy)) {
624 if (dy != 0)
625 adder = abs(dx) / 2;
626 else
627 adder = 0;
628 for (i=0; i<abs(dx); i++) {
629 // laat de kleur afhangen van de adder.
630 // adder loopt van abs(dx) tot 0
632 k = 12 - adder / (abs(dx) / 12.0);
633 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24 - ddy);
635 k = 12-k;
636 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
639 x += ddx;
641 adder -= abs(dy);
642 if (adder < 0) {
643 adder += abs(dx);
644 y += ddy;
647 } else {
648 if (dx != 0)
649 adder = abs(dy) / 2;
650 else
651 adder = 0;
652 for (i=0; i<abs(dy); i++) {
653 k = 12 - adder / (abs(dy) / 12.0);
654 copyXPMArea(79+k, 70, 1, 1, x + 31 - ddx, y + 24);
656 k = 12-k;
657 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
659 y += ddy;
661 adder -= abs(dx);
662 if (adder < 0) {
663 adder += abs(dy);
664 x += ddx;
670 /*******************************************************************************\
671 |* usage *|
672 \*******************************************************************************/
674 void usage(char *name) {
675 printf("Usage: %s [OPTION]...\n", name);
676 printf("WindowMaker dockapp that displays the time and date.\n");
677 printf("\n");
678 printf(" -d, -digital display the digital clock\n");
679 printf(" -display DISPLAY contact the DISPLAY X server\n");
680 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
681 printf(" -n, -noseconds disables the second hand\n");
682 printf(" -h display this help and exit\n");
683 printf(" -v output version information and exit\n");
686 /*******************************************************************************\
687 |* printversion *|
688 \*******************************************************************************/
690 void printversion(void) {
691 printf("WMTime version %s\n", WMMON_VERSION);
694 /* vim: sw=4 ts=4 columns=82