|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  | #include <thread.h> | 
|  | #include <bio.h> | 
|  | #include <mouse.h> | 
|  | #include <keyboard.h> | 
|  |  | 
|  | void keyboardthread(void *v); | 
|  | void mousethread(void *v); | 
|  | void resizethread(void *v); | 
|  | void updateproc(void *v); | 
|  |  | 
|  | enum { | 
|  | STACK = 8196, | 
|  | }; | 
|  |  | 
|  | int nokill; | 
|  | int textmode; | 
|  | char *title; | 
|  |  | 
|  | Biobuf b; | 
|  | Image *light; | 
|  | Image *dark; | 
|  | Image *text; | 
|  | Keyboardctl *kc; | 
|  | Mousectl *mc; | 
|  |  | 
|  | void | 
|  | initcolor(void) | 
|  | { | 
|  | text = display->black; | 
|  | light = allocimagemix(display, DPalegreen, DWhite); | 
|  | dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen); | 
|  | } | 
|  |  | 
|  | Rectangle rbar; | 
|  | vlong n, d; | 
|  | int last; | 
|  | int lastp = -1; | 
|  |  | 
|  | char backup[80]; | 
|  |  | 
|  | void | 
|  | drawbar(void) | 
|  | { | 
|  | int i, j; | 
|  | int p; | 
|  | char buf[400], bar[200]; | 
|  | static char lastbar[200]; | 
|  |  | 
|  | if(n > d || n < 0 || d <= 0) | 
|  | return; | 
|  |  | 
|  | i = (Dx(rbar)*n)/d; | 
|  | p = (n*100LL)/d; | 
|  | if(textmode){ | 
|  | if(Dx(rbar) > 150){ | 
|  | rbar.min.x = 0; | 
|  | rbar.max.x = 150; | 
|  | return; | 
|  | } | 
|  | bar[0] = '|'; | 
|  | for(j=0; j<i; j++) | 
|  | bar[j+1] = '#'; | 
|  | for(; j<Dx(rbar); j++) | 
|  | bar[j+1] = '-'; | 
|  | bar[j++] = '|'; | 
|  | bar[j++] = ' '; | 
|  | sprint(bar+j, "%3d%% ", p); | 
|  | for(i=0; bar[i]==lastbar[i] && bar[i]; i++) | 
|  | ; | 
|  | memset(buf, '\b', strlen(lastbar)-i); | 
|  | strcpy(buf+strlen(lastbar)-i, bar+i); | 
|  | if(buf[0]) | 
|  | write(1, buf, strlen(buf)); | 
|  | strcpy(lastbar, bar); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if(lastp == p && last == i) | 
|  | return; | 
|  |  | 
|  | if(lastp != p){ | 
|  | sprint(buf, "%d%%", p); | 
|  | stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP); | 
|  | lastp = p; | 
|  | } | 
|  |  | 
|  | if(last != i){ | 
|  | draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y), | 
|  | dark, nil, ZP); | 
|  | last = i; | 
|  | } | 
|  | flushimage(display, 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | resize() | 
|  | { | 
|  | Point p, q; | 
|  | Rectangle r; | 
|  |  | 
|  | r = screen->r; | 
|  | draw(screen, r, light, nil, ZP); | 
|  | p = string(screen, addpt(r.min, Pt(4,4)), text, ZP, | 
|  | display->defaultfont, title); | 
|  |  | 
|  | p.x = r.min.x+4; | 
|  | p.y += display->defaultfont->height+4; | 
|  |  | 
|  | q = subpt(r.max, Pt(4,4)); | 
|  | rbar = Rpt(p, q); | 
|  | border(screen, rbar, -2, dark, ZP); | 
|  | last = 0; | 
|  | lastp = -1; | 
|  |  | 
|  | flushimage(display, 1); | 
|  | drawbar(); | 
|  | } | 
|  |  | 
|  | void | 
|  | keyboardthread(void *v) | 
|  | { | 
|  | Rune r; | 
|  |  | 
|  | while(recv(kc->c , &r) == 1){ | 
|  | if ((r == 0x7F || r == 0x03 || r == 'q') && !nokill) | 
|  | threadexitsall("interrupt"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | mousethread(void *v) | 
|  | { | 
|  | USED(v); | 
|  |  | 
|  | while(recv(mc->c, 0) == 1); /* to unblock mc->c */ | 
|  | } | 
|  |  | 
|  | void | 
|  | resizethread(void *v) | 
|  | { | 
|  | USED(v); | 
|  |  | 
|  | while(recv(mc->resizec, 0) == 1){ | 
|  | lockdisplay(display); | 
|  | if(getwindow(display, Refnone) < 0) | 
|  | sysfatal("attach to window: %r"); | 
|  | resize(); | 
|  | unlockdisplay(display); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | updateproc(void *v) | 
|  | { | 
|  | char *p, *f[2]; | 
|  |  | 
|  | sleep(1000); | 
|  | while((p = Brdline(&b, '\n'))){ | 
|  | p[Blinelen(&b)-1] = '\0'; | 
|  | if(tokenize(p, f, 2) != 2) | 
|  | continue; | 
|  | n = strtoll(f[0], 0, 0); | 
|  | d = strtoll(f[1], 0, 0); | 
|  | if(!textmode){ | 
|  | lockdisplay(display); | 
|  | drawbar(); | 
|  | unlockdisplay(display); | 
|  | } else | 
|  | drawbar(); | 
|  | } | 
|  | threadexitsall("success"); | 
|  | } | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: statusbar [-kt] [-W winsize] 'title'\n"); | 
|  | threadexitsall("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | threadmain(int argc, char **argv) | 
|  | { | 
|  | char *p; | 
|  | int lfd; | 
|  |  | 
|  | p = "300x40@100,100"; | 
|  |  | 
|  | ARGBEGIN{ | 
|  | case 'W': | 
|  | p = ARGF(); | 
|  | break; | 
|  | case 't': | 
|  | textmode = 1; | 
|  | break; | 
|  | case 'k': | 
|  | nokill = 1; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | }ARGEND; | 
|  |  | 
|  | if(argc != 1) | 
|  | usage(); | 
|  |  | 
|  | winsize = p; | 
|  |  | 
|  | title = argv[0]; | 
|  |  | 
|  | lfd = dup(0, -1); | 
|  | Binit(&b, lfd, OREAD); | 
|  |  | 
|  | rbar = Rect(0, 0, 60, 1); | 
|  | if (!textmode){ | 
|  | if(initdraw(0, nil, "bar") < 0) | 
|  | sysfatal("initdraw: %r"); | 
|  | initcolor(); | 
|  | if((mc = initmouse(nil, screen)) == nil) | 
|  | sysfatal("initmouse: %r"); | 
|  | if((kc = initkeyboard(nil)) == nil) | 
|  | sysfatal("initkeyboard: %r"); | 
|  | display->locking = 1; | 
|  | threadcreate(resizethread, nil, STACK); | 
|  | threadcreate(keyboardthread, nil, STACK); | 
|  | threadcreate(mousethread, nil, STACK); | 
|  | resize(); | 
|  | unlockdisplay(display); | 
|  | } | 
|  | proccreate(updateproc, nil, STACK); | 
|  | } | 
|  |  |