#include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "data.h" static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *BorderColor: white\n\ *BorderWidth: 0\n\ "; static char *displayname; static char *geometryspec; static char *foreground; static char *background; static char *bordercstr; static char *borderwstr; static char *skinname; static int debug; static int argc; static char **argv; static Display *disp; static Screen *scr; static Visual *vis; static int scrwidth; static int scrheight; static int depth; static Window rootwin; static Colormap defcmap; static GC defgc; static GC gc1; static XColor fgcolor; static XColor bgcolor; static XColor bdcolor; static int borderwidth; static Window topwin; static Window win; static GC wingc; static int winx; static int winy; static int winw; static int winh; static XTextProperty wn_prop; static XTextProperty in_prop; static XSizeHints normal_hints; static XWMHints wm_hints; static XClassHint class_hints; static const SKIN *skin; static int (*prev_io_error)(Display *); static int (*prev_error)(Display *, XErrorEvent *); typedef struct hms HMS; typedef struct tmrstate TMRSTATE; typedef struct clkstate CLKSTATE; typedef struct chrstate CHRSTATE; typedef struct almstate ALMSTATE; struct hms { int hr; int mn; int sc; } ; struct tmrstate { HMS cur; HMS mem; #define TS_IDLE 1 /* adjusting time value, nothing else happening */ #define TS_DOWN 2 /* counting down */ #define TS_PAUSE 3 /* countdown paused */ #define TS_ALERT 4 /* beeping, counting up */ #define TS_QUIET 5 /* alert quelled, can summon memory */ int state; int halftick; struct timeval tick; } ; struct clkstate { HMS cur; int halftick; struct timeval tick; } ; struct chrstate { HMS cur; #define CHS_STOPPED 1 #define CHS_RUNNING 2 int state; struct timeval offset; struct timeval curtv; struct timeval tick; } ; struct almstate { HMS cur; int armed; } ; static TMRSTATE tmr; static CLKSTATE clk; static CHRSTATE chr; static ALMSTATE alm; #define D_TMR 1 #define D_CLK 2 #define D_CHR 3 #define D_ALM 4 static int dsp; static HMS *adj; static int adjvis; static int adj_wrap; static int havenow; static struct timeval now; typedef struct pm PM; struct pm { Pixmap pm; } ; static PM pm_face; static PM pm_hr_digs[10]; static PM pm_colon; static PM pm_mn_digs[10]; static PM pm_sc_digs[10]; static PM pm_updn; static PM pm_clock; static PM pm_timer; static PM pm_chron; static PM pm_alarm; static char *deconst(const char *s) { char *rv; bcopy(&s,&rv,sizeof(rv)); return(rv); } static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = (char **) malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;i 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",argv[0],*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",argv[0],*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg")) { WANTARG(); foreground = av[skip]; continue; } if (!strcmp(*av,"-background") || !strcmp(*av,"-bg")) { WANTARG(); background = av[skip]; continue; } if (!strcmp(*av,"-bordercolor") || !strcmp(*av,"-bd")) { WANTARG(); bordercstr = av[skip]; continue; } if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-skin")) { WANTARG(); skinname = av[skip]; continue; } if (!strcmp(*av,"-debug")) { debug = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",argv[0],*av); errs ++; } if (errs) { exit(1); } } static void setup_db(void) { char *str; char *home; char hostname[256]; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } home = getenv("HOME"); if (home) { str = malloc(strlen(home)+1+10+1); sprintf(str,"%s/.Xdefaults",home); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); gethostname(&hostname[0],(sizeof(hostname)/sizeof(hostname[0]))-1); hostname[(sizeof(hostname)/sizeof(hostname[0]))-1] = '\0'; str = malloc(strlen(home)+1+11+strlen(&hostname[0])+1); sprintf(str,"%s/.Xdefaults-%s",home,&hostname[0]); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); } } static void maybeset(char **strp, char *str) { if (str && !*strp) *strp = str; } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; if (XrmGetResource(db,name,class,&type,&value) == False) return(0); return(value.addr); } static void setup_color(char *str, XColor *col) { if (XParseColor(disp,defcmap,str,col) == 0) { fprintf(stderr,"%s: bad color `%s'\n",__progname,str); exit(1); } if (XAllocColor(disp,defcmap,col) == 0) { fprintf(stderr,"%s: can't allocate colormap cell for color `%s'\n",__progname,str); exit(1); } } static void setup_colors(void) { setup_color(foreground,&fgcolor); setup_color(background,&bgcolor); setup_color(bordercstr,&bdcolor); } static void setup_state(void) { tmr.cur.hr = 0; tmr.cur.mn = 0; tmr.cur.sc = 0; tmr.mem = tmr.cur; tmr.state = TS_IDLE; chr.cur.hr = 0; chr.cur.mn = 0; chr.cur.sc = 0; chr.curtv.tv_sec = 0; chr.curtv.tv_usec = 0; chr.state = CHS_STOPPED; dsp = D_TMR; } static void setup_numbers(void) { if (borderwstr) borderwidth = atoi(borderwstr); } static void expand_rle(const unsigned char *rle, unsigned char *exp, int w, int h) { int y; int x; int b; int bit; int n; unsigned char ch; b = 1; n = 0; bit = 0x80; ch = 0; y = 0; x = 0; while (1) { if (n < 1) { b = ! b; n = *rle++; continue; } if (b) ch |= bit; bit >>= 1; n --; x ++; if ((bit == 0) || (x == w)) { *exp++ = ch; bit = 0x80; ch = 0; } if (x >= w) { x = 0; y ++; if (y >= h) break; } } } static void setup_pm(PM *p, int w, int h, const unsigned char *bits) { unsigned char *xbits; XImage *i; xbits = malloc(((w+7)>>3)*h); expand_rle(bits,xbits,w,h); i = XCreateImage(disp,vis,1,XYBitmap,0,xbits,w,h,8,(w+7)>>3); i->bitmap_unit = 8; i->bitmap_bit_order = MSBFirst; p->pm = XCreatePixmap(disp,rootwin,w,h,1); XPutImage(disp,p->pm,gc1,i,0,0,0,0,w,h); XDestroyImage(i); /* also frees xbits (!) */ } static void setup_pixmaps(void) { int i; setup_pm(&pm_face,skin->face_wh.w,skin->face_wh.h,skin->face_bits); setup_pm(&pm_colon,skin->colon_wh.w,skin->colon_wh.h,skin->colon_bits); setup_pm(&pm_updn,skin->updn_wh.w,skin->updn_wh.h,skin->updn_bits); for (i=0;i<10;i++) { setup_pm(&pm_hr_digs[i],skin->hr_wh.w,skin->hr_wh.h,skin->hr_bits[i]); setup_pm(&pm_mn_digs[i],skin->mn_wh.w,skin->mn_wh.h,skin->mn_bits[i]); setup_pm(&pm_sc_digs[i],skin->sc_wh.w,skin->sc_wh.h,skin->sc_bits[i]); } setup_pm(&pm_clock,skin->modedisp_wh.w,skin->modedisp_wh.h,skin->modedisp_bits_clock); setup_pm(&pm_timer,skin->modedisp_wh.w,skin->modedisp_wh.h,skin->modedisp_bits_timer); setup_pm(&pm_chron,skin->modedisp_wh.w,skin->modedisp_wh.h,skin->modedisp_bits_chron); setup_pm(&pm_alarm,skin->modedisp_wh.w,skin->modedisp_wh.h,skin->modedisp_bits_alarm); } static void setup_window(void) { int x; int y; int w; int h; int bits; unsigned long int attrmask; XSetWindowAttributes attr; unsigned long int gcvalmask; XGCValues gcval; w = skin->face_wh.w + (borderwidth * 2); h = skin->face_wh.h + (borderwidth * 2); x = (scrwidth - w) / 2; y = (scrheight - h) / 2; bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = scrwidth + x - w; if (bits & YNegative) y = scrheight + y - h; attrmask = 0; attr.background_pixel = bgcolor.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolor.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = StructureNotifyMask; attrmask |= CWEventMask; attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; attrmask |= CWDontPropagate; winx = x; winy = y; winw = w; winh = h; w -= 2 * borderwidth; h -= 2 * borderwidth; topwin = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,CopyFromParent,attrmask,&attr); wn_prop.value = (unsigned char *) deconst("xtimer"); wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen(wn_prop.value); in_prop.value = (unsigned char *) deconst("xtimer"); in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen(in_prop.value); normal_hints.flags = PMinSize | PResizeInc; normal_hints.x = x; normal_hints.y = y; normal_hints.flags |= (bits & (XValue|YValue)) ? USPosition : PPosition; normal_hints.width = w; normal_hints.height = h; normal_hints.flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize; normal_hints.min_width = w; normal_hints.min_height = h; normal_hints.width_inc = 1; normal_hints.height_inc = 1; wm_hints.flags = InputHint; wm_hints.input = False; class_hints.res_name = deconst("xtimer"); class_hints.res_class = deconst("Random"); XSetWMProperties(disp,topwin,&wn_prop,&in_prop,argv,argc,&normal_hints,&wm_hints,&class_hints); gcvalmask = 0; gcval.foreground = fgcolor.pixel; gcvalmask |= GCForeground; gcval.background = bgcolor.pixel; gcvalmask |= GCBackground; wingc = XCreateGC(disp,topwin,gcvalmask,&gcval); attrmask = 0; attr.background_pixel = bgcolor.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask|ButtonPressMask; attrmask |= CWEventMask; win = XCreateWindow(disp,topwin,0,0,skin->face_wh.w,skin->face_wh.h,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapWindow(disp,win); XMapRaised(disp,topwin); } static int ioerror_handler(Display *d) { return((*prev_io_error)(d)); } static int error_handler(Display *d, XErrorEvent *e) { return((*prev_error)(d,e)); } static void setup_error(void) { prev_error = XSetErrorHandler(error_handler); prev_io_error = XSetIOErrorHandler(ioerror_handler); } static void getnow(void) { if (havenow) return; gettimeofday(&now,0); } __inline__ static HMS cur(void) { switch (dsp) { case D_TMR: return(tmr.cur); break; case D_CLK: return(clk.cur); break; case D_CHR: return(chr.cur); break; case D_ALM: return(alm.cur); break; } abort(); } static void draw_hr10(void) { int v; v = cur().hr; if (v / 10) { XCopyPlane(disp,pm_hr_digs[v/10].pm,win,defgc,0,0,skin->hr_wh.w,skin->hr_wh.h,skin->hr_10_xy.x,skin->hr_10_xy.y,1); } else { XClearArea(disp,win,skin->hr_10_xy.x,skin->hr_10_xy.y,skin->hr_wh.w,skin->hr_wh.h,False); } } static void draw_hr1(void) { XCopyPlane(disp,pm_hr_digs[cur().hr%10].pm,win,defgc,0,0,skin->hr_wh.w,skin->hr_wh.h,skin->hr_1_xy.x,skin->hr_1_xy.y,1); } static void draw_mn10(void) { XCopyPlane(disp,pm_mn_digs[cur().mn/10].pm,win,defgc,0,0,skin->mn_wh.w,skin->mn_wh.h,skin->mn_10_xy.x,skin->mn_10_xy.y,1); } static void draw_mn1(void) { XCopyPlane(disp,pm_mn_digs[cur().mn%10].pm,win,defgc,0,0,skin->mn_wh.w,skin->mn_wh.h,skin->mn_1_xy.x,skin->mn_1_xy.y,1); } static void draw_sc10(void) { switch (dsp) { default: XCopyPlane(disp,pm_sc_digs[cur().sc/10].pm,win,defgc,0,0,skin->sc_wh.w,skin->sc_wh.h,skin->sc_10_xy.x,skin->sc_10_xy.y,1); break; case D_ALM: XClearArea(disp,win,skin->sc_10_xy.x,skin->sc_10_xy.y,skin->sc_wh.w,skin->sc_wh.h,False); break; } } static void draw_sc1(void) { switch (dsp) { default: XCopyPlane(disp,pm_sc_digs[cur().sc%10].pm,win,defgc,0,0,skin->sc_wh.w,skin->sc_wh.h,skin->sc_1_xy.x,skin->sc_1_xy.y,1); break; case D_ALM: XClearArea(disp,win,skin->sc_1_xy.x,skin->sc_1_xy.y,skin->sc_wh.w,skin->sc_wh.h,False); break; } } static void draw_colon(void) { int prs; prs = 1; switch (dsp) { case D_TMR: switch (tmr.state) { case TS_DOWN: case TS_ALERT: prs = ! tmr.halftick; break; } break; case D_CLK: prs = ! clk.halftick; break; case D_CHR: switch (chr.state) { case CHS_RUNNING: prs = (chr.curtv.tv_usec >= 500000); break; } break; case D_ALM: prs = alm.armed; break; default: abort(); break; } if (prs) { XCopyPlane(disp,pm_colon.pm,win,defgc,0,0,skin->colon_wh.w,skin->colon_wh.h,skin->colon_xy.x,skin->colon_xy.y,1); } else { XClearArea(disp,win,skin->colon_xy.x,skin->colon_xy.y,skin->colon_wh.w,skin->colon_wh.h,False); } } static void draw_updn(void) { switch (dsp) { case D_TMR: case D_CHR: case D_ALM: XCopyPlane(disp,pm_updn.pm,win,defgc,0,0,skin->updn_wh.w,skin->updn_wh.h,skin->updn_xy.x,skin->updn_xy.y,1); break; case D_CLK: XClearArea(disp,win,skin->updn_xy.x,skin->updn_xy.y,skin->updn_wh.w,skin->updn_wh.h,False); break; default: abort(); break; } } static void draw_mode(void) { Pixmap pm; switch (dsp) { case D_TMR: pm = pm_timer.pm; break; case D_CLK: pm = pm_clock.pm; break; case D_CHR: pm = pm_chron.pm; break; case D_ALM: pm = pm_alarm.pm; break; } XCopyPlane(disp,pm,win,defgc,0,0,skin->modedisp_wh.w,skin->modedisp_wh.h,skin->modedisp_xy.x,skin->modedisp_xy.y,1); } static void draw_all(void) { draw_hr10(); draw_hr1(); draw_mn10(); draw_mn1(); draw_sc10(); draw_sc1(); draw_colon(); draw_updn(); draw_mode(); } static void redisplay(void) { XSetForeground(disp,defgc,fgcolor.pixel); XSetBackground(disp,defgc,bgcolor.pixel); XCopyPlane(disp,pm_face.pm,win,defgc,0,0,skin->face_wh.w,skin->face_wh.h,0,0,1); draw_all(); } static void sub3tv(struct timeval *a, struct timeval *b, struct timeval *c) { if (a->tv_usec >= b->tv_usec) { c->tv_sec = a->tv_sec - b->tv_sec; c->tv_usec = a->tv_usec - b->tv_usec; } else { c->tv_sec = a->tv_sec - 1 - b->tv_sec; c->tv_usec = a->tv_usec + 1000000 - b->tv_usec; } } #if 0 static void add3tv(struct timeval *a, struct timeval *b, struct timeval *c) { c->tv_sec = a->tv_sec + b->tv_sec; c->tv_usec = a->tv_usec + b->tv_usec; if (c->tv_usec >= 1000000) { c->tv_sec ++; c->tv_usec -= 1000000; } } #endif static void chr_curtv_to_cur(void) { chr.cur.hr = (chr.curtv.tv_sec / 3600) % 100; chr.cur.mn = (chr.curtv.tv_sec / 60) % 60; chr.cur.sc = chr.curtv.tv_sec % 60; } static void chr_cur_to_curtv(void) { chr.curtv.tv_sec = chr.cur.sc + (60 * chr.cur.mn) + (3600 * chr.cur.hr); chr.curtv.tv_usec = 0; } static void inctv(struct timeval *tv, unsigned long int usec) { if (usec >= 1000000) { int s; s = usec / 1000000; tv->tv_sec += s; tv->tv_usec += usec - (1000000 * s); } else { tv->tv_usec += usec; } if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec ++; } } static void inctick(struct timeval *tv) { if (tv->tv_usec >= 500000) { tv->tv_usec -= 500000; tv->tv_sec ++; } else { tv->tv_usec += 500000; } } static void chr_start(void) { chr.state = CHS_RUNNING; getnow(); chr.tick = now; if (chr.curtv.tv_usec >= 500000) { inctv(&chr.tick,1000000-chr.curtv.tv_usec); } else { inctv(&chr.tick,500000-chr.curtv.tv_usec); } sub3tv(&now,&chr.curtv,&chr.offset); } static void draw_diffs(HMS *cur, HMS *prev) { if (cur->hr != prev->hr) { if ((cur->hr/10) != (prev->hr/10)) draw_hr10(); if ((cur->hr%10) != (prev->hr%10)) draw_hr1(); } if (cur->mn != prev->mn) { if ((cur->mn/10) != (prev->mn/10)) draw_mn10(); if ((cur->mn%10) != (prev->mn%10)) draw_mn1(); } if (cur->sc != prev->sc) { if ((cur->sc/10) != (prev->sc/10)) draw_sc10(); if ((cur->sc%10) != (prev->sc%10)) draw_sc1(); } } static void chr_stop(void) { HMS prev; chr.state = CHS_STOPPED; getnow(); sub3tv(&now,&chr.offset,&chr.curtv); prev = chr.cur; chr_curtv_to_cur(); if (dsp == D_CHR) draw_diffs(&chr.cur,&prev); } static void timeadjust_pre(void) { switch (dsp) { case D_TMR: adj = &tmr.cur; if (tmr.state != TS_IDLE) { tmr.state = TS_IDLE; draw_colon(); } adj_wrap = 0; break; case D_CHR: adj = &chr.cur; if (chr.state == CHS_RUNNING) { chr_stop(); draw_colon(); } adj_wrap = 0; break; case D_ALM: adj = &alm.cur; adj_wrap = 1; break; default: adj = 0; break; } adjvis = 1; } static void timeadjust_post(void) { switch (dsp) { case D_CHR: chr_cur_to_curtv(); break; case D_ALM: if (adj->hr > 23) { if (adj->hr > 70) { adj->hr -= 100-24; } else { adj->hr -= 24; } if (adjvis) { draw_hr1(); draw_hr10(); } } default: adj = 0; break; } } static int adj_hr_inc(void) { if (adj->hr <= 98) { adj->hr ++; if (adjvis) { draw_hr1(); if ((adj->hr % 10) == 0) draw_hr10(); } return(1); } else if (adj_wrap) { adj->hr = 0; if (adjvis) { draw_hr1(); draw_hr10(); } return(1); } return(0); } static int adj_hr_dec(void) { if (adj->hr > 0) { adj->hr --; if (adjvis) { draw_hr1(); if ((adj->hr % 10) == 9) draw_hr10(); } return(1); } else if (adj_wrap) { adj->hr = 99; if (adjvis) { draw_hr1(); draw_hr10(); } return(1); } return(0); } static int adj_mn_inc(void) { if (adj->mn <= 58) { adj->mn ++; if (adjvis) { draw_mn1(); if ((adj->mn % 10) == 0) draw_mn10(); } return(1); } else if (adj_hr_inc()) { adj->mn = 0; if (adjvis) { draw_mn10(); draw_mn1(); } return(1); } return(0); } static int adj_mn_dec(void) { if (adj->mn > 0) { adj->mn --; if (adjvis) { draw_mn1(); if ((adj->mn % 10) == 9) draw_mn10(); } return(1); } else if (adj_hr_dec()) { adj->mn = 59; if (adjvis) { draw_mn10(); draw_mn1(); } return(1); } return(0); } static int adj_sc_inc(void) { if (adj->sc <= 58) { adj->sc ++; if (adjvis) { draw_sc1(); if ((adj->sc % 10) == 0) draw_sc10(); } return(1); } else if (adj_mn_inc()) { adj->sc = 0; if (adjvis) { draw_sc10(); draw_sc1(); } return(1); } return(0); } static int adj_sc_dec(void) { if (adj->sc > 0) { adj->sc --; if (adjvis) { draw_sc1(); if ((adj->sc % 10) == 9) draw_sc10(); } return(1); } else if (adj_mn_dec()) { adj->sc = 59; if (adjvis) { draw_sc10(); draw_sc1(); } return(1); } return(0); } static void hr_10_inc(void) { if (adj->hr <= 89) { adj->hr += 10; if (adjvis) draw_hr10(); } } static void hr_10_dec(void) { if (adj->hr >= 10) { adj->hr -= 10; if (adjvis) draw_hr10(); } } static void hr_1_inc(void) { adj_hr_inc(); } static void hr_1_dec(void) { adj_hr_dec(); } static void mn_10_inc(void) { if (adj->mn <= 49) { adj->mn += 10; if (adjvis) draw_mn10(); } else if (adj_hr_inc()) { adj->mn -= 50; if (adjvis) draw_mn10(); } } static void mn_10_dec(void) { if (adj->mn >= 10) { adj->mn -= 10; if (adjvis) draw_mn10(); } else if (adj_hr_dec()) { adj->mn += 50; if (adjvis) draw_mn10(); } } static void mn_1_inc(void) { adj_mn_inc(); } static void mn_1_dec(void) { adj_mn_dec(); } static void sc_10_inc(void) { if (dsp == D_ALM) return; if (adj->sc <= 49) { adj->sc += 10; if (adjvis) draw_sc10(); } else if (adj_mn_inc()) { adj->sc -= 50; if (adjvis) draw_sc10(); } } static void sc_10_dec(void) { if (dsp == D_ALM) return; if (adj->sc >= 10) { adj->sc -= 10; if (adjvis) draw_sc10(); } else if (adj_mn_dec()) { adj->sc += 50; if (adjvis) draw_sc10(); } } static void sc_1_inc(void) { if (dsp == D_ALM) return; adj_sc_inc(); } static void sc_1_dec(void) { if (dsp == D_ALM) return; adj_sc_dec(); } static void clk_setcur(void) { time_t t; struct tm *tm; getnow(); t = now.tv_sec; tm = localtime(&t); clk.cur.hr = tm->tm_hour; clk.cur.mn = tm->tm_min; clk.cur.sc = tm->tm_sec; } static void start_clock(void) { getnow(); if (now.tv_usec < 500000) { clk.tick.tv_sec = now.tv_sec; clk.tick.tv_usec = 500000; clk.halftick = 1; } else { clk.tick.tv_sec = now.tv_sec + 1; clk.tick.tv_usec = 0; clk.halftick = 0; } clk_setcur(); } static void start_stop(void) { switch (dsp) { case D_TMR: switch (tmr.state) { case TS_IDLE: if (tmr.cur.hr || tmr.cur.mn || tmr.cur.sc) { tmr.mem = tmr.cur; tmr.state = TS_DOWN; getnow(); tmr.tick = now; tmr.halftick = 1; inctick(&tmr.tick); draw_colon(); } break; case TS_DOWN: tmr.state = TS_PAUSE; draw_colon(); break; case TS_PAUSE: tmr.state = TS_DOWN; getnow(); tmr.tick = now; tmr.halftick = 1; inctick(&tmr.tick); draw_colon(); break; case TS_ALERT: tmr.state = TS_QUIET; draw_colon(); break; case TS_QUIET: tmr.state = TS_IDLE; tmr.cur = tmr.mem; draw_all(); break; default: abort(); break; } break; case D_CHR: switch (chr.state) { case CHS_STOPPED: chr_start(); draw_colon(); break; case CHS_RUNNING: chr_stop(); draw_colon(); break; } break; case D_CLK: break; case D_ALM: alm.armed = ! alm.armed; if (alm.armed) start_clock(); draw_colon(); break; default: abort(); break; } } static void clear_hms(void) { switch (dsp) { case D_TMR: if (tmr.state == TS_QUIET) tmr.state = TS_IDLE; else tmr.state = TS_QUIET; tmr.cur.hr = 0; tmr.cur.mn = 0; tmr.cur.sc = 0; draw_all(); break; case D_CHR: chr.cur.hr = 0; chr.cur.mn = 0; chr.cur.sc = 0; chr.curtv.tv_sec = 0; chr.curtv.tv_usec = 0; draw_all(); if (chr.state == CHS_RUNNING) chr_start(); break; } } static void switch_mode(void) { switch (dsp) { case D_TMR: dsp = D_CLK; start_clock(); break; case D_CLK: dsp = D_CHR; break; case D_CHR: dsp = D_ALM; break; case D_ALM: dsp = D_TMR; break; default: abort(); break; } draw_all(); } static int dsp_incdecable(void) { switch (dsp) { case D_TMR: case D_CHR: case D_ALM: return(1); } return(0); } static void click(int x, int y) { static struct { const RECT *rp; int (*cond)(void); void (*fn[3])(void); int roff; #define FOO(x,ud,id) { 0, dsp_incdecable, { timeadjust_pre, x##_##id, timeadjust_post }, offsetof(SKIN,x##_##ud) } } areas[] = { FOO(hr_10,up,inc), FOO(hr_10,dn,dec), FOO(mn_10,up,inc), FOO(mn_10,dn,dec), FOO(sc_10,up,inc), FOO(sc_10,dn,dec), FOO(hr_1,up,inc), FOO(hr_1,dn,dec), FOO(mn_1,up,inc), FOO(mn_1,dn,dec), FOO(sc_1,up,inc), FOO(sc_1,dn,dec), #undef FOO #define FOO(el,cond,fn) { 0, cond, { fn }, offsetof(SKIN,el) } FOO(clear,0,clear_hms), FOO(startstop,0,start_stop), FOO(modebutton,0,switch_mode), #undef FOO }; #define NAREAS (sizeof(areas)/sizeof(areas[0])) int i; if (areas[0].rp == 0) { for (i=0;i= areas[i].rp->pos.x) && (y >= areas[i].rp->pos.y) && (x < areas[i].rp->pos.x+areas[i].rp->siz.w) && (y < areas[i].rp->pos.y+areas[i].rp->siz.h) && (!areas[i].cond || (*areas[i].cond)()) ) { int j; for (j=0;j<3;j++) if (areas[i].fn[j]) (*areas[i].fn[j])(); return; } } } static void handle_event(XEvent *e) { switch (e->type) { default: break; case ConfigureNotify: /* XConfigureEvent - xconfigure */ winw = e->xconfigure.width + (2 * e->xconfigure.border_width); winh = e->xconfigure.height + (2 * e->xconfigure.border_width); redisplay(); break; case Expose: /* XExposeEvent - xexpose */ if (e->xexpose.count == 0) redisplay(); break; case GraphicsExpose: /* XGraphicsExposeEvent - xgraphicsexpose */ if (e->xexpose.count == 0) redisplay(); break; case ButtonPress: /* XButtonPressedEvent - XButtonEvent - xbutton */ if (e->xbutton.window == win) click(e->xbutton.x,e->xbutton.y); break; } } static void tmr_sc_dec(void) { adj = &tmr.cur; adjvis = (dsp == D_TMR); adj_sc_dec(); } static void tmr_sc_inc(void) { adj = &tmr.cur; adjvis = (dsp == D_TMR); adj_sc_inc(); } static void timer_tick(void) { switch (tmr.state) { case TS_DOWN: if (tmr.halftick) { tmr.halftick = 0; inctick(&tmr.tick); if (dsp == D_TMR) draw_colon(); return; } tmr_sc_dec(); tmr.halftick = 1; if (dsp == D_TMR) draw_colon(); inctick(&tmr.tick); if (!tmr.cur.hr && !tmr.cur.mn && !tmr.cur.sc) { XBell(disp,0); XBell(disp,0); XBell(disp,0); XBell(disp,0); tmr.state = TS_ALERT; } break; case TS_ALERT: if (tmr.halftick) { tmr.halftick = 0; inctick(&tmr.tick); if (dsp == D_TMR) draw_colon(); return; } XBell(disp,0); tmr_sc_inc(); tmr.halftick = 1; inctick(&tmr.tick); if (tmr.cur.sc >= 30) tmr.state = TS_QUIET; if (dsp == D_TMR) draw_colon(); break; default: abort(); break; } } static void clock_tick(void) { HMS prev; if ((dsp != D_CLK) && !alm.armed) return; if (clk.halftick) { clk.halftick = 0; inctick(&clk.tick); if (dsp == D_CLK) draw_colon(); return; } prev = clk.cur; start_clock(); if (dsp == D_CLK) { draw_diffs(&clk.cur,&prev); draw_colon(); } if ( alm.armed && (clk.cur.hr == alm.cur.hr) && (clk.cur.mn == alm.cur.mn) ) XBell(disp,0); } static void chron_tick(void) { HMS prev; inctick(&chr.tick); prev = chr.cur; if (chr.curtv.tv_sec & /*31*/7) { inctick(&chr.curtv); } else { getnow(); sub3tv(&now,&chr.offset,&chr.curtv); } chr_curtv_to_cur(); if (dsp == D_CHR) { draw_diffs(&chr.cur,&prev); draw_colon(); } } static void run(void) __attribute__((__noreturn__)); static void run(void) { XEvent e; struct timeval delta; struct timeval *timeout; fd_set fds; int selrv; int xfd; void (*timeoutfn)(void); static void set_timeout(struct timeval *tv, void (*fn)(void)) { if ( !timeout || (tv->tv_sec < timeout->tv_sec) || ( (tv->tv_sec == timeout->tv_sec) && (tv->tv_usec < timeout->tv_usec) ) ) { timeout = tv; timeoutfn = fn; } } xfd = XConnectionNumber(disp); while (1) { havenow = 0; XFlush(disp); if (XQLength(disp) > 0) { do { XNextEvent(disp,&e); handle_event(&e); } while (XQLength(disp) > 0); continue; } timeout = 0; switch (tmr.state) { case TS_IDLE: case TS_PAUSE: case TS_QUIET: break; case TS_DOWN: case TS_ALERT: set_timeout(&tmr.tick,timer_tick); break; default: abort(); break; } if ((dsp == D_CLK) || alm.armed) set_timeout(&clk.tick,clock_tick); switch (chr.state) { case CHS_RUNNING: set_timeout(&chr.tick,chron_tick); break; case CHS_STOPPED: break; default: abort(); break; } if (timeout) { getnow(); if ( (timeout->tv_sec < now.tv_sec) || ( (timeout->tv_sec == now.tv_sec) && (timeout->tv_usec <= now.tv_usec) ) ) { (*timeoutfn)(); continue; } if (timeout->tv_usec >= now.tv_usec) { delta.tv_usec = timeout->tv_usec - now.tv_usec; delta.tv_sec = timeout->tv_sec - now.tv_sec; } else { delta.tv_usec = timeout->tv_usec + 1000000 - now.tv_usec; delta.tv_sec = timeout->tv_sec - now.tv_sec - 1; } timeout = δ } FD_ZERO(&fds); FD_SET(xfd,&fds); selrv = select(FD_SETSIZE,&fds,0,0,timeout); if (selrv < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: select: %s\n",__progname,strerror(errno)); exit(1); } if (FD_ISSET(xfd,&fds)) { int bpend; ioctl(xfd,FIONREAD,&bpend); if (bpend == 0) XSync(disp,False); XEventsQueued(disp,QueuedAfterReading); continue; } } } static void setup_skin(void) { int i; if (skinname == 0) { skin = skins[0]; return; } for (i=0;skins[i];i++) { if (!strcmp(skinname,skins[i]->name)) { skin = skins[i]; return; } } fprintf(stderr,"%s: %s: invalid skin name\n",__progname,skinname); fprintf(stderr,"%s: valid names: ",__progname); for (i=0;skins[i];i++) fprintf(stderr," %s",skins[i]->name); fprintf(stderr,"\n"); exit(1); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); disp = XOpenDisplay(displayname); if (debug) XSynchronize(disp,True); scr = XDefaultScreenOfDisplay(disp); vis = XDefaultVisualOfScreen(scr); scrwidth = XWidthOfScreen(scr); scrheight = XHeightOfScreen(scr); depth = XDefaultDepthOfScreen(scr); rootwin = XRootWindowOfScreen(scr); defcmap = XDefaultColormapOfScreen(scr); defgc = XDefaultGCOfScreen(scr); { Pixmap pm1; pm1 = XCreatePixmap(disp,rootwin,1,1,1); gc1 = XCreateGC(disp,pm1,0,0); XSetBackground(disp,gc1,0); XSetForeground(disp,gc1,1); XFreePixmap(disp,pm1); } setup_db(); maybeset(&geometryspec,get_default_value("xtimer.geometry","Random.Geometry")); maybeset(&foreground,get_default_value("xtimer.foreground","Random.Foreground")); maybeset(&background,get_default_value("xtimer.background","Random.Background")); maybeset(&bordercstr,get_default_value("xtimer.borderColor","Random.BorderColor")); maybeset(&borderwstr,get_default_value("xtimer.borderWidth","Random.BorderWidth")); maybeset(&skinname,get_default_value("xtimer.skin","Random.Skin")); setup_skin(); setup_state(); setup_colors(); setup_numbers(); setup_pixmaps(); setup_window(); setup_error(); run(); }