2 Code based on wmppp/wmifs
6 This code was mainly put together by looking at the
10 A neat piece of equip, used to display the date
11 and time on the screen.
12 Comes with every AfterStep installation.
15 How do I create a not so solid window?
16 How do I open a window?
19 ------------------------------------------------------------
21 Author: Martijn Pieterse (pieterse@xs4all.nl)
23 This program is distributed under the GPL license.
24 (as were asclock and pppstats)
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.
61 #include <X11/X.h> /* for ButtonPress, ButtonRelease, etc */
62 #include <X11/Xlib.h> /* for XEvent, XButtonEvent, etc */
64 #include <ctype.h> /* for toupper */
65 #include <iconv.h> /* for iconv, iconv_close, etc */
66 #include <langinfo.h> /* for nl_langinfo, ABDAY_1, etc */
67 #include <locale.h> /* for NULL, setlocale, LC_ALL */
68 #include <math.h> /* for floor, cos, sin, M_PI */
69 #include <stddef.h> /* for size_t */
70 #include <stdio.h> /* for printf, asprintf, snprintf, etc */
71 #include <stdlib.h> /* for abs, free, exit, getenv */
72 #include <string.h> /* for strcmp, strdup, strncpy, etc */
73 #include <sys/wait.h> /* for waitpid, WNOHANG */
74 #include <time.h> /* for tm, time, localtime */
75 #include <unistd.h> /* for usleep */
76 #include "wmgeneral/misc.h" /* for execCommand */
77 #include "wmgeneral/wmgeneral.h" /* for copyXPMArea, RedrawWindow, etc */
78 #include "wmtime-mask.xbm" /* for wmtime_mask_bits */
79 #include "wmtime-master.xpm" /* for wmtime_master_xpm */
86 const char* default_left_action
= NULL
;
87 const char* default_middle_action
= NULL
;
88 const char* default_right_action
= NULL
;
90 #define WMTIME_VERSION "1.2"
92 /********************/
93 /* Global Variables */
94 /********************/
98 char day_of_week
[7][3] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
99 char mon_of_year
[12][4] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
105 void printversion(void);
107 void wmtime_routine(int, char **);
111 int main(int argc
, char *argv
[]) {
114 char *name
= argv
[0];
120 for (i
=1; i
<argc
; i
++) {
127 strcpy(color
, argv
[i
+1]);
132 if (strcmp(arg
+1, "display")
133 && strcmp(arg
+1, "digital") && strcmp(arg
+1, "d")) {
137 if (!strcmp(arg
+1, "digital") || !(strcmp(arg
+1, "d")))
141 if (strcmp(arg
+1, "geometry")) {
147 if (strcmp(arg
+1, "noseconds") && strcmp(arg
+1, "n")) {
159 strcpy(locale
, argv
[i
+1]);
170 if (setlocale(LC_ALL
, locale
) == NULL
)
172 "warning: locale '%s' not recognized; defaulting to '%s'.",
173 locale
, setlocale(LC_ALL
, NULL
));
176 wmtime_routine(argc
, argv
);
185 char langbuf
[10], outbuf
[10];
189 size_t insize
, outsize
;
191 icd
= iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET
));
192 if (icd
== (iconv_t
) -1) {
193 perror("wmtime: Error allocating charset conversion descriptor");
197 for (i
= 0; i
< 7; i
++) {
198 strncpy(langbuf
, nl_langinfo(ABDAY_1
+ i
), 10);
199 insize
= outsize
= 10;
203 ret
= iconv(icd
, &inp
, &insize
, &outp
, &outsize
);
204 } while (outsize
> 0 && ret
> 0);
205 if (strstr(outbuf
,"?") != NULL
) return;
206 for (outp
= outbuf
, outsize
= 0; *outp
!= 0 && outsize
< 2;
208 day_of_week
[i
][outsize
] = toupper(*outp
);
210 for (i
= 0; i
< 12; i
++) {
211 strncpy(langbuf
, nl_langinfo(ABMON_1
+ i
), 10);
212 insize
= outsize
= 10;
216 ret
= iconv(icd
, &inp
, &insize
, &outp
, &outsize
);
217 } while (outsize
> 0 && ret
> 0);
218 if (strstr(outbuf
,"?") != NULL
) return;
219 for (outp
= outbuf
, outsize
= 0; *outp
!= 0 && outsize
< 3;
221 mon_of_year
[i
][outsize
] = toupper(*outp
);
227 Pixel
scale_pixel(Pixel pixel
, float scale
)
229 int red
, green
, blue
;
231 red
= pixel
/ ( 1 << 16 );
232 green
= pixel
% (1 << 16) / (1 << 8);
233 blue
= pixel
% (1 << 8);
239 return red
* (1 << 16) + green
* (1 << 8) + blue
;
242 /*******************************************************************************\
244 \*******************************************************************************/
246 char *left_action
= NULL
;
247 char *right_action
= NULL
;
248 char *middle_action
= NULL
;
250 void DrawTime(int, int, int);
251 void DrawWijzer(int, int, int);
252 void DrawDate(int, int, int);
254 void wmtime_routine(int argc
, char **argv
) {
256 rckeys wmtime_keys
[] = {
257 { "left", &left_action
},
258 { "right", &right_action
},
259 { "middle", &middle_action
},
267 struct tm
*time_struct
;
272 char *conffile
= NULL
;
274 /* Scan through ~/.wmtimerc for the mouse button actions. */
275 if (default_left_action
) left_action
= strdup(default_left_action
);
276 if (default_middle_action
) middle_action
= strdup(default_middle_action
);
277 if (default_right_action
) right_action
= strdup(default_right_action
);
279 /* Scan through the .rc files */
280 if (asprintf(&conffile
, "/etc/wmtimerc") >= 0) {
281 parse_rcfile(conffile
, wmtime_keys
);
285 if (asprintf(&conffile
, "%s/.wmtimerc", getenv("HOME")) >= 0) {
286 parse_rcfile(conffile
, wmtime_keys
);
290 if (asprintf(&conffile
, "/etc/wmtimerc.fixed") >= 0) {
291 parse_rcfile(conffile
, wmtime_keys
);
295 /* set user-defined colors */
299 XWindowAttributes attributes
;
302 #define NUMSYMBOLS 10
303 XpmColorSymbol user_color
[NUMSYMBOLS
] = {
304 {NULL
, "#2081B2CAAEBA", 0}, /* O */
305 {NULL
, "#000049244103", 0}, /* + */
306 {NULL
, "#00007DF771C6", 0}, /* @ */
307 {NULL
, "#18618A288617", 0}, /* # */
308 {NULL
, "#18619A699658", 0}, /* ; */
309 {NULL
, "#0820861779E7", 0}, /* : */
310 {NULL
, "#000071C66185", 0}, /* > */
311 {NULL
, "#000061855144", 0}, /* , */
312 {NULL
, "#00004D344103", 0}, /* < */
313 {NULL
, "#10407DF779E7", 0} /* 1 */
317 /* code based on GetColor() from wmgeneral.c */
318 /* we need a temporary display to parse the color */
319 display
= XOpenDisplay(NULL
);
320 screen
= DefaultScreen(display
);
321 Root
= RootWindow(display
, screen
);
322 XGetWindowAttributes(display
, Root
, &attributes
);
325 if (!XParseColor(display
, attributes
.colormap
, color
, &col
)) {
326 fprintf(stderr
, "wmtime: can't parse %s.\n", color
);
328 } else if (!XAllocColor(display
, attributes
.colormap
, &col
)) {
329 fprintf(stderr
, "wmtime: can't allocate %s.\n", color
);
335 /* replace colors from wmtime-master.xpm */
336 user_color
[0].pixel
= pixel
;
337 user_color
[1].pixel
= scale_pixel(pixel
, .4);
338 user_color
[2].pixel
= scale_pixel(pixel
, .7);
339 user_color
[3].pixel
= scale_pixel(pixel
, .8);
340 user_color
[4].pixel
= scale_pixel(pixel
, .9);
341 user_color
[5].pixel
= scale_pixel(pixel
, .8);
342 user_color
[6].pixel
= scale_pixel(pixel
, .6);
343 user_color
[7].pixel
= scale_pixel(pixel
, .5);
344 user_color
[8].pixel
= scale_pixel(pixel
, .4);
345 user_color
[9].pixel
= scale_pixel(pixel
, .7);
347 wmgen
.attributes
.valuemask
|= XpmColorSymbols
;
348 wmgen
.attributes
.numsymbols
= NUMSYMBOLS
;
349 wmgen
.attributes
.colorsymbols
= user_color
;
351 XCloseDisplay(display
);
355 openXwindow(argc
, argv
, wmtime_master_xpm
, (char*)wmtime_mask_bits
, 128, 64);
357 /* Mask out the right parts of the clock */
358 copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */
359 copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */
360 copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */
363 /* add mouse region */
364 AddMouseRegion(0, 5, 48, 58, 60);
365 AddMouseRegion(1, 5, 5, 58, 46);
370 time_struct
= localtime(&curtime
);
375 waitpid(0, NULL
, WNOHANG
);
377 time_struct
= localtime(&curtime
);
380 if (curtime
>= starttime
) {
382 /* Now to update the seconds */
384 DrawWijzer(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
386 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
390 DrawTime(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
392 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
398 while (XPending(display
)) {
399 XNextEvent(display
, &Event
);
400 switch (Event
.type
) {
405 XCloseDisplay(display
);
409 but_stat
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
412 i
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
413 if (but_stat
== i
&& but_stat
>= 0) {
419 copyXPMArea(64, 98, 64, 64, 0, 0);
420 DrawTime(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
421 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
423 copyXPMArea(0, 98, 64, 64, 0, 0);
424 DrawWijzer(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
425 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
430 switch (Event
.xbutton
.button
) {
433 execCommand(left_action
);
437 execCommand(middle_action
);
441 execCommand(right_action
);
450 /* Sleep 0.3 seconds */
455 /*******************************************************************************\
457 \*******************************************************************************/
459 void DrawTime(int hr
, int min
, int sec
) {
461 char time
[TIME_SIZE
];
469 snprintf(time
, TIME_SIZE
, "%02d:%02d ", hr
, min
);
473 snprintf(time
, TIME_SIZE
, "%02d:%02d:%02d ", hr
, min
, sec
);
477 for (i
=0; i
< numfields
; i
++) {
478 for (j
=0; j
<2; j
++) {
479 copyXPMArea((*p
-'0')*7 + 1, 84, 8, 13, k
, 18);
484 copyXPMArea(71, 84, 5, 13, k
, 18);
491 /*******************************************************************************\
493 \*******************************************************************************/
495 void DrawDate(int wkday
, int dom
, int month
) {
497 char date
[DATE_SIZE
];
503 snprintf(date
, DATE_SIZE
,
504 "%.2s%02d%.3s ", day_of_week
[wkday
], dom
, mon_of_year
[month
]);
507 for (i
=0; i
<2; i
++) {
509 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
511 copyXPMArea((*p
-'A')*6, 74, 6, 9, k
, 49);
516 for (i
=0; i
<2; i
++) {
517 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
521 copyXPMArea(61, 64, 4, 9, k
, 49);
523 for (i
=0; i
<3; i
++) {
525 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
527 copyXPMArea((*p
-'A')*6, 74, 6, 9, k
, 49);
533 /*******************************************************************************\
535 \*******************************************************************************/
537 void DrawWijzer(int hr
, int min
, int sec
) {
550 copyXPMArea(5+64, 5, 54, 40, 5, 5);
552 /**********************************************************************/
553 psi
= hr
* (M_PI
/ 6.0);
554 psi
+= min
* (M_PI
/ 360);
556 dx
= floor(sin(psi
) * 22 * 0.7 + 0.5);
557 dy
= floor(-cos(psi
) * 16 * 0.7 + 0.5);
559 /* dx, dy is het punt waar we naar toe moeten.
560 * Zoek alle punten die ECHT op de lijn liggen: */
564 if (dx
< 0) ddx
= -1;
565 if (dy
< 0) ddy
= -1;
570 if (abs(dx
) > abs(dy
)) {
575 for (i
=0; i
<abs(dx
); i
++) {
576 /* laat de kleur afhangen van de adder.
577 * adder loopt van abs(dx) tot 0 */
579 k
= 12 - adder
/ (abs(dx
) / 12.0);
580 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 - ddy
);
582 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
585 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 + ddy
);
601 for (i
=0; i
<abs(dy
); i
++) {
602 k
= 12 - adder
/ (abs(dy
) / 12.0);
603 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 - ddx
, y
+ 24);
605 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
608 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 + ddx
, y
+ 24);
619 /**********************************************************************/
620 psi
= min
* (M_PI
/ 30.0);
621 psi
+= sec
* (M_PI
/ 1800);
623 dx
= floor(sin(psi
) * 22 * 0.55 + 0.5);
624 dy
= floor(-cos(psi
) * 16 * 0.55 + 0.5);
626 /* dx, dy is het punt waar we naar toe moeten.
627 * Zoek alle punten die ECHT op de lijn liggen: */
634 if (dx
< 0) ddx
= -1;
635 if (dy
< 0) ddy
= -1;
640 if (abs(dx
) > abs(dy
)) {
645 for (i
=0; i
<abs(dx
); i
++) {
646 /* laat de kleur afhangen van de adder.
647 * adder loopt van abs(dx) tot 0 */
649 k
= 12 - adder
/ (abs(dx
) / 12.0);
650 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 - ddy
);
652 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
655 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 + ddy
);
671 for (i
=0; i
<abs(dy
); i
++) {
672 k
= 12 - adder
/ (abs(dy
) / 12.0);
673 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 - ddx
, y
+ 24);
675 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
678 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 + ddx
, y
+ 24);
689 /**********************************************************************/
691 return; /* Skip drawing the seconds. */
693 psi
= sec
* (M_PI
/ 30.0);
695 dx
= floor(sin(psi
) * 22 * 0.9 + 0.5);
696 dy
= floor(-cos(psi
) * 16 * 0.9 + 0.5);
698 /* dx, dy is het punt waar we naar toe moeten.
699 * Zoek alle punten die ECHT op de lijn liggen: */
703 if (dx
< 0) ddx
= -1;
704 if (dy
< 0) ddy
= -1;
706 if (dx
== 0) ddx
= 0;
707 if (dy
== 0) ddy
= 0;
713 if (abs(dx
) > abs(dy
)) {
718 for (i
=0; i
<abs(dx
); i
++) {
719 /* laat de kleur afhangen van de adder.
720 * adder loopt van abs(dx) tot 0 */
722 k
= 12 - adder
/ (abs(dx
) / 12.0);
723 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24 - ddy
);
726 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24);
742 for (i
=0; i
<abs(dy
); i
++) {
743 k
= 12 - adder
/ (abs(dy
) / 12.0);
744 copyXPMArea(79+k
, 70, 1, 1, x
+ 31 - ddx
, y
+ 24);
747 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24);
760 /*******************************************************************************\
762 \*******************************************************************************/
764 void usage(char *name
) {
765 printf("Usage: %s [OPTION]...\n", name
);
766 printf("WindowMaker dockapp that displays the time and date.\n");
768 printf(" -d, -digital display the digital clock\n");
769 printf(" -display DISPLAY contact the DISPLAY X server\n");
770 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
771 printf(" -n, -noseconds disables the second hand\n");
772 printf(" -l LOCALE set locale to LOCALE\n");
773 printf(" -h display this help and exit\n");
774 printf(" -v output version information and exit\n");
775 printf(" -c set color\n");
778 /*******************************************************************************\
780 \*******************************************************************************/
782 void printversion(void) {
783 printf("WMTime version %s\n", WMTIME_VERSION
);
786 /* vim: sw=4 ts=4 columns=82