wmtime: Fixed Debian bug #639626. Applied a patch by Andrew Deason.
[dockapps.git] / wmtime / wmtime / wmtime.c
blob6f1a00703713beb8565d68f5eddbc86c5617be9e
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;
347 int numfields;
349 /* 7x13 */
351 if (noseconds) {
352 snprintf(time, time_size, "%02d:%02d ", hr, min);
353 numfields = 2;
355 else {
356 snprintf(time, time_size, "%02d:%02d:%02d ", hr, min, sec);
357 numfields = 3;
360 for (i=0; i < numfields; i++) {
361 for (j=0; j<2; j++) {
362 copyXPMArea((*p-'0')*7 + 1, 84, 8, 13, k, 18);
363 k += 7;
364 p++;
366 if (*p == ':') {
367 copyXPMArea(71, 84, 5, 13, k, 18);
368 k += 4;
369 p++;
374 /*******************************************************************************\
375 |* DrawDate *|
376 \*******************************************************************************/
378 void DrawDate(int wkday, int dom, int month) {
379 const int date_size = 16;
380 char date[date_size];
381 char *p = date;
382 int i,k;
384 /* 7x13 */
386 snprintf(date, date_size,
387 "%.2s%02d%.3s ", day_of_week[wkday], dom, mon_of_year[month]);
389 k = 5;
390 for (i=0; i<2; i++) {
391 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
392 k += 6;
393 p++;
395 k = 23;
396 for (i=0; i<2; i++) {
397 copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49);
398 k += 6;
399 p++;
401 copyXPMArea(61, 64, 4, 9, k, 49);
402 k += 4;
403 for (i=0; i<3; i++) {
404 copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49);
405 k += 6;
406 p++;
410 /*******************************************************************************\
411 |* DrawWijzer *|
412 \*******************************************************************************/
414 void DrawWijzer(int hr, int min, int sec) {
416 double psi;
417 int dx,dy;
418 int x,y;
419 int ddx,ddy;
420 int adder;
421 int k;
423 int i;
425 hr %= 12;
427 copyXPMArea(5+64, 5, 54, 40, 5, 5);
429 /**********************************************************************/
430 psi = hr * (M_PI / 6.0);
431 psi += min * (M_PI / 360);
433 dx = floor(sin(psi) * 22 * 0.7 + 0.5);
434 dy = floor(-cos(psi) * 16 * 0.7 + 0.5);
436 // dx, dy is het punt waar we naar toe moeten.
437 // Zoek alle punten die ECHT op de lijn liggen:
439 ddx = 1;
440 ddy = 1;
441 if (dx < 0) ddx = -1;
442 if (dy < 0) ddy = -1;
444 x = 0;
445 y = 0;
447 if (abs(dx) > abs(dy)) {
448 if (dy != 0)
449 adder = abs(dx) / 2;
450 else
451 adder = 0;
452 for (i=0; i<abs(dx); i++) {
453 // laat de kleur afhangen van de adder.
454 // adder loopt van abs(dx) tot 0
456 k = 12 - adder / (abs(dx) / 12.0);
457 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
459 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
461 k = 12-k;
462 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
465 x += ddx;
467 adder -= abs(dy);
468 if (adder < 0) {
469 adder += abs(dx);
470 y += ddy;
473 } else {
474 if (dx != 0)
475 adder = abs(dy) / 2;
476 else
477 adder = 0;
478 for (i=0; i<abs(dy); i++) {
479 k = 12 - adder / (abs(dy) / 12.0);
480 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
482 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
484 k = 12-k;
485 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
487 y += ddy;
489 adder -= abs(dx);
490 if (adder < 0) {
491 adder += abs(dy);
492 x += ddx;
496 /**********************************************************************/
497 psi = min * (M_PI / 30.0);
498 psi += sec * (M_PI / 1800);
500 dx = floor(sin(psi) * 22 * 0.55 + 0.5);
501 dy = floor(-cos(psi) * 16 * 0.55 + 0.5);
503 // dx, dy is het punt waar we naar toe moeten.
504 // Zoek alle punten die ECHT op de lijn liggen:
506 dx += dx;
507 dy += dy;
509 ddx = 1;
510 ddy = 1;
511 if (dx < 0) ddx = -1;
512 if (dy < 0) ddy = -1;
514 x = 0;
515 y = 0;
517 if (abs(dx) > abs(dy)) {
518 if (dy != 0)
519 adder = abs(dx) / 2;
520 else
521 adder = 0;
522 for (i=0; i<abs(dx); i++) {
523 // laat de kleur afhangen van de adder.
524 // adder loopt van abs(dx) tot 0
526 k = 12 - adder / (abs(dx) / 12.0);
527 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 - ddy);
529 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
531 k = 12-k;
532 copyXPMArea(79+k, 67, 1, 1, x + 31, y + 24 + ddy);
535 x += ddx;
537 adder -= abs(dy);
538 if (adder < 0) {
539 adder += abs(dx);
540 y += ddy;
543 } else {
544 if (dx != 0)
545 adder = abs(dy) / 2;
546 else
547 adder = 0;
548 for (i=0; i<abs(dy); i++) {
549 k = 12 - adder / (abs(dy) / 12.0);
550 copyXPMArea(79+k, 67, 1, 1, x + 31 - ddx, y + 24);
552 copyXPMArea(79, 67, 1, 1, x + 31, y + 24);
554 k = 12-k;
555 copyXPMArea(79+k, 67, 1, 1, x + 31 + ddx, y + 24);
557 y += ddy;
559 adder -= abs(dx);
560 if (adder < 0) {
561 adder += abs(dy);
562 x += ddx;
566 /**********************************************************************/
567 if (noseconds)
568 return; /* Skip drawing the seconds. */
570 psi = sec * (M_PI / 30.0);
572 dx = floor(sin(psi) * 22 * 0.9 + 0.5);
573 dy = floor(-cos(psi) * 16 * 0.9 + 0.5);
575 // dx, dy is het punt waar we naar toe moeten.
576 // Zoek alle punten die ECHT op de lijn liggen:
578 ddx = 1;
579 ddy = 1;
580 if (dx < 0) ddx = -1;
581 if (dy < 0) ddy = -1;
583 if (dx == 0) ddx = 0;
584 if (dy == 0) ddy = 0;
586 x = 0;
587 y = 0;
590 if (abs(dx) > abs(dy)) {
591 if (dy != 0)
592 adder = abs(dx) / 2;
593 else
594 adder = 0;
595 for (i=0; i<abs(dx); i++) {
596 // laat de kleur afhangen van de adder.
597 // adder loopt van abs(dx) tot 0
599 k = 12 - adder / (abs(dx) / 12.0);
600 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24 - ddy);
602 k = 12-k;
603 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
606 x += ddx;
608 adder -= abs(dy);
609 if (adder < 0) {
610 adder += abs(dx);
611 y += ddy;
614 } else {
615 if (dx != 0)
616 adder = abs(dy) / 2;
617 else
618 adder = 0;
619 for (i=0; i<abs(dy); i++) {
620 k = 12 - adder / (abs(dy) / 12.0);
621 copyXPMArea(79+k, 70, 1, 1, x + 31 - ddx, y + 24);
623 k = 12-k;
624 copyXPMArea(79+k, 70, 1, 1, x + 31, y + 24);
626 y += ddy;
628 adder -= abs(dx);
629 if (adder < 0) {
630 adder += abs(dy);
631 x += ddx;
637 /*******************************************************************************\
638 |* usage *|
639 \*******************************************************************************/
641 void usage(char *name) {
642 printf("Usage: %s [OPTION]...\n", name);
643 printf("WindowMaker dockapp that displays the time and date.\n");
644 printf("\n");
645 printf(" -d, -digital display the digital clock\n");
646 printf(" -display DISPLAY contact the DISPLAY X server\n");
647 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
648 printf(" -n, -noseconds disables the second hand\n");
649 printf(" -h display this help and exit\n");
650 printf(" -v output version information and exit\n");
653 /*******************************************************************************\
654 |* printversion *|
655 \*******************************************************************************/
657 void printversion(void) {
658 printf("WMTime version %s\n", WMMON_VERSION);
661 /* vim: sw=4 ts=4 columns=82