2dfed0cf6578d2b29b6447e0b10f92c30cdd40e6
[dockapps.git] / wmtime / wmtime / wmtime.c
blob2dfed0cf6578d2b29b6447e0b10f92c30cdd40e6
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>
69 #include <sys/wait.h>
70 #include <sys/param.h>
71 #include <sys/types.h>
73 #include <X11/Xlib.h>
74 #include <X11/xpm.h>
75 #include <X11/extensions/shape.h>
77 #include "../wmgeneral/wmgeneral.h"
78 #include "../wmgeneral/misc.h"
80 #include "wmtime-master.xpm"
81 #include "wmtime-mask.xbm"
83 /***********/
84 /* Defines */
85 /***********/
87 const char* default_left_action = NULL;
88 const char* default_middle_action = NULL;
89 const char* default_right_action = NULL;
91 #define WMMON_VERSION "1.0b2"
93 /********************/
94 /* Global Variables */
95 /********************/
97 int digital = 0;
98 int noseconds = 0;
99 char day_of_week[7][3] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
100 char mon_of_year[12][4] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
102 /* functions */
103 void usage(char *);
104 void printversion(void);
106 void wmtime_routine(int, char **);
107 void get_lang();
109 int main(int argc, char *argv[]) {
111 int i;
112 char *name = argv[0];
114 for (i=1; i<argc; i++) {
115 char *arg = argv[i];
117 if (*arg=='-') {
118 switch (arg[1]) {
119 case 'd' :
120 if (strcmp(arg+1, "display")
121 && strcmp(arg+1, "digital") && strcmp(arg+1, "d")) {
122 usage(name);
123 return 1;
125 if (!strcmp(arg+1, "digital") || !(strcmp(arg+1, "d")))
126 digital = 1;
127 break;
128 case 'g' :
129 if (strcmp(arg+1, "geometry")) {
130 usage(name);
131 return 1;
133 break;
134 case 'n' :
135 if (strcmp(arg+1, "noseconds") && strcmp(arg+1, "n")) {
136 usage(name);
137 return 1;
138 } else {
139 noseconds = 1;
141 break;
142 case 'v' :
143 printversion();
144 return 0;
145 default:
146 usage(name);
147 return 1;
151 get_lang();
152 wmtime_routine(argc, argv);
153 return 0;
156 /************/
157 /* get_lang */
158 /************/
159 void get_lang(){
160 FILE *fp;
161 int i;
162 const int line_size = 5;
163 char line[line_size];
165 fp=fopen("language","r");
166 if (fp) {
167 /* Grab the days of the week */
168 for (i=0;i<7;i++){
169 fgets(line, line_size, fp);
170 strncpy(day_of_week[i], line, 2);
172 /* Grab the names of the months */
173 for (i=0;i<12;i++){
174 fgets(line, line_size, fp);
175 strncpy(mon_of_year[i], line, 3);
177 fclose(fp);
181 /*******************************************************************************\
182 |* wmtime_routine *|
183 \*******************************************************************************/
185 char *left_action = NULL;
186 char *right_action = NULL;
187 char *middle_action = NULL;
189 void DrawTime(int, int, int);
190 void DrawWijzer(int, int, int);
191 void DrawDate(int, int, int);
193 void wmtime_routine(int argc, char **argv) {
195 rckeys wmtime_keys[] = {
196 { "left", &left_action },
197 { "right", &right_action },
198 { "middle", &middle_action },
199 { NULL, NULL }
202 int i;
203 XEvent Event;
204 int but_stat = -1;
206 struct tm *time_struct;
207 struct tm old_time_struct;
209 long starttime;
210 long curtime;
211 long nexttime;
213 char *conffile = NULL;
215 /* Scan through ~/.wmtimerc for the mouse button actions. */
216 if (default_left_action) left_action = strdup(default_left_action);
217 if (default_middle_action) middle_action = strdup(default_middle_action);
218 if (default_right_action) right_action = strdup(default_right_action);
220 /* Scan through the .rc files */
221 if (asprintf(&conffile, "/etc/wmtimerc") >= 0) {
222 parse_rcfile(conffile, wmtime_keys);
223 free(conffile);
226 if (asprintf(&conffile, "%s/.wmtimerc", getenv("HOME")) >= 0) {
227 parse_rcfile(conffile, wmtime_keys);
228 free(conffile);
231 if (asprintf(&conffile, "/etc/wmtimerc.fixed") >= 0) {
232 parse_rcfile(conffile, wmtime_keys);
233 free(conffile);
236 openXwindow(argc, argv, wmtime_master_xpm, wmtime_mask_bits, 128, 64);
238 /* Mask out the right parts of the clock */
239 copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */
240 copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */
241 copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */
242 setMaskXY(0, 0);
244 /* add mouse region */
245 AddMouseRegion(0, 5, 48, 58, 60);
246 AddMouseRegion(1, 5, 5, 58, 46);
248 starttime = time(0);
249 nexttime = starttime + 1;
251 curtime = time(0);
252 time_struct = localtime(&curtime);
254 while (1) {
255 curtime = time(0);
257 waitpid(0, NULL, WNOHANG);
259 old_time_struct = *time_struct;
260 time_struct = localtime(&curtime);
263 if (curtime >= starttime) {
264 if (!digital) {
265 /* Now to update the seconds */
267 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
269 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
271 } else {
273 DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
275 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
277 RedrawWindow();
281 while (XPending(display)) {
282 XNextEvent(display, &Event);
283 switch (Event.type) {
284 case Expose:
285 RedrawWindow();
286 break;
287 case DestroyNotify:
288 XCloseDisplay(display);
289 exit(0);
290 break;
291 case ButtonPress:
292 but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
293 break;
294 case ButtonRelease:
295 i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
296 if (but_stat == i && but_stat >= 0) {
297 switch (but_stat) {
298 case 0:
299 digital = 1-digital;
301 if (digital) {
302 copyXPMArea(64, 98, 64, 64, 0, 0);
303 DrawTime(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);
305 } else {
306 copyXPMArea(0, 98, 64, 64, 0, 0);
307 DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
308 DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon);
310 RedrawWindow();
311 break;
312 case 1:
313 switch (Event.xbutton.button) {
314 case 1:
315 if (left_action)
316 execCommand(left_action);
317 break;
318 case 2:
319 if (middle_action)
320 execCommand(middle_action);
321 break;
322 case 3:
323 if (right_action)
324 execCommand(right_action);
325 break;
329 break;
333 /* Sleep 0.3 seconds */
334 usleep(300000L);
338 /*******************************************************************************\
339 |* DrawTime *|
340 \*******************************************************************************/
342 void DrawTime(int hr, int min, int sec) {
343 const int time_size = 16;
344 char time[time_size];
345 char *p = time;
346 int i,j,k=6;
348 /* 7x13 */
350 if (noseconds) {
351 snprintf(time, time_size, "%02d:%02d ", hr, min);
353 else {
354 snprintf(time, time_size, "%02d:%02d:%02d ", hr, min, sec);
357 for (i=0; i < 3; i++) {
358 for (j=0; j<2; j++) {
359 copyXPMArea((*p-'0')*7 + 1, 84, 8, 13, k, 18);
360 k += 7;
361 p++;
363 if (*p == ':') {
364 copyXPMArea(71, 84, 5, 13, k, 18);
365 k += 4;
366 p++;
371 /*******************************************************************************\
372 |* DrawDate *|
373 \*******************************************************************************/
375 void DrawDate(int wkday, int dom, int month) {
376 const int date_size = 16;
377 char date[date_size];
378 char *p = date;
379 int i,k;
381 /* 7x13 */
383 snprintf(date, date_size,
384 "%.2s%02d%.3s ", day_of_week[wkday], dom, mon_of_year[month]);
386 k = 5;
387 for (i=0; i<2; i++) {
388 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
389 k += 6;
390 p++;
392 k = 23;
393 for (i=0; i<2; i++) {
394 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
395 k += 6;
396 p++;
398 copyXPMArea(61, 64, 4, 9, k, 49);
399 k += 4;
400 for (i=0; i<3; i++) {
401 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
402 k += 6;
403 p++;
407 /*******************************************************************************\
408 |* DrawWijzer *|
409 \*******************************************************************************/
411 void DrawWijzer(int hr, int min, int sec) {
413 double psi;
414 int dx,dy;
415 int x,y;
416 int ddx,ddy;
417 int adder;
418 int k;
420 int i;
422 hr %= 12;
424 copyXPMArea(5+64, 5, 54, 40, 5, 5);
426 /**********************************************************************/
427 psi = hr * (M_PI / 6.0);
428 psi += min * (M_PI / 360);
430 dx = floor(sin(psi) * 22 * 0.7 + 0.5);
431 dy = floor(-cos(psi) * 16 * 0.7 + 0.5);
433 // dx, dy is het punt waar we naar toe moeten.
434 // Zoek alle punten die ECHT op de lijn liggen:
436 ddx = 1;
437 ddy = 1;
438 if (dx < 0) ddx = -1;
439 if (dy < 0) ddy = -1;
441 x = 0;
442 y = 0;
444 if (abs(dx) > abs(dy)) {
445 if (dy != 0)
446 adder = abs(dx) / 2;
447 else
448 adder = 0;
449 for (i=0; i<abs(dx); i++) {
450 // laat de kleur afhangen van de adder.
451 // adder loopt van abs(dx) tot 0
453 k = 12 - adder / (abs(dx) / 12.0);
454 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
456 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
458 k = 12-k;
459 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
462 x += ddx;
464 adder -= abs(dy);
465 if (adder < 0) {
466 adder += abs(dx);
467 y += ddy;
470 } else {
471 if (dx != 0)
472 adder = abs(dy) / 2;
473 else
474 adder = 0;
475 for (i=0; i<abs(dy); i++) {
476 k = 12 - adder / (abs(dy) / 12.0);
477 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
479 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
481 k = 12-k;
482 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
484 y += ddy;
486 adder -= abs(dx);
487 if (adder < 0) {
488 adder += abs(dy);
489 x += ddx;
493 /**********************************************************************/
494 psi = min * (M_PI / 30.0);
495 psi += sec * (M_PI / 1800);
497 dx = floor(sin(psi) * 22 * 0.55 + 0.5);
498 dy = floor(-cos(psi) * 16 * 0.55 + 0.5);
500 // dx, dy is het punt waar we naar toe moeten.
501 // Zoek alle punten die ECHT op de lijn liggen:
503 dx += dx;
504 dy += dy;
506 ddx = 1;
507 ddy = 1;
508 if (dx < 0) ddx = -1;
509 if (dy < 0) ddy = -1;
511 x = 0;
512 y = 0;
514 if (abs(dx) > abs(dy)) {
515 if (dy != 0)
516 adder = abs(dx) / 2;
517 else
518 adder = 0;
519 for (i=0; i<abs(dx); i++) {
520 // laat de kleur afhangen van de adder.
521 // adder loopt van abs(dx) tot 0
523 k = 12 - adder / (abs(dx) / 12.0);
524 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
526 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
528 k = 12-k;
529 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
532 x += ddx;
534 adder -= abs(dy);
535 if (adder < 0) {
536 adder += abs(dx);
537 y += ddy;
540 } else {
541 if (dx != 0)
542 adder = abs(dy) / 2;
543 else
544 adder = 0;
545 for (i=0; i<abs(dy); i++) {
546 k = 12 - adder / (abs(dy) / 12.0);
547 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
549 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
551 k = 12-k;
552 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
554 y += ddy;
556 adder -= abs(dx);
557 if (adder < 0) {
558 adder += abs(dy);
559 x += ddx;
563 /**********************************************************************/
564 if (noseconds)
565 return; /* Skip drawing the seconds. */
567 psi = sec * (M_PI / 30.0);
569 dx = floor(sin(psi) * 22 * 0.9 + 0.5);
570 dy = floor(-cos(psi) * 16 * 0.9 + 0.5);
572 // dx, dy is het punt waar we naar toe moeten.
573 // Zoek alle punten die ECHT op de lijn liggen:
575 ddx = 1;
576 ddy = 1;
577 if (dx < 0) ddx = -1;
578 if (dy < 0) ddy = -1;
580 if (dx == 0) ddx = 0;
581 if (dy == 0) ddy = 0;
583 x = 0;
584 y = 0;
587 if (abs(dx) > abs(dy)) {
588 if (dy != 0)
589 adder = abs(dx) / 2;
590 else
591 adder = 0;
592 for (i=0; i<abs(dx); i++) {
593 // laat de kleur afhangen van de adder.
594 // adder loopt van abs(dx) tot 0
596 k = 12 - adder / (abs(dx) / 12.0);
597 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24 - ddy);
599 k = 12-k;
600 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
603 x += ddx;
605 adder -= abs(dy);
606 if (adder < 0) {
607 adder += abs(dx);
608 y += ddy;
611 } else {
612 if (dx != 0)
613 adder = abs(dy) / 2;
614 else
615 adder = 0;
616 for (i=0; i<abs(dy); i++) {
617 k = 12 - adder / (abs(dy) / 12.0);
618 copyXPMArea(79+k, 70, 1, 1, x + 31 - ddx, y + 24);
620 k = 12-k;
621 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
623 y += ddy;
625 adder -= abs(dx);
626 if (adder < 0) {
627 adder += abs(dy);
628 x += ddx;
634 /*******************************************************************************\
635 |* usage *|
636 \*******************************************************************************/
638 void usage(char *name) {
639 printf("Usage: %s [OPTION]...\n", name);
640 printf("WindowMaker dockapp that displays the time and date.\n");
641 printf("\n");
642 printf(" -d, -digital display the digital clock\n");
643 printf(" -display DISPLAY contact the DISPLAY X server\n");
644 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
645 printf(" -n, -noseconds disables the second hand\n");
646 printf(" -h display this help and exit\n");
647 printf(" -v output version information and exit\n");
650 /*******************************************************************************\
651 |* printversion *|
652 \*******************************************************************************/
654 void printversion(void) {
655 printf("WMTime version %s\n", WMMON_VERSION);
658 /* vim: sw=4 ts=4 columns=82