/* wmtime - Window Maker dockapp that displays the time and date Copyright (C) 1997, 1998 Martijn Pieterse Copyright (C) 1997, 1998 Antoine Nulle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Code based on wmppp/wmifs [Orig WMMON comments] This code was mainly put together by looking at the following programs: asclock A neat piece of equip, used to display the date and time on the screen. Comes with every AfterStep installation. Source used: How do I create a not so solid window? How do I open a window? How do I use pixmaps? ------------------------------------------------------------ Author: Martijn Pieterse (pieterse@xs4all.nl) This program is distributed under the GPL license. (as were asclock and pppstats) ---- Changes: ---- 15/07/2008 (Paul Harris, harris.pc@gmail.com) * Minor changes to correct build warnings 09/10/2003 (Simon Law, sfllaw@debian.org) * Add -geometry support * Add -noseconds support * Make the digital clock fill the space provided * Eliminated exploitable static buffers 17/05/1998 (Antoine Nulle, warp@xs4all.nl) * Updated version number and some other minor stuff 16/05/1998 (Antoine Nulle, warp@xs4all.nl) * Added Locale support, based on original diff supplied by Alen Salamun (snowman@hal9000.medinet.si) 04/05/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Moved the hands one pixel down. * Removed the RedrawWindow out of the main loop 02/05/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Removed a lot of code that was in the wmgeneral dir. 02/05/1998 (Antoine Nulle, warp@xs4all.nl) * Updated master-xpm, hour dots where a bit 'off' 30/04/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Added anti-aliased hands 23/04/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Changed the hand lengths.. again! ;) * Zombies were created, so added wait code 21/04/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Added digital/analog switching support 18/04/1998 (Martijn Pieterse, pieterse@xs4all.nl) * Started this project. * Copied the source from wmmon. */ #define _GNU_SOURCE #include /* for ButtonPress, ButtonRelease, etc */ #include /* for XEvent, XButtonEvent, etc */ #include #include /* for toupper */ #include /* for iconv, iconv_close, etc */ #include /* for nl_langinfo, ABDAY_1, etc */ #include /* for NULL, setlocale, LC_ALL */ #include /* for floor, cos, sin, M_PI */ #include /* for size_t */ #include /* for printf, asprintf, snprintf, etc */ #include /* for abs, free, exit, getenv */ #include /* for strcmp, strdup, strncpy, etc */ #include /* for waitpid, WNOHANG */ #include /* for tm, time, localtime */ #include /* for usleep */ #include "libdockapp/misc.h" /* for execCommand */ #include "libdockapp/wmgeneral.h" /* for copyXPMArea, RedrawWindow, etc */ #include "wmtime-mask.xbm" /* for wmtime_mask_bits */ #include "wmtime-master.xpm" /* for wmtime_master_xpm */ /***********/ /* Defines */ /***********/ const char* default_left_action = NULL; const char* default_middle_action = NULL; const char* default_right_action = NULL; #define WMTIME_VERSION "1.4" /********************/ /* Global Variables */ /********************/ int digital = 0; int noseconds = 0; char day_of_week[7][3] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; char mon_of_year[12][4] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; XpmIcon wmgen; char color[256]; /* functions */ void usage(char *); void printversion(void); void wmtime_routine(int, char **); void get_lang(); int main(int argc, char *argv[]) { int i; char *name = argv[0]; char locale[256]; locale[0] = 0; color[0] = 0; for (i=1; i i+1) { strcpy(color, argv[i+1]); i++; } break; case 'd' : if (strcmp(arg+1, "display") && strcmp(arg+1, "digital") && strcmp(arg+1, "d")) { usage(name); return 1; } if (!strcmp(arg+1, "digital") || !(strcmp(arg+1, "d"))) digital = 1; break; case 'g' : if (strcmp(arg+1, "geometry")) { usage(name); return 1; } break; case 'n' : if (strcmp(arg+1, "noseconds") && strcmp(arg+1, "n")) { usage(name); return 1; } else { noseconds = 1; } break; case 'v' : printversion(); return 0; case 'l': if (argc > i+1) { strcpy(locale, argv[i+1]); i++; } break; default: usage(name); return 1; } } } if (setlocale(LC_ALL, locale) == NULL) fprintf(stderr, "warning: locale '%s' not recognized; defaulting to '%s'.", locale, setlocale(LC_ALL, NULL)); get_lang(); wmtime_routine(argc, argv); return 0; } /************/ /* get_lang */ /************/ void get_lang(void) { char langbuf[10], outbuf[10]; char *inp, *outp; iconv_t icd; int i, ret; size_t insize, outsize; icd = iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET)); if (icd == (iconv_t) -1) { perror("wmtime: Error allocating charset conversion descriptor"); return; } for (i = 0; i < 7; i++) { strncpy(langbuf, nl_langinfo(ABDAY_1 + i), 10); insize = outsize = 10; inp = langbuf; outp = outbuf; do { ret = iconv(icd, &inp, &insize, &outp, &outsize); } while (outsize > 0 && ret > 0); if (strstr(outbuf,"?") != NULL) return; for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 2; outp++, outsize++) day_of_week[i][outsize] = toupper(*outp); } for (i = 0; i < 12; i++) { strncpy(langbuf, nl_langinfo(ABMON_1 + i), 10); insize = outsize = 10; inp = langbuf; outp = outbuf; do { ret = iconv(icd, &inp, &insize, &outp, &outsize); } while (outsize > 0 && ret > 0); if (strstr(outbuf,"?") != NULL) return; for (outp = outbuf, outsize = 0; *outp != 0 && outsize < 3; outp++, outsize++) mon_of_year[i][outsize] = toupper(*outp); } iconv_close(icd); } Pixel scale_pixel(Pixel pixel, float scale) { int red, green, blue; red = pixel / ( 1 << 16 ); green = pixel % (1 << 16) / (1 << 8); blue = pixel % (1 << 8); red *= scale; green *= scale; blue *= scale; return red * (1 << 16) + green * (1 << 8) + blue; } /*******************************************************************************\ |* wmtime_routine *| \*******************************************************************************/ char *left_action = NULL; char *right_action = NULL; char *middle_action = NULL; void DrawTime(int, int, int); void DrawWijzer(int, int, int); void DrawDate(int, int, int); void wmtime_routine(int argc, char **argv) { rckeys wmtime_keys[] = { { "left", &left_action }, { "right", &right_action }, { "middle", &middle_action }, { NULL, NULL } }; int i; XEvent Event; int but_stat = -1; struct tm *time_struct; long starttime; long curtime; char *conffile = NULL; /* Scan through ~/.wmtimerc for the mouse button actions. */ if (default_left_action) left_action = strdup(default_left_action); if (default_middle_action) middle_action = strdup(default_middle_action); if (default_right_action) right_action = strdup(default_right_action); /* Scan through the .rc files */ if (asprintf(&conffile, "/etc/wmtimerc") >= 0) { parse_rcfile(conffile, wmtime_keys); free(conffile); } if (asprintf(&conffile, "%s/.wmtimerc", getenv("HOME")) >= 0) { parse_rcfile(conffile, wmtime_keys); free(conffile); } if (asprintf(&conffile, "/etc/wmtimerc.fixed") >= 0) { parse_rcfile(conffile, wmtime_keys); free(conffile); } /* set user-defined colors */ if (color[0] != 0) { Window Root; XColor col; XWindowAttributes attributes; int screen; Pixel pixel; #define NUMSYMBOLS 10 XpmColorSymbol user_color[NUMSYMBOLS] = { {NULL, "#2081B2CAAEBA", 0}, /* O */ {NULL, "#000049244103", 0}, /* + */ {NULL, "#00007DF771C6", 0}, /* @ */ {NULL, "#18618A288617", 0}, /* # */ {NULL, "#18619A699658", 0}, /* ; */ {NULL, "#0820861779E7", 0}, /* : */ {NULL, "#000071C66185", 0}, /* > */ {NULL, "#000061855144", 0}, /* , */ {NULL, "#00004D344103", 0}, /* < */ {NULL, "#10407DF779E7", 0} /* 1 */ }; /* code based on GetColor() from wmgeneral.c */ /* we need a temporary display to parse the color */ display = XOpenDisplay(NULL); screen = DefaultScreen(display); Root = RootWindow(display, screen); XGetWindowAttributes(display, Root, &attributes); col.pixel = 0; if (!XParseColor(display, attributes.colormap, color, &col)) { fprintf(stderr, "wmtime: can't parse %s.\n", color); goto draw_window; } else if (!XAllocColor(display, attributes.colormap, &col)) { fprintf(stderr, "wmtime: can't allocate %s.\n", color); goto draw_window; } pixel = col.pixel; /* replace colors from wmtime-master.xpm */ user_color[0].pixel = pixel; user_color[1].pixel = scale_pixel(pixel, .4); user_color[2].pixel = scale_pixel(pixel, .7); user_color[3].pixel = scale_pixel(pixel, .8); user_color[4].pixel = scale_pixel(pixel, .9); user_color[5].pixel = scale_pixel(pixel, .8); user_color[6].pixel = scale_pixel(pixel, .6); user_color[7].pixel = scale_pixel(pixel, .5); user_color[8].pixel = scale_pixel(pixel, .4); user_color[9].pixel = scale_pixel(pixel, .7); wmgen.attributes.valuemask |= XpmColorSymbols; wmgen.attributes.numsymbols = NUMSYMBOLS; wmgen.attributes.colorsymbols = user_color; XCloseDisplay(display); } draw_window: openXwindow(argc, argv, wmtime_master_xpm, (char*)wmtime_mask_bits, 128, 64); /* Mask out the right parts of the clock */ copyXPMArea(0, 0, 128, 64, 0, 98); /* Draw the borders */ copyXPMArea(0, 0, 64, 64, 64, 0); /* Draw the clock face */ copyXPMArea(64, 98, 64, 64, 0, 0); /* Draw the LCD background */ setMaskXY(0, 0); /* add mouse region */ AddMouseRegion(0, 5, 48, 58, 60); AddMouseRegion(1, 5, 5, 58, 46); starttime = time(0); curtime = time(0); time_struct = localtime(&curtime); while (1) { curtime = time(0); waitpid(0, NULL, WNOHANG); time_struct = localtime(&curtime); if (curtime >= starttime) { if (!digital) { /* Now to update the seconds */ DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec); DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon); } else { DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec); DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon); } RedrawWindow(); } while (XPending(display)) { XNextEvent(display, &Event); switch (Event.type) { case Expose: RedrawWindow(); break; case DestroyNotify: XCloseDisplay(display); exit(0); break; case ButtonPress: but_stat = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); break; case ButtonRelease: i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); if (but_stat == i && but_stat >= 0) { switch (but_stat) { case 0: digital = 1-digital; if (digital) { copyXPMArea(64, 98, 64, 64, 0, 0); DrawTime(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec); DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon); } else { copyXPMArea(0, 98, 64, 64, 0, 0); DrawWijzer(time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec); DrawDate(time_struct->tm_wday, time_struct->tm_mday, time_struct->tm_mon); } RedrawWindow(); break; case 1: switch (Event.xbutton.button) { case 1: if (left_action) execCommand(left_action); break; case 2: if (middle_action) execCommand(middle_action); break; case 3: if (right_action) execCommand(right_action); break; } } } break; } } /* Sleep 0.3 seconds */ usleep(300000L); } } /*******************************************************************************\ |* DrawTime *| \*******************************************************************************/ void DrawTime(int hr, int min, int sec) { #define TIME_SIZE 16 char time[TIME_SIZE]; char *p = time; int i,j,k=6; int numfields; /* 7x13 */ if (noseconds) { snprintf(time, TIME_SIZE, "%02d:%02d ", hr, min); numfields = 2; } else { snprintf(time, TIME_SIZE, "%02d:%02d:%02d ", hr, min, sec); numfields = 3; } for (i=0; i < numfields; i++) { for (j=0; j<2; j++) { copyXPMArea((*p-'0')*7 + 1, 84, 8, 13, k, 18); k += 7; p++; } if (*p == ':') { copyXPMArea(71, 84, 5, 13, k, 18); k += 4; p++; } } } /*******************************************************************************\ |* DrawDate *| \*******************************************************************************/ void DrawDate(int wkday, int dom, int month) { #define DATE_SIZE 16 char date[DATE_SIZE]; char *p = date; int i,k; /* 7x13 */ snprintf(date, DATE_SIZE, "%.2s%02d%.3s ", day_of_week[wkday], dom, mon_of_year[month]); k = 5; for (i=0; i<2; i++) { if (*p < 'A') copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49); else copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49); k += 6; p++; } k = 23; for (i=0; i<2; i++) { copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49); k += 6; p++; } copyXPMArea(61, 64, 4, 9, k, 49); k += 4; for (i=0; i<3; i++) { if (*p < 'A') copyXPMArea((*p-'0')*6, 64, 6, 9, k, 49); else copyXPMArea((*p-'A')*6, 74, 6, 9, k, 49); k += 6; p++; } } /*******************************************************************************\ |* DrawWijzer *| \*******************************************************************************/ void DrawWijzer(int hr, int min, int sec) { double psi; int dx,dy; int x,y; int ddx,ddy; int adder; int k; int i; hr %= 12; copyXPMArea(5+64, 5, 54, 40, 5, 5); /**********************************************************************/ psi = hr * (M_PI / 6.0); psi += min * (M_PI / 360); dx = floor(sin(psi) * 22 * 0.7 + 0.5); dy = floor(-cos(psi) * 16 * 0.7 + 0.5); /* dx, dy is het punt waar we naar toe moeten. * Zoek alle punten die ECHT op de lijn liggen: */ ddx = 1; ddy = 1; if (dx < 0) ddx = -1; if (dy < 0) ddy = -1; x = 0; y = 0; if (abs(dx) > abs(dy)) { if (dy != 0) adder = abs(dx) / 2; else adder = 0; for (i=0; i abs(dy)) { if (dy != 0) adder = abs(dx) / 2; else adder = 0; for (i=0; i abs(dy)) { if (dy != 0) adder = abs(dx) / 2; else adder = 0; for (i=0; i