cc801880a5
Previously, wmitime only had support for English, French, and (in Debian only) Hungarian. In addition, the choice was made at compile time. This patch adds run-time support for any language using the Latin alphabet. The locale is determined by the user's environment or may be specified on the command line with the "-l" option. Note that users whose environment specifies a non-Latin locale may wish to use, e.g., "-l C", as otherwise no date will appear. Note that, for simplicity, the month and day are now displayed as "01 JAN" as opposed to "JAN 01". (Previously, the former format was used for English and the latter for French.)
739 lines
14 KiB
C
739 lines
14 KiB
C
/*
|
|
|
|
wmitime.c -- internet time clock
|
|
|
|
by Dave Clark (clarkd@skynet.ca) (http://www.neotokyo.org/illusion)
|
|
|
|
This software is licensed through the GNU General Public Lisence.
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <locale.h>
|
|
#include <langinfo.h>
|
|
#include <iconv.h>
|
|
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include "wmgeneral/wmgeneral.h"
|
|
#include "wmgeneral/misc.h"
|
|
|
|
#include "wmitime-master.xpm"
|
|
char wmitime_mask_bits[64*64];
|
|
int wmitime_mask_width = 64;
|
|
int wmitime_mask_height = 64;
|
|
|
|
#define WMITIME_VERSION "0.1"
|
|
|
|
#define CHAR_WIDTH 5
|
|
#define CHAR_HEIGHT 7
|
|
|
|
#define BCHAR_WIDTH 6
|
|
#define BCHAR_HEIGHT 9
|
|
|
|
#define MY_PI (3.14159)
|
|
|
|
extern char **environ;
|
|
|
|
char *ProgName;
|
|
|
|
char uconfig_file[256];
|
|
char locale[256];
|
|
|
|
time_t curtime;
|
|
time_t prevtime;
|
|
|
|
int prevhourx=19;
|
|
int prevhoury=33;
|
|
int prevminx=19;
|
|
int prevminy=33;
|
|
|
|
static struct tm *clk;
|
|
|
|
int TwelveHour=0;
|
|
|
|
void usage(void);
|
|
void printversion(void);
|
|
void BlitString(char *name, int x, int y);
|
|
void BlitNum(int num, int x, int y);
|
|
void wmitime_routine(int, char **);
|
|
int PortWatch( short port );
|
|
int ReadConfigInt(FILE *fp, char *setting, int *value);
|
|
int ReadConfigString(FILE *fp, char *setting, char *value);
|
|
int Read_Config_File( char *filename );
|
|
void DrawInetTime(void);
|
|
void DrawStdTime(void);
|
|
void DrawDate(void);
|
|
void DrawInetWheel(void);
|
|
void DrawStdWheel(void);
|
|
void DrawLine(int x1, int y1, int x2, int y2, int sourcex, int sourcey);
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
int i;
|
|
|
|
uconfig_file[0] = 0;
|
|
locale[0] = 0;
|
|
|
|
/* Parse Command Line */
|
|
|
|
ProgName = argv[0];
|
|
if (strlen(ProgName) >= 5)
|
|
ProgName += (strlen(ProgName) - 5);
|
|
|
|
for (i=1; i<argc; i++) {
|
|
char *arg = argv[i];
|
|
|
|
if (*arg=='-') {
|
|
switch (arg[1]) {
|
|
case 'd' :
|
|
if (strcmp(arg+1, "display")) {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'g' :
|
|
if (strcmp(arg+1, "geometry")) {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'v' :
|
|
printversion();
|
|
exit(0);
|
|
break;
|
|
case 'c' :
|
|
if (argc > (i+1))
|
|
{
|
|
strcpy(uconfig_file, argv[i+1]);
|
|
i++;
|
|
}
|
|
break;
|
|
case '1' :
|
|
if (arg[2] == '2')
|
|
{
|
|
// Twelve-hour mode
|
|
TwelveHour = 1;
|
|
}
|
|
break;
|
|
case 'l' :
|
|
if (argc > (i+1))
|
|
{
|
|
strcpy(locale, argv[i+1]);
|
|
i++;
|
|
}
|
|
break;
|
|
default:
|
|
usage();
|
|
exit(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (setlocale(LC_ALL, locale) == NULL)
|
|
fprintf(stderr,
|
|
"warning: locale '%s' not recognized; defaulting to '%s'.",
|
|
locale, setlocale(LC_ALL, NULL));
|
|
|
|
wmitime_routine(argc, argv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************************\
|
|
|* wmitime_routine *|
|
|
\*******************************************************************************/
|
|
|
|
void wmitime_routine(int argc, char **argv)
|
|
{
|
|
int i;
|
|
XEvent Event;
|
|
int but_stat = -1;
|
|
|
|
|
|
// char config_file[512];
|
|
|
|
createXBMfromXPM(wmitime_mask_bits, wmitime_master_xpm, wmitime_mask_width, wmitime_mask_height);
|
|
|
|
openXwindow(argc, argv, wmitime_master_xpm, wmitime_mask_bits, wmitime_mask_width, wmitime_mask_height);
|
|
|
|
AddMouseRegion(0, 5, 6, 58, 16);
|
|
|
|
// We don't need a config file (yet)...
|
|
|
|
#if 0
|
|
// Read config file
|
|
|
|
if (uconfig_file[0] != 0)
|
|
{
|
|
// user-specified config file
|
|
fprintf(stderr, "Using user-specified config file '%s'.\n", uconfig_file);
|
|
Read_Config_File(uconfig_file);
|
|
}
|
|
else
|
|
{
|
|
sprintf(config_file, "%s/.wmitimerc", getenv("HOME"));
|
|
|
|
if (!Read_Config_File(config_file))
|
|
{
|
|
// Fall back to /etc/wminetrc
|
|
sprintf(config_file, "/etc/wmitimerc");
|
|
|
|
Read_Config_File(config_file);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
RedrawWindow();
|
|
|
|
prevtime = time(0) - 1;
|
|
|
|
while (1)
|
|
{
|
|
curtime = time(0);
|
|
|
|
if ( curtime > prevtime)
|
|
{
|
|
prevtime = curtime;
|
|
|
|
clk = localtime(&curtime);
|
|
|
|
// Update display
|
|
|
|
DrawInetTime();
|
|
|
|
DrawStdTime();
|
|
|
|
DrawInetWheel();
|
|
|
|
DrawDate();
|
|
|
|
DrawStdWheel();
|
|
|
|
RedrawWindow();
|
|
|
|
}
|
|
|
|
// X Events
|
|
while (XPending(display))
|
|
{
|
|
XNextEvent(display, &Event);
|
|
switch (Event.type)
|
|
{
|
|
case Expose:
|
|
RedrawWindow();
|
|
break;
|
|
case DestroyNotify:
|
|
XCloseDisplay(display);
|
|
exit(0);
|
|
break;
|
|
case ButtonPress:
|
|
i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
|
|
|
|
but_stat = i;
|
|
break;
|
|
case ButtonRelease:
|
|
i = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y);
|
|
|
|
if (but_stat == i && but_stat >= 0)
|
|
{
|
|
switch (but_stat)
|
|
{
|
|
case 0 :
|
|
TwelveHour = (!TwelveHour);
|
|
prevtime--;
|
|
break;
|
|
case 1 :
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
|
|
}
|
|
}
|
|
but_stat = -1;
|
|
// RedrawWindow();
|
|
break;
|
|
}
|
|
}
|
|
|
|
usleep(100000);
|
|
}
|
|
}
|
|
|
|
|
|
void DrawInetTime(void)
|
|
{
|
|
int iTime;
|
|
|
|
// Compute Inet Time
|
|
iTime=(clk->tm_hour*3600+clk->tm_min*60+clk->tm_sec);
|
|
iTime=iTime+((timezone-1)+3600);
|
|
if (clk->tm_isdst)
|
|
iTime-=3600;
|
|
iTime=(iTime*1000)/86400;
|
|
|
|
if (iTime >= 1000)
|
|
iTime-=1000;
|
|
else
|
|
if (iTime < 0)
|
|
iTime+=1000;
|
|
|
|
// Blit it
|
|
|
|
BlitNum(iTime, 38, 18);
|
|
|
|
}
|
|
|
|
void DrawStdTime(void)
|
|
{
|
|
int xoff=0, yoff=0;
|
|
int srcx=0, srcy=0;
|
|
int i,j;
|
|
char blitstr[32];
|
|
int len;
|
|
|
|
i = clk->tm_hour;
|
|
|
|
if (TwelveHour)
|
|
{
|
|
if (i > 12)
|
|
i-=12;
|
|
|
|
if (i==0)
|
|
i=12;
|
|
|
|
sprintf(blitstr, "%2i:%02i:%02i", i, clk->tm_min, clk->tm_sec);
|
|
}
|
|
else
|
|
{
|
|
sprintf(blitstr, "%02i:%02i:%02i", i, clk->tm_min, clk->tm_sec);
|
|
}
|
|
|
|
|
|
|
|
len = strlen(blitstr);
|
|
|
|
// Set starting co-ordinates...
|
|
xoff = 6;
|
|
yoff = 6;
|
|
|
|
// Blit it.
|
|
for( i=0; i<len; i++)
|
|
{
|
|
if (blitstr[i] == ':')
|
|
{
|
|
copyXPMArea(138, 23, 4, BCHAR_HEIGHT, xoff, yoff);
|
|
xoff+=4;
|
|
}
|
|
else if (isdigit(blitstr[i]))
|
|
{
|
|
j = blitstr[i] - '0';
|
|
srcx = 68;
|
|
srcy = 23;
|
|
|
|
while (j)
|
|
{
|
|
j--;
|
|
srcx += (BCHAR_WIDTH + 1);
|
|
}
|
|
|
|
copyXPMArea(srcx, srcy, BCHAR_WIDTH+1, BCHAR_HEIGHT, xoff, yoff);
|
|
xoff+=(BCHAR_WIDTH + 1);
|
|
}
|
|
else
|
|
{
|
|
copyXPMArea(66, 10, BCHAR_WIDTH+1, BCHAR_HEIGHT, xoff, yoff);
|
|
xoff+=(BCHAR_WIDTH + 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void DrawDate(void)
|
|
{
|
|
char OrigBlitStr[20], BlitStr[20];
|
|
char *inbuf, *outbuf;
|
|
size_t inbytesleft, outbytesleft;
|
|
iconv_t cd;
|
|
|
|
cd = iconv_open("ASCII//TRANSLIT", nl_langinfo(CODESET));
|
|
|
|
inbuf = OrigBlitStr;
|
|
outbuf = BlitStr;
|
|
inbytesleft = sizeof OrigBlitStr;
|
|
outbytesleft = sizeof BlitStr;
|
|
|
|
sprintf(OrigBlitStr, "%s", nl_langinfo(ABDAY_1 + clk->tm_wday));
|
|
iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
|
|
BlitStr[2] = 0;
|
|
BlitString( BlitStr, 6, 50);
|
|
|
|
inbuf = OrigBlitStr;
|
|
outbuf = BlitStr;
|
|
inbytesleft = sizeof OrigBlitStr;
|
|
outbytesleft = sizeof BlitStr;
|
|
|
|
sprintf(OrigBlitStr, "%s", nl_langinfo(ABMON_1 + clk->tm_mon));
|
|
iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
|
|
BlitStr[3] = 0;
|
|
BlitString( BlitStr, 40, 50);
|
|
|
|
iconv_close(cd);
|
|
|
|
sprintf(BlitStr, "%02i", clk->tm_mday);
|
|
BlitString( BlitStr, 25, 50);
|
|
}
|
|
|
|
void DrawInetWheel(void)
|
|
{
|
|
int WheelPos=0;
|
|
int i;
|
|
int xoff=0, yoff=0;
|
|
int iTime;
|
|
|
|
// Calculate Wheel Position...
|
|
iTime=(clk->tm_hour*3600+clk->tm_min*60+clk->tm_sec);
|
|
iTime=iTime+((timezone-1)+3600);
|
|
if (clk->tm_isdst)
|
|
iTime-=3600;
|
|
iTime=(iTime*1000)/8640;
|
|
|
|
if (iTime >= 10000)
|
|
iTime-=10000;
|
|
else
|
|
if (iTime < 0)
|
|
iTime+=10000;
|
|
|
|
iTime %= 10;
|
|
|
|
WheelPos = floor( (iTime *8) / 10);
|
|
|
|
// Draw the Wheel...
|
|
i=WheelPos;
|
|
yoff=35;
|
|
xoff=67;
|
|
|
|
xoff+=19;
|
|
|
|
while(i)
|
|
{
|
|
xoff +=19;
|
|
i--;
|
|
}
|
|
|
|
copyXPMArea(xoff, yoff, 19, 19, 39, 29);
|
|
|
|
}
|
|
|
|
|
|
void DrawStdWheel(void)
|
|
{
|
|
//19x33 = center
|
|
//radius of 14
|
|
|
|
int sx, sy;
|
|
int cx, cy;
|
|
int dx, dy;
|
|
int hr;
|
|
double psi;
|
|
|
|
cx=19;
|
|
cy=33;
|
|
|
|
sx = 2;
|
|
sy = 97;
|
|
|
|
// Hour Hand...
|
|
|
|
DrawLine(cx, cy, prevhourx, prevhoury, 66, 9); // erase old line
|
|
|
|
hr = (clk->tm_hour % 12);
|
|
|
|
psi = hr * (M_PI / 6.0);
|
|
psi += clk->tm_min * (M_PI / 360);
|
|
|
|
dx = floor(sin(psi) * 22 * 0.5 + 0.5);
|
|
dy = floor(-cos(psi) * 16 * 0.5 + 0.5);
|
|
|
|
dx += cx;
|
|
dy += cy;
|
|
|
|
prevhourx=dx;
|
|
prevhoury=dy;
|
|
|
|
DrawLine(cx, cy, dx, dy, sx, sy);
|
|
|
|
// Minute Hand...
|
|
|
|
DrawLine(cx, cy, prevminx, prevminy, 66, 9); // erase old line
|
|
|
|
cx=19;
|
|
cy=33;
|
|
sx = 2;
|
|
sy = 96;
|
|
|
|
psi = clk->tm_min * (M_PI / 30.0);
|
|
psi += clk->tm_sec * (M_PI / 1800);
|
|
|
|
dx = floor(sin(psi) * 22 * 0.7 + 0.5);
|
|
dy = floor(-cos(psi) * 16 * 0.7 + 0.5);
|
|
|
|
dx += cx;
|
|
dy += cy;
|
|
|
|
prevminx = dx;
|
|
prevminy = dy;
|
|
|
|
|
|
DrawLine(cx, cy, dx, dy, sx, sy);
|
|
}
|
|
|
|
void DrawLine(int x1, int y1, int x2, int y2, int sourcex, int sourcey)
|
|
{
|
|
int x, y;
|
|
int deltax, deltay;
|
|
int xs, ys;
|
|
|
|
float xd=0, yd=0;
|
|
float xi, yi;
|
|
|
|
x = x1;
|
|
y = y1;
|
|
|
|
|
|
if ( (x2-x1) < 0)
|
|
xs = -1;
|
|
else
|
|
xs = 1;
|
|
|
|
if ( (y2-y1) < 0)
|
|
ys = -1;
|
|
else
|
|
ys = 1;
|
|
|
|
deltax = abs( x2 - x1 );
|
|
deltay = abs( y2 - y1 );
|
|
|
|
if (deltay !=0)
|
|
xi = (float) ((float)deltax / (float) deltay);
|
|
else
|
|
xi=0;
|
|
|
|
if (deltax !=0)
|
|
yi = (float) ((float)deltay / (float) deltax);
|
|
else
|
|
yi=0;
|
|
|
|
if ( deltax > deltay )
|
|
{
|
|
for (x=x1; x!= x2; x+= xs)
|
|
{
|
|
yd += yi;
|
|
y += (int) (yd * ys);
|
|
|
|
copyXPMArea(sourcex, sourcey, 1, 1, x, y);
|
|
|
|
yd -= (int) yd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (y=y1; y!= y2; y+= ys)
|
|
{
|
|
xd += xi;
|
|
x += (int) (xd * xs);
|
|
|
|
copyXPMArea(sourcex, sourcey, 1, 1, x, y);
|
|
|
|
xd -= (int) xd;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Blits a string at given co-ordinates
|
|
void BlitString(char *name, int x, int y)
|
|
{
|
|
int i;
|
|
int c;
|
|
int k;
|
|
|
|
k = x;
|
|
for (i=0; name[i]; i++)
|
|
{
|
|
|
|
c = toupper(name[i]);
|
|
if (c >= 'A' && c <= 'Z')
|
|
{ // its a letter
|
|
c -= 'A';
|
|
copyXPMArea(c * 6, 74, 6, 8, k, y);
|
|
k += 6;
|
|
}
|
|
else
|
|
{ // its a number or symbol
|
|
c -= '0';
|
|
copyXPMArea(c * 6, 64, 6, 8, k, y);
|
|
k += 6;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void BlitNum(int num, int x, int y)
|
|
{
|
|
char buf[1024];
|
|
int newx=x;
|
|
|
|
sprintf(buf, "%03i", num);
|
|
|
|
BlitString(buf, newx, y);
|
|
}
|
|
|
|
|
|
// ReadConfigSetting
|
|
int ReadConfigString(FILE *fp, char *setting, char *value)
|
|
{
|
|
char str[1024];
|
|
char buf[1024];
|
|
int i;
|
|
int len;
|
|
int slen;
|
|
char *p=NULL;
|
|
|
|
|
|
if (!fp)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
sprintf(str, "%s=", setting);
|
|
slen = strlen(str);
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
while ( !feof(fp) )
|
|
{
|
|
|
|
if (!fgets(buf, 512, fp))
|
|
break;
|
|
|
|
len = strlen(buf);
|
|
|
|
// strip linefeed
|
|
for (i=0; i!=len; i++)
|
|
{
|
|
if (buf[i] == '\n')
|
|
{
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
|
|
//printf("Scanning '%s'...\n", buf);
|
|
if ( strncmp(buf, str, strlen(str)) == 0)
|
|
{
|
|
// found our setting
|
|
|
|
for(i=0; i!=slen; i++)
|
|
{
|
|
if ( buf[i] == '=' )
|
|
{
|
|
p=buf+i+1;
|
|
strcpy(value, p);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ReadConfigInt(FILE *fp, char *setting, int *value)
|
|
{
|
|
char buf[1024];
|
|
|
|
if (ReadConfigString(fp, setting, (char *) &buf))
|
|
{
|
|
*value = atoi(buf);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Read_Config_File( char *filename )
|
|
{
|
|
FILE *fp;
|
|
|
|
fp = fopen(filename, "r");
|
|
if (fp)
|
|
{
|
|
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
perror("Read_Config_File");
|
|
fprintf(stderr, "Unable to open %s, no settings read.\n", filename);
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************\
|
|
|* usage *|
|
|
\*******************************************************************************/
|
|
|
|
void usage(void)
|
|
{
|
|
fprintf(stderr, "\nWMiTIME - illusion <clarkd@skynet.ca> http://www.neotokyo.org/illusion\n\n");
|
|
fprintf(stderr, "usage:\n");
|
|
fprintf(stderr, " -12 12-hour mode\n");
|
|
fprintf(stderr, " -display <display name>\n");
|
|
fprintf(stderr, " -geometry +XPOS+YPOS initial window position\n");
|
|
// fprintf(stderr, " -c <filename> use specified config file\n");
|
|
fprintf(stderr, " -l <locale> specify locale\n");
|
|
fprintf(stderr, " -h this help screen\n");
|
|
fprintf(stderr, " -v print the version number\n");
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
/*******************************************************************************\
|
|
|* printversion *|
|
|
\*******************************************************************************/
|
|
|
|
void printversion(void)
|
|
{
|
|
fprintf(stderr, "wmitime v%s\n", WMITIME_VERSION);
|
|
}
|