#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #define ERSIZE 65536 typedef enum { BKS_NASCENT = 1, BKS_NONE, BKS_BROKEN, BKS_DISCONNECTED, BKS_SCANNING, BKS_CATCHUP, BKS_LIVE, BKS_RESCAN, BKS_PASSIVE_LIVE, BKS_PASSIVE_SCAN } BKSTATE; typedef struct bk BK; typedef struct es ES; typedef struct er ER; typedef struct ere ERE; typedef struct lbd LBD; struct ere { struct timeval stamp; char *text; } ; struct er { ERE v[ERSIZE]; int h; int t; } ; struct es { char *b; int a; int l; } ; struct lbd { LBD *link; unsigned int flags; #define LBDF_DEAD 0x00000001 char *str; struct addrinfo *ai0; int fd; int id; union { struct { AIO_OQ oq; ES b; void (*rdchk)(LBD *, int); BK *bksf; BK *bksb; } ; struct { struct addrinfo *ai; } ; } ; } ; struct bk { BK *lflink; BK *lblink; BK *aflink; BK *ablink; LBD *lbd; char *id; int idlen; char *backingname; ES stat; XCharStruct namesize; BKSTATE state; int pct; int pht; int xsetup; Window win; Window textwin; Window barwin; int y0; int lastw; } ; static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *LiveColour: #0f0\n\ *CatchupColour: #f00\n\ *ScanColour: #00f\n\ *ScanDoneColour: #09f\n\ *RescanColour: #f0f\n\ *PassiveLiveColour: #696\n\ *PassiveScanColour: #669\n\ *BrokenColour: #f00\n\ *BarBackground: #585858\n\ *BorderColour: white\n\ *BorderWidth: 1\n\ *BorderMargin: 2\n\ *Name: lbwatch\n\ *IconName: lbwatch\n\ *LBD: ::1/20000\n\ "; static char *displayname; static char *geometryspec; static char *foreground; static char *background; static char *livecstr; static char *catchupcstr; static char *scancstr; static char *scandonecstr; static char *rescancstr; static char *passivelivecstr; static char *passivescancstr; static char *brokencstr; static char *barbgcstr; static char *bordercstr; static char *borderwstr; static char *bordermstr; static char *name; static char *visualstr; static char *iconname; static char *fontname; static int synch = 0; /* grrr, preempts sync */ static const char *resname = "lbwatch"; static const char *resclass = "Random"; static char *xrmstr = 0; static int argc; static char **argv; static Display *disp; static Screen *scr; static int width; static int height; static int depth; static Window rootwin; static Colormap defcmap; static Visual *visual; static int (*preverr)(Display *, XErrorEvent *); static int (*prevIOerr)(Display *); static XColor fgcolour; static XColor bgcolour; static XColor livecolour; static XColor catchupcolour; static XColor scancolour; static XColor scandonecolour; static XColor rescancolour; static XColor passivelivecolour; static XColor passivescancolour; static XColor brokencolour; static XColor barbgcolour; static XColor bdcolour; static GC wingc; static Window topwin; static Colormap wincmap; static int margin; static int borderwidth; static XFontStruct *font; static int deffont; static int baselineskip; static int prev_topy; static int junk_direction; static int junk_ascent; static int junk_descent; #define XTE_JUNK &junk_direction,&junk_ascent,&junk_descent static BK *abksf; static BK *abksb; static int xflushid; static int xfd; static int xid; static ER ering; static LBD *lbds = 0; static int lbdadd = 0; static int lbd_try_connect(void *); /* forward */ #define Cisdigit(x) isdigit((unsigned char)(x)) static void *deconst(const volatile void *s) { return((((const volatile char *)s)-((const volatile char *)0))+(char *)0); } static void es_init(ES *es) { es->b = 0; es->a = 0; es->l = 0; } static void es_free(ES *es) { free(es->b); es->b = 0; es->a = 0; es->l = 0; } static void es_space(ES *es, int n) { if (n < es->l) abort(); if (es->a < n) es->b = realloc(es->b,es->a=n); } static void es_room(ES *es, int n) { if (n < 0) abort(); es_space(es,es->l+n); } static char *es_buf(ES *es) { return(es->b); } static int es_len(ES *es) { return(es->l); } static int es_avail(ES *es) { return(es->a-es->l); } static int es_fillby(ES *es, int n) { es->l += n; if (es->l < 0) abort(); return(es->l); } static void es_setlen(ES *es, int l) { if (l < 0) abort(); es->l = l; } static char *b_l_dup(const char *b, int l) { char *t; t = malloc(l+1); bcopy(b,t,l); t[l] = '\0'; return(t); } static void er_init(void) { int i; for (i=ERSIZE-1;i>=0;i--) ering.v[i].text = 0; ering.h = 0; ering.t = 0; } static void er_record(const char *, ...) __attribute__((__format__(__printf__,1,2))); static void er_record(const char *fmt, ...) { va_list ap; char *s; ERE *e; va_start(ap,fmt); vasprintf(&s,fmt,ap); va_end(ap); e = &ering.v[ering.h]; free(e->text); e->text = s; gettimeofday(&e->stamp,0); ering.h = (ering.h ? : ERSIZE) - 1; if (ering.h == ering.t) ering.t = (ering.t ? : ERSIZE) - 1; } 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;istr = b_l_dup(s,slen); l->ai0 = 0; l->fd = -1; l->id = AIO_NOID; l->link = lbds; lbds = l; } static void add_lbd_list(const char *s) { const char *comma; if (! s) return; while (1) { comma = index(s,','); if (comma) { add_one_lbd(s,comma-s); s = comma + 1; } else { add_one_lbd(s,strlen(s)); break; } } } static void add_lbd_arg(const char *s) { if (!strcmp(s,"+")) { lbdadd = 1; return; } add_lbd_list(s); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**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,"-bordercolour") || !strcmp(*av,"-bd") || !strcmp(*av,"-bordercolor")) { WANTARG(); bordercstr = av[skip]; continue; } if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-bordermargin") || !strcmp(*av,"-bm")) { WANTARG(); bordermstr = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-name")) { WANTARG(); name = av[skip]; continue; } if (!strcmp(*av,"-iconname")) { WANTARG(); iconname = av[skip]; continue; } if (!strcmp(*av,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = 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; } if (!strcmp(*av,"-lbd")) { WANTARG(); add_lbd_arg(av[skip]); continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } 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 void setup_db(void) { char *str; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } #if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 5) str = XScreenResourceString(scr); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } #endif if (xrmstr) { db2 = XrmGetStringDatabase(xrmstr); XrmMergeDatabases(db2,&db); } } 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; 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 relayout(void) { BK *b; int y; int maxw; XWindowChanges chg; unsigned int chgmask; er_record("relayout"); y = 0; maxw = 0; for (b=abksf;b;b=b->aflink) { if (! b->xsetup) continue; if (b->namesize.width > maxw) maxw = b->namesize.width; } er_record("maxw = %d",maxw); for (b=abksf;b;b=b->aflink) { if (! b->xsetup) continue; er_record("%p: y0 %d lastw %d -> %d %d",(void *)b,b->y0,b->lastw,y,maxw); if ((y != b->y0) || (maxw != b->lastw)) { b->y0 = y; b->lastw = maxw; er_record("MoveResizeWindow %lx to %dx%d+%d+%d",(unsigned long int)b->win, 100+maxw+(3*margin), baselineskip+(2*margin), 0, y); XMoveResizeWindow(disp,b->win,0,y,100+maxw+(3*margin),baselineskip+(2*margin)); } y += baselineskip + (2 * margin) + borderwidth; } if (y != prev_topy) { chgmask = 0; chg.width = 100 + maxw + (3 * margin); chgmask |= CWWidth; chg.height = y - borderwidth; chgmask |= CWHeight; er_record("ReconfigureWMWindow: %lx to %dx%d",(unsigned long int)topwin,chg.width,chg.height); XReconfigureWMWindow(disp,topwin,XScreenNumberOfScreen(scr),chgmask,&chg); if (abksf) { er_record("Mapping"); XMapWindow(disp,topwin); } else { er_record("Withdrawing"); XWithdrawWindow(disp,topwin,XScreenNumberOfScreen(scr)); } prev_topy = y; } } static BK *bk_new(LBD *l, const char *id, int idlen, const char *bf, int bflen) { BK *b; b = malloc(sizeof(BK)); b->lbd = l; b->id = malloc(idlen); bcopy(id,b->id,idlen); b->idlen = idlen; b->backingname = b_l_dup(bf,bflen); es_init(&b->stat); b->state = BKS_NASCENT; b->xsetup = 0; er_record("bk_new %s: id %.*s bf %.*s -> %p",l->str,idlen,id,bflen,bf,(void *)b); return(b); } static BK *bk_by_id(LBD *l, const char *id, int idlen) { BK *b; for (b=l->bksf;b;b=b->lflink) if ((b->idlen == idlen) && !bcmp(b->id,id,idlen)) break; er_record("bk_by_id %s %.*s -> %p",l->str,idlen,id,(void *)b); return(b); } static void bk_teardown(BK *b) { er_record("bk_teardown %p (id %.*s bf %s)",(void *)b,b->idlen,b->id,b->backingname); if (b->lflink) b->lflink->lblink = b->lblink; else b->lbd->bksb = b->lblink; if (b->lblink) b->lblink->lflink = b->lflink; else b->lbd->bksf = b->lflink; if (b->aflink) b->aflink->ablink = b->ablink; else abksb = b->ablink; if (b->ablink) b->ablink->aflink = b->aflink; else abksf = b->aflink; free(b->id); free(b->backingname); es_free(&b->stat); if (b->xsetup) { XDestroyWindow(disp,b->win); } free(b); } static void bk_append(BK *b) { er_record("bk_append %p",(void *)b); b->aflink = 0; b->ablink = abksb; if (abksb) abksb->aflink = b; else abksf = b; abksb = b; b->lflink = 0; b->lblink = b->lbd->bksb; if (b->lbd->bksb) b->lbd->bksb->lflink = b; else b->lbd->bksf = b; b->lbd->bksb = b; } static int bk_lt(BK *a, BK *b) { if (a->state != b->state) { if (a->state == BKS_BROKEN) return(1); if (b->state == BKS_BROKEN) return(0); if (a->state == BKS_NASCENT) return(0); if (b->state == BKS_NASCENT) return(1); if (a->state == BKS_LIVE) return(0); if (b->state == BKS_LIVE) return(1); } return(strcmp(a->backingname,b->backingname)<0); } static void bk_sort(void) { BK *b; int any; BK *t; er_record("bk_sort"); while (1) { any = 0; for (b=abksf;b;b=b->aflink) { t = b->aflink; if (t && bk_lt(t,b)) { if (b->ablink) b->ablink->aflink = t; else abksf = t; if (t->aflink) t->aflink->ablink = b; else abksb = b; t->ablink = b->ablink; b->aflink = t->aflink; t->aflink = b; b->ablink = t; b = t; any = 1; } } if (! any) break; any = 0; for (b=abksb;b;b=b->ablink) { t = b->ablink; if (t && bk_lt(b,t)) { if (b->aflink) b->aflink->ablink = t; else abksb = t; if (t->ablink) t->ablink->aflink = b; else abksf = b; t->aflink = b->aflink; b->ablink = t->ablink; t->ablink = b; b->aflink = t; b = t; any = 1; } } if (! any) break; } } static void bk_setup_x(BK *b) { unsigned long int attrmask; XSetWindowAttributes attr; if (b->xsetup) { er_record("bk_setup_x %p already done",(void *)b); return; } attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.colormap = wincmap; attrmask |= CWColormap; b->win = XCreateWindow(disp,topwin,-2,-2,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; attr.colormap = wincmap; attrmask |= CWColormap; b->textwin = XCreateWindow(disp,b->win,100+(2*margin),margin,32767,baselineskip,0,depth,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attr.background_pixel = barbgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; attr.colormap = wincmap; attrmask |= CWColormap; b->barwin = XCreateWindow(disp,b->win,margin,margin,100,baselineskip,0,depth,InputOutput,CopyFromParent,attrmask,&attr); b->y0 = -1; b->lastw = -1; XTextExtents(font,b->backingname,strlen(b->backingname),XTE_JUNK,&b->namesize); b->xsetup = 1; XMapWindow(disp,b->textwin); XMapWindow(disp,b->barwin); XMapWindow(disp,b->win); er_record("bk_setup_x %p win %lx",(void *)b,(unsigned long int)b->win); } static void bk_retext(BK *b) { er_record("bk_retext %p",(void *)b); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,fgcolour.pixel); XDrawString(disp,b->textwin,wingc,0,font->ascent,b->backingname,strlen(b->backingname)); } static void bk_draw_pht(BK *b, unsigned long int pixel) { er_record("bk_draw_pht %p (pht=%d)",(void *)b,b->pht); if (b->pht >= 0) { XSetForeground(disp,wingc,pixel); if (b->pht >= 100) { XFillRectangle(disp,b->barwin,wingc,0,0,b->pht/100,9); XFillRectangle(disp,b->barwin,wingc,0,0,(b->pht>=1000)?100:(b->pht/10),3); XFillRectangle(disp,b->barwin,wingc,0,0,100,1); } else { if (b->pht >= 10) XFillRectangle(disp,b->barwin,wingc,0,0,b->pht/10,3); XFillRectangle(disp,b->barwin,wingc,0,0,b->pht,1); } } } static void bk_redisplay(BK *b) { switch (b->state) { case BKS_NASCENT: er_record("bk_redisplay %p (NASCENT)",(void *)b); break; case BKS_NONE: er_record("bk_redisplay %p (NONE)",(void *)b); break; case BKS_BROKEN: er_record("bk_redisplay %p (BROKEN)",(void *)b); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,brokencolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,100,baselineskip); break; case BKS_DISCONNECTED: er_record("bk_redisplay %p (DISCONNECTED)",(void *)b); break; case BKS_SCANNING: er_record("bk_redisplay %p (SCANNING %d %d)",(void *)b,b->pct,b->pht); XSetFunction(disp,wingc,GXcopy); if (b->pct < 100) { XSetForeground(disp,wingc,barbgcolour.pixel); XFillRectangle(disp,b->barwin,wingc,b->pct,0,100-b->pct,baselineskip); } if (b->pct > 0) { XSetForeground(disp,wingc,scancolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,b->pct,baselineskip); } bk_draw_pht(b,catchupcolour.pixel); break; case BKS_CATCHUP: er_record("bk_redisplay %p (CATCHUP %d)",(void *)b,b->pht); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,scandonecolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,100,baselineskip); bk_draw_pht(b,catchupcolour.pixel); break; case BKS_LIVE: er_record("bk_redisplay %p (LIVE)",(void *)b); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,livecolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,100,baselineskip); break; case BKS_RESCAN: er_record("bk_redisplay %p (RESCAN)",(void *)b); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,rescancolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,100,baselineskip); break; case BKS_PASSIVE_LIVE: er_record("bk_redisplay %p (PASSIVE_LIVE %d)",(void *)b,b->pht); XSetFunction(disp,wingc,GXcopy); XSetForeground(disp,wingc,passivelivecolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,100,baselineskip); bk_draw_pht(b,catchupcolour.pixel); break; case BKS_PASSIVE_SCAN: er_record("bk_redisplay %p (PASSIVE_SCAN %d %d)",(void *)b,b->pct,b->pht); XSetFunction(disp,wingc,GXcopy); if (b->pct < 100) { XSetForeground(disp,wingc,barbgcolour.pixel); XFillRectangle(disp,b->barwin,wingc,b->pct,0,100-b->pct,baselineskip); } if (b->pct > 0) { XSetForeground(disp,wingc,passivescancolour.pixel); XFillRectangle(disp,b->barwin,wingc,0,0,b->pct,baselineskip); } bk_draw_pht(b,catchupcolour.pixel); break; default: er_record("bk_redisplay %p (? %d)",(void *)b,(int)b->state); break; } } static void expose_event(Drawable win, int x, int y, int w, int h, int count) { BK *b; x=x; y=y; w=w; h=h; for (b=abksf;b;b=b->aflink) { if (win == b->textwin) { if (count == 0) { er_record("expose_event %p textwin",(void *)b); bk_retext(b); } } else if (win == b->barwin) { if (count == 0) { er_record("expose_event %p barwin",(void *)b); bk_redisplay(b); } } } } /* * I would normally use scanf to parse numbers, with (for this program) * an input stream that reads from memory. But scanf is too broken. * It's broken in a minor way in that %*u and %*lu are the same thing * (there is no room in the spec for %u to reject numbers that fit * unsigned long but not unsigned int, if any such exist); it's broken * in a much more major way in that %u and %lu accept negative * numbers. * * Unfortunately strtoul also accepts negative numbers. I don't know * what the hell its designers were thinking, since this leaves no way * to reject signed input without cobbling together one's own! * * So this is my cobbling-together. It looks sorta like scanf, except * that (a) the input comes from pointer-and-length and (b) the escape * sequences are different. Specifically: * * ~p Accepts a number from 0 through 100, without leading * 0s. Argument: unsigned int *. * * ~l Accept any sequence of digits but does not assign it * anywhere. * * ~P Accepts a number from 0 through 100, with exactly two * decimal places and no leading 0s. The value assigned * is 100 times this number (ie, 0-10000). Argument: * unsigned int *. * * Return value is 1 if the format matches the entire buf/buflen * string, 0 otherwise. If 0 is returned, some/all of the arguments * may be stored through. */ static int num_parse(const char *buf, int buflen, const char *fmt, ...) { __label__ done_; va_list ap; const char *fp; int bx; int rv; void done(int ret) { rv = ret; goto done_; } va_start(ap,fmt); bx = 0; fp = fmt; while <"fmt"> (1) { switch (*fp++) { case '\0': done(bx==buflen); break; default: if (bx >= buflen) done(0); if (buf[bx++] != fp[-1]) done(0); break; case '~': switch (*fp++) { default: fprintf(stderr,"%s: bad format ~%c to num_parse\n",__progname,fp[-1]); exit(1); break; case 'p': if (bx >= buflen) done(0); if (! Cisdigit(buf[bx])) done(0); if ((buflen-bx >= 3) && !bcmp(buf+bx,"100",3)) { *va_arg(ap,unsigned int *) = 100; bx += 3; continue; } if ((buflen-bx == 1) || !Cisdigit(buf[bx+1])) { *va_arg(ap,unsigned int *) = buf[bx++] - '0'; continue; } *va_arg(ap,unsigned int *) = ((buf[bx]-'0') * 10) + (buf[bx+1] - '0'); bx += 2; continue; break; case 'P': if (buflen-bx < 4) done(0); if (! Cisdigit(buf[bx])) done(0); if ((buflen-bx >= 6) && !bcmp(buf+bx,"100.00",6)) { *va_arg(ap,unsigned int *) = 10000; bx += 6; continue; } if ((buf[bx+1] == '.') && Cisdigit(buf[bx+2]) && Cisdigit(buf[bx+3])) { *va_arg(ap,unsigned int *) = ((buf[bx]-'0') * 100) + ((buf[bx+2]-'0') * 10) + (buf[bx+3]-'0'); bx += 4; continue; } if (Cisdigit(buf[bx+1]) && (buf[bx+2] == '.') && Cisdigit(buf[bx+3]) && Cisdigit(buf[bx+4])) { *va_arg(ap,unsigned int *) = ((buf[bx]-'0') * 1000) + ((buf[bx+1]-'0') * 100) + ((buf[bx+3]-'0') * 10) + (buf[bx+4]-'0'); bx += 5; continue; } done(0); break; case 'l': if (bx >= buflen) done(0); if (! Cisdigit(buf[bx])) done(0); while ((bx < buflen) && Cisdigit(buf[bx])) bx ++; break; } break; } } done_:; va_end(ap); return(rv); } static void restart_lbd_connect(void *lv) { LBD *l; l = lv; close(l->fd); l->fd = -1; aio_remove_poll(l->id); l->id = AIO_NOID; l->ai = l->ai0; l->id = aio_add_block(&lbd_try_connect,l); } static void schedule_reconnect(LBD *l) { struct itimerval itv; l->fd = socket(AF_TIMER,SOCK_STREAM,0); if (l->fd < 0) { fprintf(stderr,"%s: AF_TIMER socket: %s\n",__progname,strerror(errno)); exit(1); } itv.it_value.tv_sec = 60; itv.it_value.tv_usec = 0; itv.it_interval.tv_sec = 00; itv.it_interval.tv_usec = 0; write(l->fd,&itv,sizeof(itv)); l->id = aio_add_poll(l->fd,&aio_rwtest_always,&aio_rwtest_never,&restart_lbd_connect,0,l); } static int kill_lbd(void *lv) { LBD *l; l = lv; aio_remove_block(l->id); close(l->fd); aio_oq_flush(&l->oq); es_free(&l->b); while (l->bksf) bk_teardown(l->bksf); bk_sort(); relayout(); schedule_reconnect(l); return(AIO_BLOCK_LOOP); } static void dead_lbd(LBD *l) { if (l->flags & LBDF_DEAD) return; l->flags |= LBDF_DEAD; aio_remove_poll(l->id); l->id = aio_add_block(&kill_lbd,l); } /* * See the comment on num_parse, above, for why I use it here. */ static void lbd_line_status(LBD *l, const char *id, int idlen, const char *arg, int arglen) { BK *b; int x; char *cx; unsigned int v1; unsigned int v2; const char *a; int al; er_record("lbd_line_status %s %.*s %.*s",l->str,idlen,id,arglen,arg); b = bk_by_id(l,id,idlen); if (! b) { er_record("can't find any BK for %s with ID %.*s",l->str,idlen,id); return; } x = 0; while (1) { if (x >= arglen) { er_record("%s: %s: status ends with colon: %.*s",l->str,b->backingname,arglen,arg); dead_lbd(l); return; } cx = memchr(arg+x,':',arglen-x); if (! cx) break; x = (cx + 1) - arg; } a = arg + x; al = arglen - x; if ((al == 5) && !bcmp(a," live",5)) { b->state = BKS_LIVE; } else if ((al == 7) && !bcmp(a," rescan",7)) { b->state = BKS_RESCAN; } else if ((al == 13) && !bcmp(a," disconnected",13)) { b->state = BKS_DISCONNECTED; } else if ((al == 17) && !bcmp(a," passive (rescan)",17)) { b->state = BKS_PASSIVE_SCAN; b->pct = 0; b->pht = 0; } else if ((al == 23) && !bcmp(a," passive (disconnected)",23)) { b->state = BKS_DISCONNECTED; } else if ((al > 10) && !bcmp(a," scanning ",10)) { if (num_parse(a+10,al-10,"~p%/0",&v1)) { b->state = BKS_SCANNING; b->pct = v1; b->pht = 0; } else if (num_parse(a+10,al-10,"~p%/~l/~P%",&v1,&v2)) { b->state = BKS_SCANNING; b->pct = v1; b->pht = v2; } else { er_record("%s: %s: can't parse scanning line: %.*s",l->str,b->backingname,arglen,arg); b->state = BKS_BROKEN; } } else if ((al > 9) && !bcmp(a," catchup ",9)) { if ((al == 10) && (a[9] == '0')) { b->state = BKS_CATCHUP; b->pht = 0; } else if (num_parse(a+9,al-9,"~l/~P%",&v1)) { b->state = BKS_CATCHUP; b->pht = v1; } else { er_record("%s: %s: can't parse catchup line: %.*s",l->str,b->backingname,arglen,arg); b->state = BKS_BROKEN; } } else if ((al > 19) && !bcmp(a," passive (scanning ",19)) { if (num_parse(a+19,al-19,"~p%/0)",&v1)) { b->state = BKS_PASSIVE_SCAN; b->pct = v1; b->pht = 0; } else if (num_parse(a+19,al-19,"~p%/~l/~P%)",&v1,&v2)) { b->state = BKS_PASSIVE_SCAN; b->pct = v1; b->pht = v2; } else { er_record("%s: %s: can't parse passive scanning line: %.*s",l->str,b->backingname,arglen,arg); b->state = BKS_BROKEN; } } else if ((al > 9) && !bcmp(a," passive ",9)) { if ((al == 10) && (a[9] == '0')) { b->state = BKS_PASSIVE_LIVE; b->pht = 0; } else if (num_parse(a+9,al-9,"~l/~P%",&v1)) { b->state = BKS_PASSIVE_LIVE; b->pht = v1; } else { er_record("%s: %s: can't parse passive line: %.*s",l->str,b->backingname,arglen,arg); b->state = BKS_BROKEN; return; } } else { er_record("%s: %s: can't identify line type: %.*s",l->str,b->backingname,arglen,arg); b->state = BKS_BROKEN; return; } bk_redisplay(b); } static void lbd_line_connect(LBD *l, const char *id, int idlen, const char *arg, int arglen) { BK *b; er_record("lbd_line_connect %s %.*s %.*s",l->str,idlen,id,arglen,arg); while (1) { b = bk_by_id(l,id,idlen); if (! b) break; bk_teardown(b); } b = bk_new(l,id,idlen,arg,arglen); b->state = BKS_NASCENT; bk_append(b); } static void lbd_line_up(LBD *l, const char *id, int idlen, const char *arg, int arglen) { BK *b; er_record("lbd_line_up %s %.*s %.*s",l->str,idlen,id,arglen,arg); b = bk_by_id(l,id,idlen); if (b == 0) { b = bk_new(l,id,idlen,arg,arglen); b->state = BKS_NONE; bk_append(b); } bk_setup_x(b); bk_redisplay(b); } static void lbd_line_dead(LBD *l, const char *id, int idlen, const char *arg __attribute__((__unused__)), int arglen __attribute__((__unused__))) { BK *b; er_record("lbd_line_dead %s %.*s %.*s",l->str,idlen,id,arglen,arg); b = bk_by_id(l,id,idlen); if (b) bk_teardown(b); } static void lbd_line(LBD *l, const char *data, int len) { int opx; int oplen; int idx; int idlen; int argx; int arglen; int x; if ((len < 6) || bcmp(data,"WATCH ",6)) { er_record("non-WATCH line from %s: %.*s",l->str,len,data); dead_lbd(l); return; } opx = 6; for (x=opx;(x= len) { er_record("WATCH line with no second space from %s: %.*s",l->str,len,data); dead_lbd(l); return; } oplen = x - opx; idx = x + 1; for (x=idx;(x= len) { er_record("WATCH line with no third space from %s: %.*s",l->str,len,data); dead_lbd(l); return; } idlen = x - idx; argx = x + 1; arglen = len - argx; if ((oplen == 6) && !bcmp(data+opx,"STATUS",6)) { lbd_line_status(l,data+idx,idlen,data+argx,arglen); } else if ((oplen == 7) && !bcmp(data+opx,"CONNECT",7)) { lbd_line_connect(l,data+idx,idlen,data+argx,arglen); } else if ((oplen == 2) && !bcmp(data+opx,"UP",2)) { lbd_line_up(l,data+idx,idlen,data+argx,arglen); } else if ((oplen == 4) && !bcmp(data+opx,"DEAD",4)) { lbd_line_dead(l,data+idx,idlen,data+argx,arglen); } else { er_record("WATCH line with unknown op from %s: %.*s",l->str,len,data); dead_lbd(l); } if (l->flags & LBDF_DEAD) return; bk_sort(); relayout(); } static void lbd_rdchk_watch(LBD *l, int n) { char *eb; int el; char *nl; int bx; if (n < 1) abort(); el = es_len(&l->b); if (n > el) abort(); bx = 0; eb = es_buf(&l->b); while (1) { nl = (n > 0) ? memchr(eb+(el-n),'\n',n) : 0; if (! nl) { if (bx > 0) { el = es_fillby(&l->b,-bx); if (el) bcopy(eb+bx,eb,el); } if (es_len(&l->b) > 1024) { er_record("ridiculous line length (>= %d) from %s",es_len(&l->b),l->str); dead_lbd(l); } return; } lbd_line(l,eb+bx,nl-(eb+bx)); if (l->flags & LBDF_DEAD) return; bx = (nl + 1) - eb; n = el - bx; } } static void lbd_rdchk_step2(LBD *l, int n) { char *eb; int el; eb = es_buf(&l->b); el = es_len(&l->b); if (n != el) abort(); if (eb[0] != '\n') { er_record("lbd %s didn't follow @ with newline (2)",l->str); dead_lbd(l); return; } l->rdchk = &lbd_rdchk_watch; el = es_fillby(&l->b,-1); if (el) { bcopy(eb+1,eb,el); lbd_rdchk_watch(l,el); } } static void lbd_rdchk_step1(LBD *l, int n) { char *eb; int el; char *at; int x; if (n < 1) abort(); el = es_len(&l->b); if (n > el) abort(); eb = es_buf(&l->b); at = memchr(eb+(el-n),'@',n); if (! at) return; x = at - eb; if (x == el-1) { es_setlen(&l->b,0); l->rdchk = &lbd_rdchk_step2; return; } if (eb[x+1] == '\n') { l->rdchk = &lbd_rdchk_watch; el = es_fillby(&l->b,-(x+2)); if (el) { bcopy(eb+x+2,eb,el); lbd_rdchk_watch(l,el); } return; } er_record("lbd %s didn't follow @ with newline (1)",l->str); dead_lbd(l); } static int wtest_lbd(void *lv) { return(aio_oq_nonempty(&((LBD *)lv)->oq)); } static void wr_lbd(void *lv) { LBD *l; int w; l = lv; w = aio_oq_writev(&l->oq,l->fd,-1); if (w < 0) { switch (errno) { case EINTR: case EWOULDBLOCK: return; break; } er_record("writev to %s: %s",l->str,strerror(errno)); dead_lbd(l); return; } aio_oq_dropdata(&l->oq,w); } static void rd_lbd(void *lv) { LBD *l; int nr; int e; l = lv; es_room(&l->b,256); nr = read(l->fd,es_buf(&l->b)+es_len(&l->b),es_avail(&l->b)); if (nr < 0) { er_record("lbd %s read: error %d (%s)",l->str,e,strerror(e)); e = errno; switch (e) { case EINTR: case EWOULDBLOCK: return; break; } dead_lbd(l); return; } if (nr == 0) { er_record("lbd %s read EOF",l->str); dead_lbd(l); return; } er_record("lbd %s read: got %d",l->str,nr); es_fillby(&l->b,nr); (*l->rdchk)(l,nr); } static void lbd_connected(LBD *l) { er_record("%s now connected",l->str); aio_oq_init(&l->oq); es_init(&l->b); aio_oq_queue_point(&l->oq,"prompt\necho @\nwatch\n",AIO_STRLEN); l->id = aio_add_poll(l->fd,&aio_rwtest_always,&wtest_lbd,&rd_lbd,&wr_lbd,l); l->rdchk = &lbd_rdchk_step1; } static void record_connect_err(LBD *l, int err) { int e2; char host[NI_MAXHOST]; char serv[NI_MAXSERV]; e2 = getnameinfo(l->ai->ai_addr,l->ai->ai_addrlen,&host[0],NI_MAXHOST,&serv[0],NI_MAXSERV,NI_NUMERICHOST|NI_NUMERICSERV); if (e2) { er_record("%s: connect (af %d, can't print address: %s): %s",l->str,l->ai->ai_family,strerror(e2),strerror(err)); } else { er_record("%s: connect %s/%s: %s",l->str,&host[0],&serv[0],strerror(err)); } } static void lbd_check_connect(void *lv) { LBD *l; int e; socklen_t elen; l = lv; elen = sizeof(e); do <"fail"> { if (getsockopt(l->fd,SOL_SOCKET,SO_ERROR,&e,&elen) < 0) { er_record("%s: getsockopt SO_ERROR: %s",l->str,strerror(errno)); break <"fail">; } aio_remove_poll(l->id); if (e) { record_connect_err(l,e); break <"fail">; } lbd_connected(l); return; } while (0); close(l->fd); l->ai = l->ai->ai_next; l->id = aio_add_block(&lbd_try_connect,l); } static int lbd_try_connect(void *lv) { LBD *l; int e; int e2; int s; int on; char host[NI_MAXHOST]; char serv[NI_MAXSERV]; l = lv; if (! l->ai) { er_record("%s: all connect attempts failed",l->str); aio_remove_block(l->id); schedule_reconnect(l); return(AIO_BLOCK_LOOP); } s = socket(l->ai->ai_family,l->ai->ai_socktype,l->ai->ai_protocol); if (s < 0) { er_record("%s: socket (af %d): %s",l->str,l->ai->ai_family,strerror(errno)); l->ai = l->ai->ai_next; return(AIO_BLOCK_LOOP); } fcntl(s,F_SETFL,fcntl(s,F_GETFL,0)|O_NONBLOCK); on = 1; setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,&on,sizeof(on)); if (connect(s,l->ai->ai_addr,l->ai->ai_addrlen) < 0) { e = errno; if (e == EINPROGRESS) { aio_remove_block(l->id); l->fd = s; l->id = aio_add_poll(s,&aio_rwtest_never,&aio_rwtest_always,0,&lbd_check_connect,l); return(AIO_BLOCK_LOOP); } record_connect_err(l,e); close(s); l->ai = l->ai->ai_next; return(AIO_BLOCK_LOOP); } e2 = getnameinfo(l->ai->ai_addr,l->ai->ai_addrlen,&host[0],NI_MAXHOST,&serv[0],NI_MAXSERV,NI_NUMERICHOST|NI_NUMERICSERV); if (e2) { er_record("%s: connect worked (af %d, can't print address: %s)",l->str,l->ai->ai_family,strerror(e2)); } else { er_record("%s: connect worked %s/%s",l->str,&host[0],&serv[0]); } aio_remove_block(l->id); l->fd = s; lbd_connected(l); return(AIO_BLOCK_LOOP); } static void lbd_start_connect(LBD *l) { struct addrinfo hints; char *slash; char *addr; int alen; char *port; int e; struct addrinfo *ai0; slash = index(l->str,'/'); if (slash == 0) { fprintf(stderr,"%s: %s: invalid LBD contact point (no slash)\n",__progname,l->str); exit(1); } port = slash + 1; alen = slash - l->str; addr = malloc(alen+1); bcopy(l->str,addr,alen); addr[alen] = '\0'; hints.ai_flags = 0; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = 0; hints.ai_addr = 0; hints.ai_next = 0; e = getaddrinfo(addr,port,&hints,&ai0); if (e) { fprintf(stderr,"%s: %s: can't resolve: %s\n",__progname,l->str,gai_strerror(e)); exit(1); } if (! ai0) { fprintf(stderr,"%s: %s: resolved but zero addresses\n",__progname,l->str); exit(1); } l->ai0 = ai0; l->ai = ai0; l->id = aio_add_block(&lbd_try_connect,l); } static void setup_lbd(void) { LBD *l; if (! lbds) { fprintf(stderr,"%s: no lbd!\n",__progname); exit(1); } for (l=lbds;l;l=l->link) { l->bksf = 0; l->bksb = 0; lbd_start_connect(l); } } static void setup_visual(void) { char *cp; XVisualInfo *xvi; int nvi; XVisualInfo template; long int mask; int i; int vpref; visual = 0; depth = XDefaultDepthOfScreen(scr); if (visualstr == 0) return; template.screen = XScreenNumberOfScreen(scr); mask = VisualScreenMask | VisualClassMask; for (cp=visualstr;*cp;cp++) *cp = tolower((unsigned char)*cp); if (!strcmp(visualstr,"staticgray")) template.class = StaticGray; else if (!strcmp(visualstr,"grayscale")) template.class = GrayScale; else if (!strcmp(visualstr,"staticcolour")) template.class = StaticColor; else if (!strcmp(visualstr,"pseudocolour")) template.class = PseudoColor; else if (!strcmp(visualstr,"directcolour")) template.class = DirectColor; else if (!strcmp(visualstr,"truecolour")) template.class = TrueColor; else if (!strcmp(visualstr,"staticcolor")) template.class = StaticColor; else if (!strcmp(visualstr,"pseudocolor")) template.class = PseudoColor; else if (!strcmp(visualstr,"directcolor")) template.class = DirectColor; else if (!strcmp(visualstr,"truecolor")) template.class = TrueColor; else { unsigned long int id; id = strtol(visualstr,&cp,0); if (*cp) { fprintf(stderr,"%s: %s: invalid visual option\n",__progname,visualstr); exit(1); } template.visualid = (VisualID) id; mask |= VisualIDMask; mask &= ~VisualClassMask; } xvi = XGetVisualInfo(disp,mask,&template,&nvi); if (xvi == 0) { fprintf(stderr,"%s: no matching visual found\n",__progname); exit(1); } if (nvi == 0) { fprintf(stderr,"%s: what? XGetVisualInfo returned non-nil but zero count?\n",__progname); exit(1); } vpref = 0; for (i=1;i xvi[vpref].depth) vpref = i; visual = xvi[vpref].visual; depth = xvi[vpref].depth; XFree((char *)xvi); } static void setup_font(void) { deffont = 1; if (fontname) { font = XLoadQueryFont(disp,fontname); if (! font) { fprintf(stderr,"%s: can't load font %s, using server default\n",__progname,fontname); } else { deffont = 0; } } if (deffont) { font = XQueryFont(disp,XGContextFromGC(XDefaultGCOfScreen(scr))); } baselineskip = font->ascent + font->descent; } static void setup_colour(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) { wincmap = defcmap; if (visual) wincmap = XCreateColormap(disp,rootwin,visual,AllocNone); setup_colour(foreground,&fgcolour); setup_colour(background,&bgcolour); setup_colour(livecstr,&livecolour); setup_colour(catchupcstr,&catchupcolour); setup_colour(scancstr,&scancolour); setup_colour(scandonecstr,&scandonecolour); setup_colour(rescancstr,&rescancolour); setup_colour(passivelivecstr,&passivelivecolour); setup_colour(passivescancstr,&passivescancolour); setup_colour(brokencstr,&brokencolour); setup_colour(barbgcstr,&barbgcolour); setup_colour(bordercstr,&bdcolour); } static void setup_numbers(void) { if (bordermstr) margin = atoi(bordermstr); if (borderwstr) borderwidth = atoi(borderwstr); } static void setup_windows(void) { int i; int x; int y; unsigned int w; unsigned 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 } }; x = 0; y = 0; bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = width + x - w; if (bits & YNegative) y = height + y - h; w = 1; h = 1; attrmask = 0; attr.background_pixel = bdcolour.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = KeyPressMask; attrmask |= CWEventMask; attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; attrmask |= CWDontPropagate; attr.colormap = wincmap; attrmask |= CWColormap; topwin = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,visual?visual: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.flags = PMinSize | PResizeInc | PWinGravity; normal_hints.x = x; normal_hints.y = y; normal_hints.win_gravity = CenterGravity; 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 |= PSize; normal_hints.min_width = 1; normal_hints.min_height = 1; normal_hints.width_inc = 1; normal_hints.height_inc = 1; wm_hints.flags = InputHint; wm_hints.input = True; class_hints.res_name = deconst(resname); class_hints.res_class = deconst(resclass); XSetWMProperties(disp,topwin,&wn_prop,&in_prop,argv,argc,&normal_hints,&wm_hints,&class_hints); gcvalmask = 0; if (! deffont) { gcval.font = font->fid; gcvalmask |= GCFont; } gcval.foreground = fgcolour.pixel; gcvalmask |= GCForeground; gcval.background = bgcolour.pixel; gcvalmask |= GCBackground; wingc = XCreateGC(disp,topwin,gcvalmask,&gcval); prev_topy = 0; } static void handle_event(XEvent *e) { switch (e->type) { default: break; case Expose: /* XExposeEvent - xexpose */ expose_event((Drawable)e->xexpose.window,e->xexpose.x,e->xexpose.y,e->xexpose.width,e->xexpose.height,e->xexpose.count); break; } } static void rd_x(void *arg __attribute__((__unused__))) { if (XPending(disp) > 0) { do { XEvent e; XNextEvent(disp,&e); handle_event(&e); } while (XQLength(disp) > 0); } } static int flush_x(void *arg __attribute__((__unused__))) { XFlush(disp); return(AIO_BLOCK_NIL); } static void setup_watchers(void) { xflushid = aio_add_block(&flush_x,0); xfd = XConnectionNumber(disp); xid = aio_add_poll(xfd,&aio_rwtest_always,&aio_rwtest_never,&rd_x,0,0); } static void setup_er(void) { er_init(); } static void mainloop(void) { while (1) { aio_pre_poll(); if (aio_do_poll() < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); } aio_post_poll(); } } static void dumpring(void) { int x; int fd; FILE *f; fd = open("lbwatch.ring",O_WRONLY|O_TRUNC|O_APPEND,0); if (fd < 0) return; f = fdopen(fd,"w"); x = ering.t; while (x != ering.h) { fprintf(f,"%lu.%06lu %s\n", (unsigned long int) ering.v[x].stamp.tv_sec, (unsigned long int) ering.v[x].stamp.tv_usec, ering.v[x].text); x = (x ? : ERSIZE) - 1; } fclose(f); } static int err(Display *d, XErrorEvent *ee) { dumpring(); return((*preverr)(d,ee)); } static int ioerr(Display *d) { dumpring(); return((*prevIOerr)(d)); } int main(int, char **); int main(int ac, char **av) { aio_poll_init(); saveargv(ac,av); handleargs(ac,av); XrmInitialize(); disp = open_display(displayname); if (synch) XSynchronize(disp,True); preverr = XSetErrorHandler(&err); prevIOerr = XSetIOErrorHandler(&ioerr); scr = XDefaultScreenOfDisplay(disp); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); rootwin = XRootWindowOfScreen(scr); defcmap = XDefaultColormapOfScreen(scr); setup_db(); maybeset(&geometryspec,get_default_value("geometry","Geometry")); maybeset(&fontname,get_default_value("font","Font")); maybeset(&foreground,get_default_value("foreground","Foreground")); maybeset(&background,get_default_value("background","Background")); maybeset(&livecstr,get_default_value("liveColour","LiveColour")); maybeset(&catchupcstr,get_default_value("catchupColour","CatchupColour")); maybeset(&scancstr,get_default_value("scanColour","ScanColour")); maybeset(&scandonecstr,get_default_value("scanDoneColour","ScanDoneColour")); maybeset(&rescancstr,get_default_value("rescanColour","RescanColour")); maybeset(&passivelivecstr,get_default_value("passiveLiveColour","PassiveLiveColour")); maybeset(&passivescancstr,get_default_value("passiveScanColour","PassiveScanColour")); maybeset(&brokencstr,get_default_value("brokenColour","BrokenColour")); maybeset(&barbgcstr,get_default_value("barBackground","BarBackground")); maybeset(&bordercstr,get_default_value("borderColour","BorderColour")); maybeset(&borderwstr,get_default_value("borderWidth","BorderWidth")); maybeset(&bordermstr,get_default_value("borderMargin","BorderMargin")); maybeset(&name,get_default_value("name","Name")); maybeset(&iconname,get_default_value("iconName","IconName")); maybeset(&visualstr,get_default_value("visual","Visual")); if (!lbds || lbdadd) add_lbd_list(get_default_value("lbd","LBD")); setup_lbd(); setup_visual(); setup_font(); setup_colours(); setup_numbers(); setup_windows(); setup_watchers(); setup_er(); mainloop(); return(0); }