import statusbar, converted to libthread (Lou Kamenov)
diff --git a/src/cmd/draw/statusbar.c b/src/cmd/draw/statusbar.c
new file mode 100644
index 0000000..fef6d2d
--- /dev/null
+++ b/src/cmd/draw/statusbar.c
@@ -0,0 +1,234 @@
+#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);
+}
+