dockapps/wmitime/wmitime.c
Doug Torrance cc801880a5 wmitime: Improve locale support.
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.)
2014-12-20 09:55:06 +00:00

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);
}