#include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "driver.h" static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *Name: munch\n\ *IconName: munch\n\ "; static char *displayname; static char *geometryspec; static char *foreground; static char *background; static char *name; static char *iconname; static const char *resname = "mclock"; static const char *resclass = "Clock"; static char *xrmstr = 0; static int synch = 0; static int argc; static char **argv; static int (*previoerror)(Display *); static int (*preverror)(Display *, XErrorEvent *); static Screen *scr; static int width; static int height; static int depth; static Window rootwin; static Colormap defcmap; static Visual *visual; static XColor bgcolour; static XColor fgcolour; static GC wingc; static Window win; static Colormap wincmap; static int timerfd; unsigned int t; Display *disp; GC bitgc; Pixmap pic; int winw; int winh; int npar; int *pars; static char *deconst_(int x, ...) { char *rv; va_list ap; va_start(ap,x); rv = va_arg(ap,char *); va_end(ap); return(rv); } static char *deconst(const char *s) { return(deconst_(0,s)); } 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 != '-') { pars = realloc(pars,(npar+1)*sizeof(int)); pars[npar++] = atoi(*av); // fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); // errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*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,"-name")) { WANTARG(); name = av[skip]; continue; } if (!strcmp(*av,"-iconname")) { WANTARG(); iconname = av[skip]; continue; } if (!strcmp(*av,"-resname")) { WANTARG(); resname = av[skip]; continue; } if (!strcmp(*av,"-resclass")) { WANTARG(); resclass = av[skip]; continue; } if (!strcmp(*av,"-xrm")) { WANTARG(); strappend(&xrmstr,"\n"); strappend(&xrmstr,av[skip]); continue; } if (!strcmp(*av,"-sync")) { synch = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) { exit(1); } } static void maybeset(char **strp, char *str) { if (str && !*strp) *strp = str; } static void setup_db(void) { char *str; char *home; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } else { 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); } } if (xrmstr) { db2 = XrmGetStringDatabase(xrmstr); XrmMergeDatabases(db2,&db); } } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; int nl; int cl; static int buflen = -1; static int rnlen = 0; static int rclen = 0; static char *nbuf; static char *cbuf; nl = strlen(name); cl = strlen(class); if ((nl+1+rnlen >= buflen) || (cl+1+rclen >= buflen)) { if (buflen < 0) { rnlen = strlen(resname); rclen = strlen(resclass); buflen = 10; nbuf = malloc(buflen); cbuf = malloc(buflen); } if (buflen <= nl+1+rnlen) buflen = nl+1+rnlen + 1; if (buflen <= cl+1+rclen) buflen = cl+1+rclen + 1; nbuf = realloc(nbuf,buflen); cbuf = realloc(cbuf,buflen); } sprintf(nbuf,"%s.%s",resname,name); sprintf(cbuf,"%s.%s",resclass,class); if (XrmGetResource(db,nbuf,cbuf,&type,&value) == False) return(0); return(value.addr); } static void setup_timer(void) { struct itimerval itv; timerfd = socket(AF_TIMER,SOCK_STREAM,0); if (timerfd < 0) { fprintf(stderr,"%s: can't create timer socket: %s\n",__progname,strerror(errno)); exit(1); } itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 10000; itv.it_value = itv.it_interval; write(timerfd,&itv,sizeof(itv)); } static void setup_colour(const char *str, XColor *col) { if (XParseColor(disp,wincmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } while (1) { if (XAllocColor(disp,wincmap,col) == 0) { if (wincmap != defcmap) { fprintf(stderr,"%s: can't allocate colourmap cell for colour `%s'\n",__progname,str); exit(1); } wincmap = XCopyColormapAndFree(disp,wincmap); continue; } break; } } static void setup_colours(void) { setup_colour(background,&bgcolour); setup_colour(foreground,&fgcolour); } static void setup_pixmaps(void) { pic = XCreatePixmap(disp,rootwin,1,1,1); bitgc = XCreateGC(disp,pic,0L,(XGCValues *)0); } static void resize(int topw, int toph) { winw = topw; winh = toph; XFreePixmap(disp,pic); pic = XCreatePixmap(disp,win,winw,winh,1); XSetForeground(disp,bitgc,0); XSetFunction(disp,bitgc,GXcopy); XFillRectangle(disp,pic,bitgc,0,0,winw,winh); } static void setup_windows(void) { int x; int y; int w; int h; int bits; unsigned long int attrmask; unsigned long int gcvalmask; XGCValues gcval; XSetWindowAttributes attr; XTextProperty wn_prop; XTextProperty in_prop; XSizeHints *normal_hints; XWMHints *wm_hints; XClassHint *class_hints; static struct { int value; int gravity; } gravities[] = { { XValue|YValue, NorthWestGravity }, { XValue|YValue|XNegative, NorthEastGravity }, { XValue|YValue|YNegative, SouthWestGravity }, { XValue|YValue|XNegative|YNegative, SouthEastGravity } }; w = 512; h = 512; x = (width - w) / 2; y = (height - h) / 2; bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = width + x - w; if (bits & YNegative) y = height + y - h; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.bit_gravity = ForgetGravity; attrmask |= CWBitGravity; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = StructureNotifyMask | ExposureMask; attrmask |= CWEventMask; win = XCreateWindow(disp,rootwin,x,y,w,h,0,depth,InputOutput,CopyFromParent,attrmask,&attr); wn_prop.value = (unsigned char *) name; wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen((char *)wn_prop.value); in_prop.value = (unsigned char *) iconname; in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen((char *)in_prop.value); normal_hints = XAllocSizeHints(); normal_hints->flags = PMinSize | PResizeInc; normal_hints->x = x; normal_hints->y = y; normal_hints->flags |= PWinGravity; normal_hints->win_gravity = CenterGravity; { int i; for (i=0;i<(sizeof(gravities)/sizeof(gravities[0]));i++) { if ((bits & (XValue|YValue|XNegative|YNegative)) == gravities[i].value) { normal_hints->win_gravity = gravities[i].gravity; } } } 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 = 1; normal_hints->min_height = 1; normal_hints->width_inc = 1; normal_hints->height_inc = 1; wm_hints = XAllocWMHints(); wm_hints->flags = InputHint; wm_hints->input = True; class_hints = XAllocClassHint(); class_hints->res_name = deconst(resname); class_hints->res_class = deconst(resclass); XSetWMProperties(disp,win,&wn_prop,&in_prop,argv,argc,normal_hints,wm_hints,class_hints); XFree((char *)normal_hints); XFree((char *)wm_hints); XFree((char *)class_hints); if (wincmap != defcmap) XSetWindowColormap(disp,win,wincmap); gcvalmask = 0; gcval.background = bgcolour.pixel; gcvalmask |= GCBackground; gcval.foreground = fgcolour.pixel; gcvalmask |= GCForeground; wingc = XCreateGC(disp,win,gcvalmask,&gcval); XMapRaised(disp,win); resize(w,h); } static void handle_event(XEvent *e) { switch (e->type) { default: break; case ConfigureNotify: /* XConfigureEvent - xconfigure */ resize(e->xconfigure.width,e->xconfigure.height); break; } } static __inline__ int spacetab(int) __attribute__((__const__)); static __inline__ int spacetab(int c) { switch (c) { case ' ': case '\t': return(1); } return(0); } static __inline__ int spacetabnl(int) __attribute__((__const__)); static __inline__ int spacetabnl(int c) { switch (c) { case ' ': case '\t': case '\n': return(1); } return(0); } static void run(void) { XEvent e; struct timersock_event tse; struct pollfd pfd[2]; int prv; while (1) { while (XEventsQueued(disp,QueuedAfterFlush) > 0) { XNextEvent(disp,&e); handle_event(&e); } pfd[0].fd = timerfd; pfd[0].events = POLLIN | POLLRDNORM; pfd[1].fd = XConnectionNumber(disp); pfd[1].events = POLLIN | POLLRDNORM; prv = poll(&pfd[0],2,INFTIM); if (prv < 0) { switch (errno) { case EINTR: continue; break; default: fprintf(stderr,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); break; } } if (pfd[0].revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP|POLLNVAL)) { read(timerfd,&tse,sizeof(tse)); tick(); XCopyPlane(disp,pic,win,wingc,0,0,winw,winh,0,0,1); t ++; } } } static Display *open_display(const char *disp) { Display *rv; rv = XOpenDisplay(disp); if (rv == 0) { fprintf(stderr,"%s: can't open display %s\n",__progname,XDisplayName(disp)); exit(1); } return(rv); } static int ioerror_handler(Display *d) { return((*previoerror)(d)); } static int error_handler(Display *d, XErrorEvent *e) { return((*preverror)(d,e)); } static void setup_error(void) { preverror = XSetErrorHandler(&error_handler); previoerror = XSetIOErrorHandler(&ioerror_handler); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); disp = open_display(displayname); setup_error(); if (synch) XSynchronize(disp,True); scr = XDefaultScreenOfDisplay(disp); rootwin = XRootWindowOfScreen(scr); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); depth = XDefaultDepthOfScreen(scr); defcmap = XDefaultColormapOfScreen(scr); visual = XDefaultVisualOfScreen(scr); wincmap = defcmap; t = 0; setup_db(); maybeset(&geometryspec,get_default_value("geometry","Geometry")); maybeset(&background,get_default_value("background","Background")); maybeset(&foreground,get_default_value("foreground","Foreground")); maybeset(&name,get_default_value("name","Name")); maybeset(&iconname,get_default_value("iconName","IconName")); setup_colours(); setup_pixmaps(); setup_windows(); setup_timer(); run(); return(0); }