1 /* wmtime - Window Maker dockapp that displays the time and date
2 Copyright (C) 1997, 1998 Martijn Pieterse <pieterse@xs4all.nl>
3 Copyright (C) 1997, 1998 Antoine Nulle <warp@xs4all.nl>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 Code based on wmppp/wmifs
22 This code was mainly put together by looking at the
26 A neat piece of equip, used to display the date
27 and time on the screen.
28 Comes with every AfterStep installation.
31 How do I create a not so solid window?
32 How do I open a window?
35 ------------------------------------------------------------
37 Author: Martijn Pieterse (pieterse@xs4all.nl)
39 This program is distributed under the GPL license.
40 (as were asclock and pppstats)
45 15/07/2008 (Paul Harris, harris.pc@gmail.com)
46 * Minor changes to correct build warnings
47 09/10/2003 (Simon Law, sfllaw@debian.org)
48 * Add -geometry support
49 * Add -noseconds support
50 * Make the digital clock fill the space provided
51 * Eliminated exploitable static buffers
52 17/05/1998 (Antoine Nulle, warp@xs4all.nl)
53 * Updated version number and some other minor stuff
54 16/05/1998 (Antoine Nulle, warp@xs4all.nl)
55 * Added Locale support, based on original diff supplied
56 by Alen Salamun (snowman@hal9000.medinet.si)
57 04/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
58 * Moved the hands one pixel down.
59 * Removed the RedrawWindow out of the main loop
60 02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl)
61 * Removed a lot of code that was in the wmgeneral dir.
62 02/05/1998 (Antoine Nulle, warp@xs4all.nl)
63 * Updated master-xpm, hour dots where a bit 'off'
64 30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
65 * Added anti-aliased hands
66 23/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
67 * Changed the hand lengths.. again! ;)
68 * Zombies were created, so added wait code
69 21/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
70 * Added digital/analog switching support
71 18/04/1998 (Martijn Pieterse, pieterse@xs4all.nl)
72 * Started this project.
73 * Copied the source from wmmon.
77 #include <X11/X.h> /* for ButtonPress, ButtonRelease, etc */
78 #include <X11/Xlib.h> /* for XEvent, XButtonEvent, etc */
80 #include <ctype.h> /* for toupper */
81 #include <iconv.h> /* for iconv, iconv_close, etc */
82 #include <langinfo.h> /* for nl_langinfo, ABDAY_1, etc */
83 #include <locale.h> /* for NULL, setlocale, LC_ALL */
84 #include <math.h> /* for floor, cos, sin, M_PI */
85 #include <stddef.h> /* for size_t */
86 #include <stdio.h> /* for printf, asprintf, snprintf, etc */
87 #include <stdlib.h> /* for abs, free, exit, getenv */
88 #include <string.h> /* for strcmp, strdup, strncpy, etc */
89 #include <sys/wait.h> /* for waitpid, WNOHANG */
90 #include <time.h> /* for tm, time, localtime */
91 #include <unistd.h> /* for usleep */
92 #include "libdockapp/misc.h" /* for execCommand */
93 #include "libdockapp/wmgeneral.h" /* for copyXPMArea, RedrawWindow, etc */
94 #include "wmtime-mask.xbm" /* for wmtime_mask_bits */
95 #include "wmtime-master.xpm" /* for wmtime_master_xpm */
102 const char* default_left_action
= NULL
;
103 const char* default_middle_action
= NULL
;
104 const char* default_right_action
= NULL
;
106 #define WMTIME_VERSION "1.4"
108 /********************/
109 /* Global Variables */
110 /********************/
114 char day_of_week
[7][3] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" };
115 char mon_of_year
[12][4] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
121 void printversion(void);
123 void wmtime_routine(int, char **);
127 int main(int argc
, char *argv
[]) {
130 char *name
= argv
[0];
136 for (i
=1; i
<argc
; i
++) {
143 strcpy(color
, argv
[i
+1]);
148 if (strcmp(arg
+1, "display")
149 && strcmp(arg
+1, "digital") && strcmp(arg
+1, "d")) {
153 if (!strcmp(arg
+1, "digital") || !(strcmp(arg
+1, "d")))
157 if (strcmp(arg
+1, "geometry")) {
163 if (strcmp(arg
+1, "noseconds") && strcmp(arg
+1, "n")) {
175 strcpy(locale
, argv
[i
+1]);
186 if (setlocale(LC_ALL
, locale
) == NULL
)
188 "warning: locale '%s' not recognized; defaulting to '%s'.",
189 locale
, setlocale(LC_ALL
, NULL
));
192 wmtime_routine(argc
, argv
);
201 char langbuf
[10], outbuf
[10];
205 size_t insize
, outsize
;
207 icd
= iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET
));
208 if (icd
== (iconv_t
) -1) {
209 perror("wmtime: Error allocating charset conversion descriptor");
213 for (i
= 0; i
< 7; i
++) {
214 strncpy(langbuf
, nl_langinfo(ABDAY_1
+ i
), 10);
215 insize
= outsize
= 10;
219 ret
= iconv(icd
, &inp
, &insize
, &outp
, &outsize
);
220 } while (outsize
> 0 && ret
> 0);
221 if (strstr(outbuf
,"?") != NULL
) return;
222 for (outp
= outbuf
, outsize
= 0; *outp
!= 0 && outsize
< 2;
224 day_of_week
[i
][outsize
] = toupper(*outp
);
226 for (i
= 0; i
< 12; i
++) {
227 strncpy(langbuf
, nl_langinfo(ABMON_1
+ i
), 10);
228 insize
= outsize
= 10;
232 ret
= iconv(icd
, &inp
, &insize
, &outp
, &outsize
);
233 } while (outsize
> 0 && ret
> 0);
234 if (strstr(outbuf
,"?") != NULL
) return;
235 for (outp
= outbuf
, outsize
= 0; *outp
!= 0 && outsize
< 3;
237 mon_of_year
[i
][outsize
] = toupper(*outp
);
243 Pixel
scale_pixel(Pixel pixel
, float scale
)
245 int red
, green
, blue
;
247 red
= pixel
/ ( 1 << 16 );
248 green
= pixel
% (1 << 16) / (1 << 8);
249 blue
= pixel
% (1 << 8);
255 return red
* (1 << 16) + green
* (1 << 8) + blue
;
258 /*******************************************************************************\
260 \*******************************************************************************/
262 char *left_action
= NULL
;
263 char *right_action
= NULL
;
264 char *middle_action
= NULL
;
266 void DrawTime(int, int, int);
267 void DrawWijzer(int, int, int);
268 void DrawDate(int, int, int);
270 void wmtime_routine(int argc
, char **argv
) {
272 rckeys wmtime_keys
[] = {
273 { "left", &left_action
},
274 { "right", &right_action
},
275 { "middle", &middle_action
},
283 struct tm
*time_struct
;
288 char *conffile
= NULL
;
290 /* Scan through ~/.wmtimerc for the mouse button actions. */
291 if (default_left_action
) left_action
= strdup(default_left_action
);
292 if (default_middle_action
) middle_action
= strdup(default_middle_action
);
293 if (default_right_action
) right_action
= strdup(default_right_action
);
295 /* Scan through the .rc files */
296 if (asprintf(&conffile
, "/etc/wmtimerc") >= 0) {
297 parse_rcfile(conffile
, wmtime_keys
);
301 if (asprintf(&conffile
, "%s/.wmtimerc", getenv("HOME")) >= 0) {
302 parse_rcfile(conffile
, wmtime_keys
);
306 if (asprintf(&conffile
, "/etc/wmtimerc.fixed") >= 0) {
307 parse_rcfile(conffile
, wmtime_keys
);
311 /* set user-defined colors */
315 XWindowAttributes attributes
;
318 #define NUMSYMBOLS 10
319 XpmColorSymbol user_color
[NUMSYMBOLS
] = {
320 {NULL
, "#2081B2CAAEBA", 0}, /* O */
321 {NULL
, "#000049244103", 0}, /* + */
322 {NULL
, "#00007DF771C6", 0}, /* @ */
323 {NULL
, "#18618A288617", 0}, /* # */
324 {NULL
, "#18619A699658", 0}, /* ; */
325 {NULL
, "#0820861779E7", 0}, /* : */
326 {NULL
, "#000071C66185", 0}, /* > */
327 {NULL
, "#000061855144", 0}, /* , */
328 {NULL
, "#00004D344103", 0}, /* < */
329 {NULL
, "#10407DF779E7", 0} /* 1 */
333 /* code based on GetColor() from wmgeneral.c */
334 /* we need a temporary display to parse the color */
335 display
= XOpenDisplay(NULL
);
336 screen
= DefaultScreen(display
);
337 Root
= RootWindow(display
, screen
);
338 XGetWindowAttributes(display
, Root
, &attributes
);
341 if (!XParseColor(display
, attributes
.colormap
, color
, &col
)) {
342 fprintf(stderr
, "wmtime: can't parse %s.\n", color
);
344 } else if (!XAllocColor(display
, attributes
.colormap
, &col
)) {
345 fprintf(stderr
, "wmtime: can't allocate %s.\n", color
);
351 /* replace colors from wmtime-master.xpm */
352 user_color
[0].pixel
= pixel
;
353 user_color
[1].pixel
= scale_pixel(pixel
, .4);
354 user_color
[2].pixel
= scale_pixel(pixel
, .7);
355 user_color
[3].pixel
= scale_pixel(pixel
, .8);
356 user_color
[4].pixel
= scale_pixel(pixel
, .9);
357 user_color
[5].pixel
= scale_pixel(pixel
, .8);
358 user_color
[6].pixel
= scale_pixel(pixel
, .6);
359 user_color
[7].pixel
= scale_pixel(pixel
, .5);
360 user_color
[8].pixel
= scale_pixel(pixel
, .4);
361 user_color
[9].pixel
= scale_pixel(pixel
, .7);
363 wmgen
.attributes
.valuemask
|= XpmColorSymbols
;
364 wmgen
.attributes
.numsymbols
= NUMSYMBOLS
;
365 wmgen
.attributes
.colorsymbols
= user_color
;
367 XCloseDisplay(display
);
371 openXwindow(argc
, argv
, wmtime_master_xpm
, (char*)wmtime_mask_bits
, 128, 64);
373 /* Mask out the right parts of the clock */
374 copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */
375 copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */
376 copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */
379 /* add mouse region */
380 AddMouseRegion(0, 5, 48, 58, 60);
381 AddMouseRegion(1, 5, 5, 58, 46);
386 time_struct
= localtime(&curtime
);
391 waitpid(0, NULL
, WNOHANG
);
393 time_struct
= localtime(&curtime
);
396 if (curtime
>= starttime
) {
398 /* Now to update the seconds */
400 DrawWijzer(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
402 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
406 DrawTime(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
408 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
414 while (XPending(display
)) {
415 XNextEvent(display
, &Event
);
416 switch (Event
.type
) {
421 XCloseDisplay(display
);
425 but_stat
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
428 i
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
429 if (but_stat
== i
&& but_stat
>= 0) {
435 copyXPMArea(64, 98, 64, 64, 0, 0);
436 DrawTime(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
437 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
439 copyXPMArea(0, 98, 64, 64, 0, 0);
440 DrawWijzer(time_struct
->tm_hour
, time_struct
->tm_min
, time_struct
->tm_sec
);
441 DrawDate(time_struct
->tm_wday
, time_struct
->tm_mday
, time_struct
->tm_mon
);
446 switch (Event
.xbutton
.button
) {
449 execCommand(left_action
);
453 execCommand(middle_action
);
457 execCommand(right_action
);
466 /* Sleep 0.3 seconds */
471 /*******************************************************************************\
473 \*******************************************************************************/
475 void DrawTime(int hr
, int min
, int sec
) {
477 char time
[TIME_SIZE
];
485 snprintf(time
, TIME_SIZE
, "%02d:%02d ", hr
, min
);
489 snprintf(time
, TIME_SIZE
, "%02d:%02d:%02d ", hr
, min
, sec
);
493 for (i
=0; i
< numfields
; i
++) {
494 for (j
=0; j
<2; j
++) {
495 copyXPMArea((*p
-'0')*7 + 1, 84, 8, 13, k
, 18);
500 copyXPMArea(71, 84, 5, 13, k
, 18);
507 /*******************************************************************************\
509 \*******************************************************************************/
511 void DrawDate(int wkday
, int dom
, int month
) {
513 char date
[DATE_SIZE
];
519 snprintf(date
, DATE_SIZE
,
520 "%.2s%02d%.3s ", day_of_week
[wkday
], dom
, mon_of_year
[month
]);
523 for (i
=0; i
<2; i
++) {
525 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
527 copyXPMArea((*p
-'A')*6, 74, 6, 9, k
, 49);
532 for (i
=0; i
<2; i
++) {
533 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
537 copyXPMArea(61, 64, 4, 9, k
, 49);
539 for (i
=0; i
<3; i
++) {
541 copyXPMArea((*p
-'0')*6, 64, 6, 9, k
, 49);
543 copyXPMArea((*p
-'A')*6, 74, 6, 9, k
, 49);
549 /*******************************************************************************\
551 \*******************************************************************************/
553 void DrawWijzer(int hr
, int min
, int sec
) {
566 copyXPMArea(5+64, 5, 54, 40, 5, 5);
568 /**********************************************************************/
569 psi
= hr
* (M_PI
/ 6.0);
570 psi
+= min
* (M_PI
/ 360);
572 dx
= floor(sin(psi
) * 22 * 0.7 + 0.5);
573 dy
= floor(-cos(psi
) * 16 * 0.7 + 0.5);
575 /* dx, dy is het punt waar we naar toe moeten.
576 * Zoek alle punten die ECHT op de lijn liggen: */
580 if (dx
< 0) ddx
= -1;
581 if (dy
< 0) ddy
= -1;
586 if (abs(dx
) > abs(dy
)) {
591 for (i
=0; i
<abs(dx
); i
++) {
592 /* laat de kleur afhangen van de adder.
593 * adder loopt van abs(dx) tot 0 */
595 k
= 12 - adder
/ (abs(dx
) / 12.0);
596 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 - ddy
);
598 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
601 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 + ddy
);
617 for (i
=0; i
<abs(dy
); i
++) {
618 k
= 12 - adder
/ (abs(dy
) / 12.0);
619 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 - ddx
, y
+ 24);
621 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
624 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 + ddx
, y
+ 24);
635 /**********************************************************************/
636 psi
= min
* (M_PI
/ 30.0);
637 psi
+= sec
* (M_PI
/ 1800);
639 dx
= floor(sin(psi
) * 22 * 0.55 + 0.5);
640 dy
= floor(-cos(psi
) * 16 * 0.55 + 0.5);
642 /* dx, dy is het punt waar we naar toe moeten.
643 * Zoek alle punten die ECHT op de lijn liggen: */
650 if (dx
< 0) ddx
= -1;
651 if (dy
< 0) ddy
= -1;
656 if (abs(dx
) > abs(dy
)) {
661 for (i
=0; i
<abs(dx
); i
++) {
662 /* laat de kleur afhangen van de adder.
663 * adder loopt van abs(dx) tot 0 */
665 k
= 12 - adder
/ (abs(dx
) / 12.0);
666 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 - ddy
);
668 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
671 copyXPMArea(79+k
, 67, 1, 1, x
+ 31, y
+ 24 + ddy
);
687 for (i
=0; i
<abs(dy
); i
++) {
688 k
= 12 - adder
/ (abs(dy
) / 12.0);
689 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 - ddx
, y
+ 24);
691 copyXPMArea(79, 67, 1, 1, x
+ 31, y
+ 24);
694 copyXPMArea(79+k
, 67, 1, 1, x
+ 31 + ddx
, y
+ 24);
705 /**********************************************************************/
707 return; /* Skip drawing the seconds. */
709 psi
= sec
* (M_PI
/ 30.0);
711 dx
= floor(sin(psi
) * 22 * 0.9 + 0.5);
712 dy
= floor(-cos(psi
) * 16 * 0.9 + 0.5);
714 /* dx, dy is het punt waar we naar toe moeten.
715 * Zoek alle punten die ECHT op de lijn liggen: */
719 if (dx
< 0) ddx
= -1;
720 if (dy
< 0) ddy
= -1;
722 if (dx
== 0) ddx
= 0;
723 if (dy
== 0) ddy
= 0;
729 if (abs(dx
) > abs(dy
)) {
734 for (i
=0; i
<abs(dx
); i
++) {
735 /* laat de kleur afhangen van de adder.
736 * adder loopt van abs(dx) tot 0 */
738 k
= 12 - adder
/ (abs(dx
) / 12.0);
739 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24 - ddy
);
742 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24);
758 for (i
=0; i
<abs(dy
); i
++) {
759 k
= 12 - adder
/ (abs(dy
) / 12.0);
760 copyXPMArea(79+k
, 70, 1, 1, x
+ 31 - ddx
, y
+ 24);
763 copyXPMArea(79+k
, 70, 1, 1, x
+ 31, y
+ 24);
776 /*******************************************************************************\
778 \*******************************************************************************/
780 void usage(char *name
) {
781 printf("Usage: %s [OPTION]...\n", name
);
782 printf("WindowMaker dockapp that displays the time and date.\n");
784 printf(" -d, -digital display the digital clock\n");
785 printf(" -display DISPLAY contact the DISPLAY X server\n");
786 printf(" -geometry GEOMETRY position the clock at GEOMETRY\n");
787 printf(" -n, -noseconds disables the second hand\n");
788 printf(" -l LOCALE set locale to LOCALE\n");
789 printf(" -h display this help and exit\n");
790 printf(" -v output version information and exit\n");
791 printf(" -c set color\n");
794 /*******************************************************************************\
796 \*******************************************************************************/
798 void printversion(void) {
799 printf("WMTime version %s\n", WMTIME_VERSION
);
802 /* vim: sw=4 ts=4 columns=82