summaryrefslogtreecommitdiff
path: root/sys/src/cmd/bitsy
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/bitsy
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/bitsy')
-rwxr-xr-xsys/src/cmd/bitsy/bitsyload.c130
-rwxr-xr-xsys/src/cmd/bitsy/keyboard.c437
-rwxr-xr-xsys/src/cmd/bitsy/light.rc14
-rwxr-xr-xsys/src/cmd/bitsy/mkfile21
-rwxr-xr-xsys/src/cmd/bitsy/params.c83
-rwxr-xr-xsys/src/cmd/bitsy/pencal.c188
-rwxr-xr-xsys/src/cmd/bitsy/prompter.c303
7 files changed, 1176 insertions, 0 deletions
diff --git a/sys/src/cmd/bitsy/bitsyload.c b/sys/src/cmd/bitsy/bitsyload.c
new file mode 100755
index 000000000..a7c6d5801
--- /dev/null
+++ b/sys/src/cmd/bitsy/bitsyload.c
@@ -0,0 +1,130 @@
+#include <u.h>
+#include <libc.h>
+
+enum
+{
+ Magic= 0x5a5abeef,
+};
+
+typedef struct Method Method;
+struct Method {
+ char *verb;
+ char *part;
+ char *file;
+};
+
+Method method[] =
+{
+ { "k", "/dev/flash/kernel", "/sys/src/9/bitsy/9bitsy" },
+ { "r", "/dev/flash/ramdisk", "/sys/src/9/bitsy/paqdisk" },
+ { "u", "/dev/flash/user", "/sys/src/9/bitsy/user" },
+};
+
+void
+leputl(uchar *p, ulong x)
+{
+ *p++ = x;
+ *p++ = x>>8;
+ *p++ = x>>16;
+ *p = x>>24;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s k|r [file]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ char *file;
+ int ctl, in, out;
+ int i, n;
+ uchar *buf;
+ char ctlfile[64];
+ char ctldata[1024];
+ char *args[10];
+ Dir *d;
+ ulong nsects, sectsize;
+ Method *m;
+
+ ARGBEGIN {
+ } ARGEND;
+
+ if(argc == 0)
+ usage();
+
+ for(m = method; m < method + nelem(method); m++)
+ if(strcmp(argv[0], m->verb) == 0)
+ break;
+ if(m == method + nelem(method))
+ usage();
+
+ if(argc < 2)
+ file = m->file;
+ else
+ file = argv[1];
+
+ in = open(file, OREAD);
+ if(in < 0)
+ sysfatal("%s: %r", file);
+ d = dirfstat(in);
+ if(d == nil)
+ sysfatal("stating %s: %r", file);
+
+ out = open(m->part, OWRITE);
+ if(out < 0)
+ sysfatal("%s: %r", m->part);
+ sprint(ctlfile, "%sctl", m->part);
+ ctl = open(ctlfile, ORDWR);
+ if(ctl < 0)
+ sysfatal("%s: %r", ctlfile);
+
+ i = read(ctl, ctldata, sizeof(ctldata) - 1);
+ if (i <= 0)
+ sysfatal("%s: %r", ctlfile);
+ ctldata[i] = '\0';
+ i = tokenize(ctldata, args, nelem(args));
+ if(i < 7)
+ sysfatal("bad flash geometry");
+
+ nsects = atoi(args[5]);
+ sectsize = atoi(args[6]);
+ if(nsects < 3)
+ sysfatal("unreasonable value for nsects: %lud", nsects);
+ if(sectsize < 512)
+ sysfatal("unreasonable value for sectsize: %lud", sectsize);
+
+ /* allocate a buffer and read in the whole file */
+ n = d->length;
+ buf = malloc(n + sectsize);
+ if(buf == nil)
+ sysfatal("not enough room to read in file: %r");
+
+ print("reading %d bytes of %s\n", n, file);
+ if(readn(in, buf, n) != n)
+ sysfatal("error reading file: %r");
+ close(in);
+
+ memset(buf + n, 0, sectsize);
+ n = ((n+sectsize-1)/sectsize)*sectsize;
+
+ if (nsects * sectsize < n)
+ sysfatal("file too large (%d) for partition (%lud)", n, nsects * sectsize);
+
+ print("erasing %s\n", m->part);
+ if(fprint(ctl, "erase") < 0)
+ sysfatal("erase %s: %r", ctlfile);
+ close(ctl);
+ print("writing %s\n", m->part);
+
+ for (i = 0; i < n; i += sectsize)
+ if(write(out, buf + i, sectsize) != sectsize)
+ sysfatal("writing %s at %d: %r", file, i);
+
+ print("write done\n");
+ close(in);
+ close(out);
+}
diff --git a/sys/src/cmd/bitsy/keyboard.c b/sys/src/cmd/bitsy/keyboard.c
new file mode 100755
index 000000000..0972bcd75
--- /dev/null
+++ b/sys/src/cmd/bitsy/keyboard.c
@@ -0,0 +1,437 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <control.h>
+#include <scribble.h>
+
+int debug = 0;
+typedef struct Win Win;
+struct Win {
+ int n;
+ int dirty;
+ char *label;
+ Control *button;
+};
+
+Win *win;
+int nwin;
+int mwin;
+int onwin;
+int rows, cols;
+int kbdonly;
+int scribbleleft;
+int winshow;
+
+Channel *kc;
+Channel *ec;
+Channel *tc;
+Rectangle r, rk, rs, rw;
+Font *keyfont, *keyctlfont;
+
+enum{
+ Back,
+ Shade,
+ Light,
+ Mask,
+ Ncol
+};
+
+enum {
+ kbdheight = 2 + 5*13,
+};
+
+enum {
+ Keyback = 0xeeee9eff,
+ Keyshade = 0xaaaa55ff,
+ Keylight = DWhite,
+ Keymask = 0x0C0C0C0C,
+};
+
+Image *colors[Ncol];
+
+Control *kbd;
+Control *scrib;
+Control *boxbox;
+Controlset *cs;
+
+int ctldeletequits = 1;
+int wctl;
+
+int
+hidden(void)
+{
+ char buf[128];
+ int n;
+
+ close(wctl);
+ if ((wctl = open("/dev/wctl", ORDWR)) < 0)
+ return 0;
+ n = read(wctl, buf, sizeof buf-1);
+ if (n <= 0)
+ sysfatal("wctl read: %r");
+ buf[n] = 0;
+ return strstr(buf, "visible") == nil;
+}
+
+void
+mousemux(void *v)
+{
+ Mouse m;
+ Channel *c;
+ int ob;
+
+ c = v;
+
+ for(ob = 0;;ob = m.buttons){
+ if(recv(c, &m) < 0)
+ break;
+ if ((m.buttons & 0x20) == 0) {
+ if (ob & 0x20) {
+ /* hide button just came up */
+ if (hidden()) {
+ if (debug) fprint(2, "unhide");
+ if (fprint(wctl, "unhide") <= 0)
+ fprint(2, "unhide failed: %r\n");
+ } else {
+ if (debug) fprint(2, "hide");
+ if (fprint(wctl, "hide") <= 0)
+ fprint(2, "hide failed: %r\n");
+ }
+ } else
+ send(cs->mousec, &m);
+ }
+ }
+}
+
+void
+refreshwin(void)
+{
+ char label[128];
+ int i, fd, lfd, n, nr, nw, m;
+ Dir *pd;
+
+ if((fd = open("/dev/wsys", OREAD)) < 0)
+ return;
+
+ nw = 0;
+/* i'd rather read one at a time but rio won't let me */
+ while((nr=dirread(fd, &pd)) > 0){
+ for(i=0; i<nr; i++){
+ n = atoi(pd[i].name);
+ sprint(label, "/dev/wsys/%d/label", n);
+ if((lfd = open(label, OREAD)) < 0)
+ continue;
+ m = read(lfd, label, sizeof(label)-1);
+ close(lfd);
+ if(m < 0)
+ continue;
+ label[m] = '\0';
+ if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){
+ nw++;
+ continue;
+ }
+
+ if(nw < nwin){
+ free(win[nw].label);
+ win[nw].label = nil;
+ }
+ if(nw >= mwin){
+ mwin += 8;
+ win = ctlrealloc(win, mwin*sizeof(win[0]));
+ memset(&win[mwin-8], 0, 8*sizeof(win[0]));
+ }
+ win[nw].n = n;
+ win[nw].label = ctlstrdup(label);
+ win[nw].dirty = 1;
+ sprint(label, "%d", nw);
+ if (win[nw].button == nil){
+ win[nw].button = createtextbutton(cs, label);
+ chanprint(cs->ctl, "%q font keyfont", label);
+ chanprint(cs->ctl, "%q image keyback", label);
+ chanprint(cs->ctl, "%q pressedtextcolor red", label);
+ chanprint(cs->ctl, "%q mask transparent", label);
+ chanprint(cs->ctl, "%q border 1", label);
+ chanprint(cs->ctl, "%q bordercolor black", label);
+ chanprint(cs->ctl, "%q align centerleft", label);
+ chanprint(cs->ctl, "%q size 16 %d 512 %d", label, keyfont->height+2, keyfont->height+2);
+ controlwire(win[nw].button, "event", ec);
+ }
+ if (nw >= nwin){
+ activate(win[nw].button);
+ chanprint(cs->ctl, "cols add %q", label);
+ }
+ chanprint(cs->ctl, "%q text %q", win[nw].button->name, win[nw].label);
+ nw++;
+ }
+ }
+ for(i = nw; i < nwin; i++){
+ free(win[i].label);
+ win[i].label = nil;
+ deactivate(win[i].button);
+ chanprint(cs->ctl, "cols remove %q", win[i].button->name);
+ }
+ nwin = nw;
+ close(fd);
+ if (rw.max.x)
+ chanprint(cs->ctl, "cols rect %R\ncols show", rw);
+}
+
+void
+resizecontrolset(Controlset*)
+{
+ int fd;
+ char buf[61];
+
+
+ if(getwindow(display, Refnone) < 0)
+ ctlerror("resize failed: %r");
+
+ if (hidden()) {
+ if (debug) fprint(2, "resizecontrolset: hidden\n");
+ return;
+ }
+
+ fd = open("/dev/screen", OREAD);
+ if (fd < 0) {
+ r = display->image->r;
+ if (debug) fprint(2, "display->imgae->r: %R\n", r);
+ } else {
+ if (read(fd, buf, 60) != 60)
+ sysfatal("resizecontrolset: read: /dev/screen: %r");
+ close(fd);
+ buf[60] = '\0';
+ r.min.x = atoi(buf+1+1*12);
+ r.min.y = atoi(buf+1+2*12);
+ r.max.x = atoi(buf+1+3*12);
+ r.max.y = atoi(buf+1+4*12);
+ if (debug) fprint(2, "/dev/screen: %R\n", r);
+ }
+ r = insetrect(r, 4);
+ r.min.y = r.max.y - kbdheight - 2*Borderwidth;
+ if (debug) fprint(2, "before eqrect: %R\n", r);
+ if (eqrect(r, screen->r) == 0) {
+ if (debug) fprint(2, "resizecontrolset: resize %R\n", r);
+ if (fprint(wctl, "resize -r %R", insetrect(r, -4)) <= 0) {
+ fprint(2, "resizecontrolset: resize failed\n");
+ }
+ return;
+ }
+
+ if (debug) fprint(2, "after eqrect: %R\n", r);
+ rk = r;
+ if (winshow){
+ rw = rk;
+ rw.min.x = (3*rk.max.x + rk.min.x)/4;
+ rk.max.x = rw.min.x;
+ if (debug) fprint(2, "rw: rect %R\n", rw);
+ chanprint(cs->ctl, "cols rect %R\ncols show", rw);
+ }
+ if (kbdonly) {
+ chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
+ } else {
+ rs = rk;
+ if (scribbleleft){
+ rk.min.x = (rk.max.x + 3*rk.min.x)/4;
+ rs.max.x = rk.min.x;
+ }else{
+ rk.max.x = (3*rk.max.x + rk.min.x)/4;
+ rs.min.x = rk.max.x;
+ }
+ chanprint(cs->ctl, "keyboard rect %R\nkeyboard show", rk);
+ if (debug) fprint(2, "rk: rect %R\nkeyboard show\n", rk);
+ chanprint(cs->ctl, "scribble rect %R\nscribble show", rs);
+ if (debug) fprint(2, "rs: rect %R\nscribble show\n", rs);
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: keyboard\n");
+ threadexitsall("usage");
+}
+
+void
+timerproc(void*v)
+{
+ Channel *c;
+
+ c = v;
+ for(;;){
+ sleep(5000);
+ sendul(c, 1);
+ }
+}
+
+void
+watchproc(void*)
+{
+
+ for(;;){}
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ int i, n, kbdfd;
+ char str[UTFmax+1];
+ Rune r;
+ Mousectl *mousectl;
+ Channel *mtok;
+ char *e, buf[128], *args[8];
+ int fd;
+
+ ARGBEGIN{
+ case 'w':
+ winshow++;
+ break;
+ case 'l':
+ scribbleleft++;
+ break;
+ case 'n':
+ kbdonly++;
+ break;
+ case 'd':
+ ScribbleDebug++;
+ debug++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 0)
+ usage();
+
+ kbdfd = open("/dev/kbdin", OWRITE);
+ if (kbdfd < 0 && (kbdfd = open("#r/kbdin", OWRITE)) < 0) {
+ if (debug) fprint(2, "open %s: %r\n", "#r/kbdin");
+ kbdfd = 1;
+ }
+
+ initdraw(0, 0, "keyboard");
+ mousectl = initmouse(nil, screen);
+
+ wctl = open("/dev/wctl", ORDWR);
+ if (wctl < 0) {
+ fprint(2, "open %s: %r\n", "/dev/wctl");
+ wctl = 2; /* for debugging */
+ }
+
+ mtok = chancreate(sizeof(Mouse), 0);
+
+ initcontrols();
+
+ cs = newcontrolset(screen, nil, mtok, mousectl->resizec);
+
+ threadcreate(mousemux, mousectl->c, 4096);
+
+ kc = chancreate(sizeof(char*), 0);
+ tc = chancreate(sizeof(int), 1);
+ ec = chancreate(sizeof(char*), 1);
+
+ colors[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback);
+ namectlimage(colors[Back], "keyback");
+ colors[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight);
+ namectlimage(colors[Light], "keylight");
+ colors[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade);
+ namectlimage(colors[Shade], "keyshade");
+ colors[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask);
+ namectlimage(colors[Shade], "keymask");
+ keyfont = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font");
+ namectlfont(keyfont, "keyfont");
+ keyctlfont = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font");
+ namectlfont(keyctlfont, "keyctlfont");
+
+ kbd = createkeyboard(cs, "keyboard");
+ chanprint(cs->ctl, "keyboard font keyfont keyctlfont");
+ chanprint(cs->ctl, "keyboard image keyback");
+ chanprint(cs->ctl, "keyboard light keylight");
+ chanprint(cs->ctl, "keyboard mask keymask");
+ chanprint(cs->ctl, "keyboard border 1");
+ chanprint(cs->ctl, "keyboard size %d %d %d %d", 246, 2 + 5 * (keyfont->height + 1), 512, 256);
+ controlwire(kbd, "event", kc);
+
+ if (kbdonly == 0){
+ scrib = createscribble(cs, "scribble");
+ if (scrib == nil)
+ sysfatal("createscribble");
+ chanprint(cs->ctl, "scribble font keyfont");
+ chanprint(cs->ctl, "scribble image keyback");
+ chanprint(cs->ctl, "scribble border 1");
+ controlwire(scrib, "event", kc);
+ }
+
+ if (winshow){
+ boxbox = createboxbox(cs, "cols");
+
+ chanprint(cs->ctl, "cols border 2");
+ chanprint(cs->ctl, "cols bordercolor keyback");
+ }
+
+ resizecontrolset(nil);
+
+ activate(kbd);
+ if (kbdonly == 0)
+ activate(scrib);
+ if (winshow){
+ refreshwin();
+ proccreate(timerproc, tc, 2048);
+ }
+
+ for(;;){
+ Alt a[] = {
+ { kc, &e, CHANRCV },
+ { ec, &e, CHANRCV },
+ { tc, &n, CHANRCV },
+ { nil, nil, CHANEND }
+ };
+ switch(alt(a)){
+ case 0: /* Keyboard */
+ n = tokenize(e, args, nelem(args));
+ if(n == 3)
+ if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0)
+ if(strcmp(args[1], "value") == 0){
+ n = atoi(args[2]);
+ if(n <= 0xFFFF){
+ r = n;
+ i = runetochar(str, &r);
+ write(kbdfd, str, i);
+ }
+ }
+ break;
+ case 1: /* Button event */
+ n = tokenize(e, args, nelem(args));
+ if (n != 3 || strcmp(args[1], "value"))
+ sysfatal("event string");
+ i = atoi(args[0]);
+ if (i < 0 || i >= nwin)
+ sysfatal("win out of range: %d of %d", i, nwin);
+ n = atoi(args[2]);
+ if (n){
+ sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
+ if((fd = open(buf, OWRITE)) >= 0){
+ while (write(fd, "top\n", 4) < 0) {
+ /* wait until mouse comes up */
+ rerrstr(buf, sizeof buf);
+ if (strncmp(buf, "action disallowed when mouse active", sizeof buf)){
+ fprint(2, "write top: %s\n", buf);
+ break;
+ }
+ sleep(100);
+ }
+ if (write(fd, "current\n", 8) < 0)
+ fprint(2, "write current: %r\n");
+ close(fd);
+ }
+ chanprint(cs->ctl, "%q value 0", win[i].button->name);
+ }
+ break;
+ case 2:
+ refreshwin();
+ break;
+ }
+ }
+}
diff --git a/sys/src/cmd/bitsy/light.rc b/sys/src/cmd/bitsy/light.rc
new file mode 100755
index 000000000..d17cd8212
--- /dev/null
+++ b/sys/src/cmd/bitsy/light.rc
@@ -0,0 +1,14 @@
+#!/bin/rc
+
+#master file is /sys/src/cmd/bitsy/light.rc
+
+switch($1){
+case on
+ echo -n 2 1 0x80 > /dev/backlight
+case off
+ echo -n 2 0 0x80 > /dev/backlight
+case auto
+ echo -n 1 1 0x80 > /dev/backlight
+case *
+ echo -n 2 1 $1 > /dev/backlight
+}
diff --git a/sys/src/cmd/bitsy/mkfile b/sys/src/cmd/bitsy/mkfile
new file mode 100755
index 000000000..806683d80
--- /dev/null
+++ b/sys/src/cmd/bitsy/mkfile
@@ -0,0 +1,21 @@
+</$objtype/mkfile
+
+TARG=\
+ bitsyload\
+ pencal\
+ prompter\
+ keyboard\
+ light\
+ params\
+
+BIN=/$objtype/bin/bitsy
+</sys/src/cmd/mkmany
+
+light.$O:V:
+ # nothing
+
+$O.light: light.rc
+ cp light.rc $target
+
+light.install:
+ cp light.rc $BIN/light
diff --git a/sys/src/cmd/bitsy/params.c b/sys/src/cmd/bitsy/params.c
new file mode 100755
index 000000000..4d27930e9
--- /dev/null
+++ b/sys/src/cmd/bitsy/params.c
@@ -0,0 +1,83 @@
+#include <u.h>
+#include <libc.h>
+
+void
+erase(char *part)
+{
+ char file[256];
+ int fd;
+
+ snprint(file, sizeof file, "%sctl", part);
+ fd = open(file, ORDWR);
+ if(fd < 0)
+ return;
+ fprint(fd, "erase");
+ close(fd);
+}
+
+char*
+readfile(char *file)
+{
+ char buf[512];
+ int n, fd;
+ uchar *p;
+
+ fd = open(file, OREAD);
+ if(fd < 0)
+ sysfatal("opening %s: %r", file);
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if(n < 0)
+ return "";
+ buf[n] = 0;
+ for(p = (uchar*)buf; *p; p++)
+ if(*p == 0xff){
+ *p = 0;
+ break;
+ }
+ return strdup(buf);
+}
+
+void
+writefile(char *file, char *data)
+{
+ int fd;
+
+ fd = open(file, OWRITE);
+ if(fd < 0)
+ fd = create(file, OWRITE, 0664);
+ if(fd < 0)
+ return;
+ write(fd, data, strlen(data));
+ close(fd);
+}
+
+void
+main(int argc, char **argv)
+{
+ int from = 0;
+ char *params;
+ char *file = "/tmp/tmpparams";
+ char *part;
+
+ ARGBEGIN {
+ case 'f':
+ from++;
+ break;
+ } ARGEND;
+
+ if(argc)
+ part = argv[0];
+ else
+ part = "/dev/flash/user";
+
+ if(from){
+ params = readfile(part);
+ writefile(file, params);
+ } else {
+ params = readfile(file);
+ erase(part);
+ writefile(part, params);
+ free(params);
+ }
+}
diff --git a/sys/src/cmd/bitsy/pencal.c b/sys/src/cmd/bitsy/pencal.c
new file mode 100755
index 000000000..4ce830010
--- /dev/null
+++ b/sys/src/cmd/bitsy/pencal.c
@@ -0,0 +1,188 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+int debug = 0;
+
+struct Cal {
+ double scalex;
+ double transx;
+ double scaley;
+ double transy;
+} cal;
+
+/* Calibrate the pen */
+
+Point pts[5];
+
+Point pens[5];
+
+Point up = { 0, -10};
+Point down = { 0, 10};
+Point left = {-10, 0};
+Point right = { 10, 0};
+
+Point
+pen2scr(Point p)
+{
+ return Pt(p.x * cal.scalex / 65536.0 + cal.transx,
+ p.y * cal.scaley / 65536.0 + cal.transy);
+}
+
+Point
+scr2pen(Point p)
+{
+ return Pt((p.x - cal.transx) * 65536.0 / cal.scalex,
+ (p.y + cal.transy) * 65536.0 / cal.scaley);
+}
+
+void
+cross(Point p) {
+ draw(screen, screen->r, display->white, nil, ZP);
+ line(screen, addpt(p, up), addpt(p, down), Endsquare, Endsquare, 0, display->black, ZP);
+ line(screen, addpt(p, left), addpt(p, right), Endsquare, Endsquare, 0, display->black, ZP);
+ flushimage(display, 1);
+}
+
+Point
+getmouse(int mouse) {
+ static char buf[50];
+ int x, y, b, n;
+ Point p;
+
+ n = 0;
+ p.x = p.y = 0;
+ do{
+ if (read(mouse, buf, 48) != 48)
+ sysfatal("read: %r");
+ if (debug > 1) fprint(2, "%s\n", buf);
+ if (buf[0] == 'r') {
+ b = 1;
+ continue;
+ }
+ if (buf[0] != 'm')
+ sysfatal("mouse message: %s", buf);
+ x = strtol(buf+1, nil, 10);
+ y = strtol(buf+13, nil, 10);
+ b = strtol(buf+25, nil, 10);
+ p.x = (n * p.x + x)/(n+1);
+ p.y = (n * p.y + y)/(n+1);
+ n++;
+ }while (b & 0x7);
+ return p;
+}
+
+void
+main(int argc, char **argv) {
+ int i, mouse, mousectl, wctl, ntries;
+ Rectangle r, oldsize;
+
+ ARGBEGIN{
+ case 'd':
+ debug = 1;
+ break;
+ }ARGEND;
+
+ if((mouse = open("/dev/mouse", OREAD)) < 0
+ && (mouse = open("#m/mouse", OREAD)) < 0)
+ sysfatal("#m/mouse: %r");
+
+ mousectl = open("#m/mousectl", ORDWR);
+ if(mousectl < 0)
+ sysfatal("#m/mousectl: %r");
+
+ if(initdraw(nil, nil, "calibrate") < 0)
+ sysfatal("initdraw: %r");
+
+ wctl = -1;
+ for(ntries = 0; ntries < 3; ntries++){
+ r = insetrect(display->image->r, 2);
+
+ if(wctl < 0)
+ wctl = open("/dev/wctl", ORDWR);
+ if(wctl >= 0){
+ char buf[4*12+1];
+
+ buf[48] = 0;
+ oldsize = screen->r;
+ if(fprint(wctl, "resize -r %R", r) <= 0)
+ sysfatal("write /dev/wctl, %r");
+ if(getwindow(display, Refbackup) < 0)
+ sysfatal("getwindow");
+ if(debug) fprint(2, "resize: %R\n", screen->r);
+
+ if(read(mousectl, buf, 48) != 48)
+ sysfatal("read mousectl: %r");
+ if(debug > 1) fprint(2, "mousectl %s\n", buf);
+ if(buf[0] != 'c')
+ sysfatal("mousectl message: %s", buf);
+ cal.scalex = strtol(buf+ 1, nil, 10);
+ cal.scaley = strtol(buf+13, nil, 10);
+ cal.transx = strtol(buf+25, nil, 10);
+ cal.transy = strtol(buf+37, nil, 10);
+ }else{
+ fprint(mousectl, "calibrate");
+ cal.scalex = 1<<16;
+ cal.scaley = 1<<16;
+ cal.transx = 0;
+ cal.transy = 0;
+ }
+
+ fprint(2, "calibrate %ld %ld %ld %ld (old)\n",
+ (long)cal.scalex, (long)cal.scaley, (long)cal.transx, (long)cal.transy);
+
+ if(debug)
+ fprint(2, "screen coords %R\n", screen->r);
+ pts[0] = addpt(Pt( 16, 16), screen->r.min);
+ pts[1] = addpt(Pt( 16, -16), Pt(screen->r.min.x, screen->r.max.y));
+ pts[2] = addpt(Pt(-16, 16), Pt(screen->r.max.x, screen->r.min.y));
+ pts[3] = addpt(Pt(-16, -16), screen->r.max);
+ pts[4] = Pt((screen->r.max.x + screen->r.min.x)/2,
+ (screen->r.max.y + screen->r.min.y)/2);;
+
+ for(i = 0; i < 4; i++){
+ cross(pts[i]);
+ pens[i] = scr2pen(getmouse(mouse));
+ if (debug) fprint(2, "%P\n", pens[i]);
+ }
+
+ cal.scalex = (pts[2].x + pts[3].x - pts[0].x - pts[1].x) * 65536.0 /
+ (pens[2].x + pens[3].x - pens[0].x - pens[1].x);
+ cal.scaley = (pts[1].y + pts[3].y - pts[0].y - pts[2].y) * 65536.0 /
+ (pens[1].y + pens[3].y - pens[0].y - pens[2].y);
+ cal.transx = pts[0].x - (pens[0].x*cal.scalex) / 65536.0;
+ cal.transy = pts[0].y - (pens[0].y*cal.scaley) / 65536.0;
+
+ if(debug)
+ fprint(2, "scale [%f, %f], trans [%f, %f]\n",
+ cal.scalex, cal.scaley, cal.transx, cal.transy);
+
+ fprint(mousectl, "calibrate %ld %ld %ld %ld",
+ (long)cal.scalex, (long)cal.scaley, (long)cal.transx, (long)cal.transy);
+
+ cross(pts[4]);
+ pens[4] = getmouse(mouse);
+
+ draw(screen, screen->r, display->white, nil, ZP);
+ flushimage(display, 1);
+
+ if(abs(pts[4].x-pens[4].x) <= 4 && abs(pts[4].y-pens[4].y) <= 4){
+ fprint(2, "Calibration ok: %P -> %P\n", pts[4], pens[4]);
+ break;
+ }
+ fprint(2, "Calibration inaccurate: %P -> %P\n", pts[4], pens[4]);
+ }
+ print("calibrate='%ld %ld %ld %ld'\n",
+ (long)cal.scalex, (long)cal.scaley, (long)cal.transx, (long)cal.transy);
+
+ if(debug)
+ for(i = 0; i < 4; i++){
+ cross(pts[i]);
+ pens[i] = getmouse(mouse);
+ if (debug) fprint(2, "%P\n", pens[i]);
+ }
+
+ if(wctl >= 0)
+ fprint(wctl, "resize -r %R", oldsize);
+
+}
diff --git a/sys/src/cmd/bitsy/prompter.c b/sys/src/cmd/bitsy/prompter.c
new file mode 100755
index 000000000..9a76a0d0e
--- /dev/null
+++ b/sys/src/cmd/bitsy/prompter.c
@@ -0,0 +1,303 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <control.h>
+
+int Nline;
+
+enum{
+ Back,
+ Shade,
+ Light,
+ Mask,
+ Ncol
+};
+
+enum {
+ Keyback = 0xeeee9eff,
+ Keyshade = 0xaaaa55ff,
+ Keylight = DWhite,
+ Keymask = 0x0C0C0C0C,
+};
+
+Image *cols[Ncol];
+
+int nline;
+
+char *lines[24]; /* plus one so last line gets terminated by getfields */
+Control *entry[24];
+Control *kbd;
+Control *scrib;
+Controlset *keyboard;
+Controlset *text;
+int kbdy;
+
+int resizeready;
+
+int ctldeletequits = 1;
+
+Channel *eventchan;
+
+void
+resizecontrolset(Controlset *cs)
+{
+ int i;
+ Rectangle r, r1;
+
+ if(cs != keyboard)
+ return;
+ if (!resizeready)
+ return;
+ if(getwindow(display, Refnone) < 0)
+ ctlerror("resize failed: %r");
+ draw(screen, screen->r, cols[Back], nil, ZP);
+ r = insetrect(screen->r, 4);
+ for(i=0; i<Nline; i++){
+ r.max.y = r.min.y + font->height;
+ ctlprint(entry[i], "rect %R", r);
+ ctlprint(entry[i], "show");
+ r.min.y = r.max.y;
+ }
+ kbdy = r.min.y;
+
+ r = screen->r;
+ r.min.y = kbdy;
+ r.max.y = screen->r.max.y;
+ r.min.y = r.max.y - 2*2 - 5*13;
+ if(r.min.y >= r.max.y)
+ r.min.y = r.max.y;
+ r1 = r;
+ if(scrib)
+ r.max.x = (3*r.max.x + r.min.x)/4;
+ ctlprint(kbd, "rect %R", r);
+ ctlprint(kbd, "show");
+ if(scrib){
+ r1.min.x = (3*r1.max.x + r1.min.x)/4;
+ ctlprint(scrib, "rect %R", r1);
+ ctlprint(scrib, "show");
+ }
+}
+
+void
+readall(char *s)
+{
+ char *buf;
+ int fd;
+ Dir *d;
+
+ fd = open(s, OREAD);
+ if(fd < 0){
+ fprint(2, "prompter: can't open %s: %r\n", s);
+ exits("open");
+ }
+ d = dirfstat(fd);
+ if(d == nil){
+ fprint(2, "prompter: can't stat %s: %r\n", s);
+ exits("stat");
+ }
+ buf = ctlmalloc(d->length+1); /* +1 for NUL on end */
+ if(read(fd, buf, d->length) != d->length){
+ fprint(2, "prompter: can't read %s: %r\n", s);
+ exits("stat");
+ }
+ nline = getfields(buf, lines, nelem(lines), 0, "\n");
+ free(d);
+ close(fd);
+}
+
+void
+mousemux(void *v)
+{
+ Mouse m;
+ Channel *c;
+
+ c = v;
+
+ for(;;){
+ if(recv(c, &m) < 0)
+ break;
+ if(m.buttons & 0x20) {
+ sendp(eventchan, "mouse: exit");
+ break;
+ }
+ if(m.xy.y >= kbdy)
+ send(keyboard->mousec, &m);
+ else
+ send(text->mousec, &m);
+ }
+}
+
+void
+resizemux(void *v)
+{
+ Channel *c;
+
+ c = v;
+
+ for(;;){
+ if(recv(c, nil) < 0)
+ break;
+ send(keyboard->resizec, nil);
+ send(text->resizec, nil);
+ }
+}
+
+void
+writeall(char *s)
+{
+ int fd;
+ int i, n;
+
+ fd = create(s, OWRITE, 0666);
+ if(fd < 0){
+ fprint(2, "prompter: can't create %s: %r\n", s);
+ exits("open");
+ }
+
+ for(n=Nline; --n>=0; )
+ if(lines[n][0] != '\0')
+ break;
+
+ for(i=0; i<=n; i++)
+ fprint(fd, "%s\n", lines[i]);
+ close(fd);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: prompter file\n");
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+ char *s;
+ Font *f;
+ int i, n;
+ char buf[32], *args[3];
+ Keyboardctl *kbdctl;
+ Mousectl *mousectl;
+ Rune r;
+ Channel *mtok, *mtot, *ktok, *rtok, *rtot;
+ int noscrib;
+
+ noscrib = 0;
+ ARGBEGIN{
+ case 'n':
+ noscrib++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+
+ readall(argv[0]);
+
+ initdraw(0, 0, "prompter");
+ mousectl = initmouse(nil, screen);
+ kbdctl = initkeyboard(nil);
+
+ mtok = chancreate(sizeof(Mouse), 0);
+ mtot = chancreate(sizeof(Mouse), 0);
+ ktok = chancreate(sizeof(Rune), 20);
+ rtok = chancreate(sizeof(int), 2);
+ rtot = chancreate(sizeof(int), 2);
+
+ initcontrols();
+
+ keyboard = newcontrolset(screen, ktok, mtok, rtok);
+ text = newcontrolset(screen, kbdctl->c, mtot, rtot);
+ text->clicktotype = 1;
+
+ threadcreate(mousemux, mousectl->c, 4096);
+ threadcreate(resizemux, mousectl->resizec, 4096);
+
+ eventchan = chancreate(sizeof(char*), 0);
+
+ cols[Back] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyback);
+ namectlimage(cols[Back], "keyback");
+ cols[Light] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keylight);
+ namectlimage(cols[Light], "keylight");
+ cols[Shade] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, Keyshade);
+ namectlimage(cols[Shade], "keyshade");
+ cols[Mask] = allocimage(display, Rect(0,0,1,1), RGBA32, 1, Keymask);
+ namectlimage(cols[Shade], "keymask");
+ f = openfont(display, "/lib/font/bit/lucidasans/boldlatin1.6.font");
+ namectlfont(f, "bold");
+ f = openfont(display, "/lib/font/bit/lucidasans/unicode.6.font");
+ namectlfont(f, "roman");
+ font = f;
+
+ Nline = (screen->r.max.y - 2*2 - 5*13 - 8)/font->height;
+ if (Nline > nelem(entry)) Nline = nelem(entry);
+
+ for(i=0; i<Nline; i++){
+ snprint(buf, sizeof buf, "line.%.2d", i);
+ entry[i] = createentry(text, buf);
+ ctlprint(entry[i], "font roman");
+ ctlprint(entry[i], "image keyback");
+ if(i < nline)
+ ctlprint(entry[i], "value %q", lines[i]);
+ controlwire(entry[i], "event", eventchan);
+ activate(entry[i]);
+ }
+
+ kbd = createkeyboard(keyboard, "keyboard");
+ ctlprint(kbd, "font bold roman");
+ ctlprint(kbd, "image keyback");
+ ctlprint(kbd, "light keylight");
+ ctlprint(kbd, "mask keymask");
+ ctlprint(kbd, "border 1");
+ controlwire(kbd, "event", eventchan);
+
+ scrib = nil;
+ if(!noscrib){
+ scrib = createscribble(keyboard, "scribble");
+ ctlprint(scrib, "font bold");
+ ctlprint(scrib, "image keyback");
+ ctlprint(scrib, "border 1");
+ controlwire(scrib, "event", eventchan);
+ activate(scrib);
+ }
+
+ activate(kbd);
+ resizeready = 1;
+ resizecontrolset(keyboard);
+
+ for(;;){
+ s = recvp(eventchan);
+ n = tokenize(s, args, nelem(args));
+ if(n == 2 && strcmp(args[0], "mouse:")==0 && strcmp(args[1], "exit")==0)
+ break;
+ if(n == 3)
+ if(strcmp(args[0], "keyboard:")==0 || strcmp(args[0], "scribble:")==0)
+ if(strcmp(args[1], "value") == 0){
+ n = atoi(args[2]);
+ if(n == '\033') /* Escape exits */
+ break;
+ if(n <= 0xFFFF){
+ r = n;
+ send(kbdctl->c, &r);
+ }
+ }
+ }
+
+ for(i=0; i<Nline; i++){
+ ctlprint(entry[i], "data");
+ lines[i] = ctlstrdup(recvp(entry[i]->data));
+ }
+
+ writeall(argv[0]);
+
+ draw(screen, screen->r, display->white, nil, ZP);
+ flushimage(display, 1);
+
+ threadexitsall(nil);
+}