wmgeneral: Fix segfault if newline encountered in parse_rcfile.
[dockapps.git] / wmtime / wmtime.c
blobef12a4d393a5d7017fa5e7d340d80d4a96eef461
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 WMTIME_VERSION "1.2"
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];
117 char locale[256];
119 locale[0] = 0;
121 for (i=1; i<argc; i++) {
122 char *arg = argv[i];
124 if (*arg=='-') {
125 switch (arg[1]) {
126 case 'd' :
127 if (strcmp(arg+1, "display")
128 && strcmp(arg+1, "digital") && strcmp(arg+1, "d")) {
129 usage(name);
130 return 1;
132 if (!strcmp(arg+1, "digital") || !(strcmp(arg+1, "d")))
133 digital = 1;
134 break;
135 case 'g' :
136 if (strcmp(arg+1, "geometry")) {
137 usage(name);
138 return 1;
140 break;
141 case 'n' :
142 if (strcmp(arg+1, "noseconds") && strcmp(arg+1, "n")) {
143 usage(name);
144 return 1;
145 } else {
146 noseconds = 1;
148 break;
149 case 'v' :
150 printversion();
151 return 0;
152 case 'l':
153 if (argc > i+1) {
154 strcpy(locale, argv[i+1]);
155 i++;
157 break;
158 default:
159 usage(name);
160 return 1;
165 if (setlocale(LC_ALL, locale) == NULL)
166 fprintf(stderr,
167 "warning: locale '%s' not recognized; defaulting to '%s'.",
168 locale, setlocale(LC_ALL, NULL));
169 get_lang();
171 wmtime_routine(argc, argv);
172 return 0;
175 /************/
176 /* get_lang */
177 /************/
178 void get_lang(void)
180 char langbuf[10], outbuf[10];
181 char *inp, *outp;
182 iconv_t icd;
183 int i, ret;
184 size_t insize, outsize;
186 icd = iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET));
187 if (icd < 0)
188 return;
190 for (i = 0; i < 7; i++) {
191 strncpy(langbuf, nl_langinfo(ABDAY_1 + i), 10);
192 insize = outsize = 10;
193 inp = langbuf;
194 outp = outbuf;
195 do {
196 ret = iconv(icd, &inp, &insize, &outp, &outsize);
197 } while (outsize > 0 && ret > 0);
198 if (strstr(outbuf,"?") != NULL) return;
199 for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 2;
200 outp++, outsize++)
201 day_of_week[i][outsize] = toupper(*outp);
203 for (i = 0; i < 12; i++) {
204 strncpy(langbuf, nl_langinfo(ABMON_1 + i), 10);
205 insize = outsize = 10;
206 inp = langbuf;
207 outp = outbuf;
208 do {
209 ret = iconv(icd, &inp, &insize, &outp, &outsize);
210 } while (outsize > 0 && ret > 0);
211 if (strstr(outbuf,"?") != NULL) return;
212 for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 3;
213 outp++, outsize++)
214 mon_of_year[i][outsize] = toupper(*outp);
217 iconv_close(icd);
220 /*******************************************************************************\
221 |* wmtime_routine *|
222 \*******************************************************************************/
224 char *left_action = NULL;
225 char *right_action = NULL;
226 char *middle_action = NULL;
228 void DrawTime(int, int, int);
229 void DrawWijzer(int, int, int);
230 void DrawDate(int, int, int);
232 void wmtime_routine(int argc, char **argv) {
234 rckeys wmtime_keys[] = {
235 { "left", &left_action },
236 { "right", &right_action },
237 { "middle", &middle_action },
238 { NULL, NULL }
241 int i;
242 XEvent Event;
243 int but_stat = -1;
245 struct tm *time_struct;
247 long starttime;
248 long curtime;
250 char *conffile = NULL;
252 /* Scan through ~/.wmtimerc for the mouse button actions. */
253 if (default_left_action) left_action = strdup(default_left_action);
254 if (default_middle_action) middle_action = strdup(default_middle_action);
255 if (default_right_action) right_action = strdup(default_right_action);
257 /* Scan through the .rc files */
258 if (asprintf(&conffile, "/etc/wmtimerc") >= 0) {
259 parse_rcfile(conffile, wmtime_keys);
260 free(conffile);
263 if (asprintf(&conffile, "%s/.wmtimerc", getenv("HOME")) >= 0) {
264 parse_rcfile(conffile, wmtime_keys);
265 free(conffile);
268 if (asprintf(&conffile, "/etc/wmtimerc.fixed") >= 0) {
269 parse_rcfile(conffile, wmtime_keys);
270 free(conffile);
273 openXwindow(argc, argv, wmtime_master_xpm, wmtime_mask_bits, 128, 64);
275 /* Mask out the right parts of the clock */
276 copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */
277 copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */
278 copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */
279 setMaskXY(0, 0);
281 /* add mouse region */
282 AddMouseRegion(0, 5, 48, 58, 60);
283 AddMouseRegion(1, 5, 5, 58, 46);
285 starttime = time(0);
287 curtime = time(0);
288 time_struct = localtime(&curtime);
290 while (1) {
291 curtime = time(0);
293 waitpid(0, NULL, WNOHANG);
295 time_struct = localtime(&curtime);
298 if (curtime >= starttime) {
299 if (!digital) {
300 /* Now to update the seconds */
302 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
304 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
306 } else {
308 DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
310 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
312 RedrawWindow();
316 while (XPending(display)) {
317 XNextEvent(display, &Event);
318 switch (Event.type) {
319 case Expose:
320 RedrawWindow();
321 break;
322 case DestroyNotify:
323 XCloseDisplay(display);
324 exit(0);
325 break;
326 case ButtonPress:
327 but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
328 break;
329 case ButtonRelease:
330 i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
331 if (but_stat == i && but_stat >= 0) {
332 switch (but_stat) {
333 case 0:
334 digital = 1-digital;
336 if (digital) {
337 copyXPMArea(64, 98, 64, 64, 0, 0);
338 DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
339 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
340 } else {
341 copyXPMArea(0, 98, 64, 64, 0, 0);
342 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
343 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
345 RedrawWindow();
346 break;
347 case 1:
348 switch (Event.xbutton.button) {
349 case 1:
350 if (left_action)
351 execCommand(left_action);
352 break;
353 case 2:
354 if (middle_action)
355 execCommand(middle_action);
356 break;
357 case 3:
358 if (right_action)
359 execCommand(right_action);
360 break;
364 break;
368 /* Sleep 0.3 seconds */
369 usleep(300000L);
373 /*******************************************************************************\
374 |* DrawTime *|
375 \*******************************************************************************/
377 void DrawTime(int hr, int min, int sec) {
378 const int time_size = 16;
379 char time[time_size];
380 char *p = time;
381 int i,j,k=6;
382 int numfields;
384 /* 7x13 */
386 if (noseconds) {
387 snprintf(time, time_size, "%02d:%02d ", hr, min);
388 numfields = 2;
390 else {
391 snprintf(time, time_size, "%02d:%02d:%02d ", hr, min, sec);
392 numfields = 3;
395 for (i=0; i < numfields; i++) {
396 for (j=0; j<2; j++) {
397 copyXPMArea((*p-'0')*7 + 1, 84, 8, 13, k, 18);
398 k += 7;
399 p++;
401 if (*p == ':') {
402 copyXPMArea(71, 84, 5, 13, k, 18);
403 k += 4;
404 p++;
409 /*******************************************************************************\
410 |* DrawDate *|
411 \*******************************************************************************/
413 void DrawDate(int wkday, int dom, int month) {
414 const int date_size = 16;
415 char date[date_size];
416 char *p = date;
417 int i,k;
419 /* 7x13 */
421 snprintf(date, date_size,
422 "%.2s%02d%.3s ", day_of_week[wkday], dom, mon_of_year[month]);
424 k = 5;
425 for (i=0; i<2; i++) {
426 if (*p < 'A')
427 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
428 else
429 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
430 k += 6;
431 p++;
433 k = 23;
434 for (i=0; i<2; i++) {
435 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
436 k += 6;
437 p++;
439 copyXPMArea(61, 64, 4, 9, k, 49);
440 k += 4;
441 for (i=0; i<3; i++) {
442 if (*p < 'A')
443 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
444 else
445 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
446 k += 6;
447 p++;
451 /*******************************************************************************\
452 |* DrawWijzer *|
453 \*******************************************************************************/
455 void DrawWijzer(int hr, int min, int sec) {
457 double psi;
458 int dx,dy;
459 int x,y;
460 int ddx,ddy;
461 int adder;
462 int k;
464 int i;
466 hr %= 12;
468 copyXPMArea(5+64, 5, 54, 40, 5, 5);
470 /**********************************************************************/
471 psi = hr * (M_PI / 6.0);
472 psi += min * (M_PI / 360);
474 dx = floor(sin(psi) * 22 * 0.7 + 0.5);
475 dy = floor(-cos(psi) * 16 * 0.7 + 0.5);
477 // dx, dy is het punt waar we naar toe moeten.
478 // Zoek alle punten die ECHT op de lijn liggen:
480 ddx = 1;
481 ddy = 1;
482 if (dx < 0) ddx = -1;
483 if (dy < 0) ddy = -1;
485 x = 0;
486 y = 0;
488 if (abs(dx) > abs(dy)) {
489 if (dy != 0)
490 adder = abs(dx) / 2;
491 else
492 adder = 0;
493 for (i=0; i<abs(dx); i++) {
494 // laat de kleur afhangen van de adder.
495 // adder loopt van abs(dx) tot 0
497 k = 12 - adder / (abs(dx) / 12.0);
498 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
500 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
502 k = 12-k;
503 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
506 x += ddx;
508 adder -= abs(dy);
509 if (adder < 0) {
510 adder += abs(dx);
511 y += ddy;
514 } else {
515 if (dx != 0)
516 adder = abs(dy) / 2;
517 else
518 adder = 0;
519 for (i=0; i<abs(dy); i++) {
520 k = 12 - adder / (abs(dy) / 12.0);
521 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
523 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
525 k = 12-k;
526 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
528 y += ddy;
530 adder -= abs(dx);
531 if (adder < 0) {
532 adder += abs(dy);
533 x += ddx;
537 /**********************************************************************/
538 psi = min * (M_PI / 30.0);
539 psi += sec * (M_PI / 1800);
541 dx = floor(sin(psi) * 22 * 0.55 + 0.5);
542 dy = floor(-cos(psi) * 16 * 0.55 + 0.5);
544 // dx, dy is het punt waar we naar toe moeten.
545 // Zoek alle punten die ECHT op de lijn liggen:
547 dx += dx;
548 dy += dy;
550 ddx = 1;
551 ddy = 1;
552 if (dx < 0) ddx = -1;
553 if (dy < 0) ddy = -1;
555 x = 0;
556 y = 0;
558 if (abs(dx) > abs(dy)) {
559 if (dy != 0)
560 adder = abs(dx) / 2;
561 else
562 adder = 0;
563 for (i=0; i<abs(dx); i++) {
564 // laat de kleur afhangen van de adder.
565 // adder loopt van abs(dx) tot 0
567 k = 12 - adder / (abs(dx) / 12.0);
568 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
570 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
572 k = 12-k;
573 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
576 x += ddx;
578 adder -= abs(dy);
579 if (adder < 0) {
580 adder += abs(dx);
581 y += ddy;
584 } else {
585 if (dx != 0)
586 adder = abs(dy) / 2;
587 else
588 adder = 0;
589 for (i=0; i<abs(dy); i++) {
590 k = 12 - adder / (abs(dy) / 12.0);
591 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
593 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
595 k = 12-k;
596 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
598 y += ddy;
600 adder -= abs(dx);
601 if (adder < 0) {
602 adder += abs(dy);
603 x += ddx;
607 /**********************************************************************/
608 if (noseconds)
609 return; /* Skip drawing the seconds. */
611 psi = sec * (M_PI / 30.0);
613 dx = floor(sin(psi) * 22 * 0.9 + 0.5);
614 dy = floor(-cos(psi) * 16 * 0.9 + 0.5);
616 // dx, dy is het punt waar we naar toe moeten.
617 // Zoek alle punten die ECHT op de lijn liggen:
619 ddx = 1;
620 ddy = 1;
621 if (dx < 0) ddx = -1;
622 if (dy < 0) ddy = -1;
624 if (dx == 0) ddx = 0;
625 if (dy == 0) ddy = 0;
627 x = 0;
628 y = 0;
631 if (abs(dx) > abs(dy)) {
632 if (dy != 0)
633 adder = abs(dx) / 2;
634 else
635 adder = 0;
636 for (i=0; i<abs(dx); i++) {
637 // laat de kleur afhangen van de adder.
638 // adder loopt van abs(dx) tot 0
640 k = 12 - adder / (abs(dx) / 12.0);
641 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24 - ddy);
643 k = 12-k;
644 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
647 x += ddx;
649 adder -= abs(dy);
650 if (adder < 0) {
651 adder += abs(dx);
652 y += ddy;
655 } else {
656 if (dx != 0)
657 adder = abs(dy) / 2;
658 else
659 adder = 0;
660 for (i=0; i<abs(dy); i++) {
661 k = 12 - adder / (abs(dy) / 12.0);
662 copyXPMArea(79+k, 70, 1, 1, x + 31 - ddx, y + 24);
664 k = 12-k;
665 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
667 y += ddy;
669 adder -= abs(dx);
670 if (adder < 0) {
671 adder += abs(dy);
672 x += ddx;
678 /*******************************************************************************\
679 |* usage *|
680 \*******************************************************************************/
682 void usage(char *name) {
683 printf("Usage: %s [OPTION]...\n", name);
684 printf("WindowMaker dockapp that displays the time and date.\n");
685 printf("\n");
686 printf(" -d, -digital display the digital clock\n");
687 printf(" -display DISPLAY contact the DISPLAY X server\n");
688 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
689 printf(" -n, -noseconds disables the second hand\n");
690 printf(" -l LOCALE set locale to LOCALE\n");
691 printf(" -h display this help and exit\n");
692 printf(" -v output version information and exit\n");
695 /*******************************************************************************\
696 |* printversion *|
697 \*******************************************************************************/
699 void printversion(void) {
700 printf("WMTime version %s\n", WMTIME_VERSION);
703 /* vim: sw=4 ts=4 columns=82