an old saddle
diff --git a/src/cmd/proof/screen.c b/src/cmd/proof/screen.c
new file mode 100644
index 0000000..dccfe01
--- /dev/null
+++ b/src/cmd/proof/screen.c
@@ -0,0 +1,315 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <cursor.h>
+#include <event.h>
+#include <bio.h>
+#include "proof.h"
+
+static	int	checkmouse(void);
+/* static	int	buttondown(void); */
+static	char	*getmousestr(void);
+static	char	*getkbdstr(int);
+
+extern	Cursor	blot;
+extern	char	*track;
+
+Mouse	mouse;
+
+void
+mapscreen(void)
+{
+	if(initdraw(0, 0, "proof") < 0){
+		fprint(2, "proof: initdraw failed: %r\n");
+		exits("initdraw");
+	}
+	einit(Ekeyboard|Emouse);
+}
+
+void
+clearscreen(void)
+{
+	draw(screen, screen->r, display->black, nil, ZP);
+}
+
+void
+screenprint(char *fmt, ...)
+{
+	char buf[100];
+	Point p;
+	va_list args;
+
+	va_start(args, fmt);
+	vseprint(buf, &buf[sizeof buf], fmt, args);
+	va_end(args);
+	p = Pt(screen->clipr.min.x+40, screen->clipr.max.y-40);
+	string(screen, p, display->black, ZP, font, buf);
+}
+
+#define	Viewkey	0xb2
+#define etimer(x, y) 0
+
+char *
+getcmdstr(void)
+{
+	Event ev;
+	int e;
+	static ulong timekey = 0;
+	ulong tracktm = 0;
+	Dir *dir;
+
+	if(track){
+		if(timekey == 0)
+			timekey = etimer(0, 5000);
+		dir = dirstat(track);
+		if(dir != nil){
+			tracktm = dir->mtime;
+			free(dir);
+		}
+	}
+	for (;;) {
+		e = event(&ev);
+		if(resized){
+			resized = 0;
+			return "p";
+		}
+		if ((e & Emouse) && ev.mouse.buttons) {
+			mouse = ev.mouse;
+			return getmousestr();
+		} else if (e & Ekeyboard)
+			return getkbdstr(ev.kbdc);	/* sadly, no way to unget */
+		else if (e & timekey) {
+			if((dir = dirstat(track)) != nil){
+				if(tracktm < dir->mtime){
+					free(dir);
+					return "q";
+				}
+				free(dir);
+			}
+		}
+	}
+	return nil;
+}
+
+static char *
+getkbdstr(int c0)
+{
+	static char buf[100];
+	char *p;
+	int c;
+
+	if (c0 == '\n')
+		return "";
+	buf[0] = c0;
+	buf[1] = 0;
+	screenprint("%s", buf);
+	for (p = buf+1; (c = ekbd()) != '\n' && c != '\r' && c != -1 && c != Viewkey; ) {
+		if (c == '\b' && p > buf) {
+			*--p = ' ';
+		} else {
+			*p++ = c;
+			*p = 0;
+		}
+		screenprint("%s", buf);
+	}
+	*p = 0;
+	return buf;
+}
+
+
+#define button3(b)	((b) & 4)
+#define button2(b)	((b) & 2)
+#define button1(b)	((b) & 1)
+#define button23(b)	((b) & 6)
+#define button123(b)	((b) & 7)
+
+#define	butcvt(b)	(1 << ((b) - 1))
+
+#if 0
+static int buttondown(void)	/* report state of buttons, if any */
+{
+	if (!ecanmouse())	/* no event pending */
+		return 0;
+	mouse = emouse();	/* something, but it could be motion */
+	return mouse.buttons & 7;
+}
+#endif
+
+int waitdown(void)	/* wait until some button is down */
+{
+	while (!(mouse.buttons & 7))
+		mouse = emouse();
+	return mouse.buttons & 7;
+}
+
+int waitup(void)
+{
+	while (mouse.buttons & 7)
+		mouse = emouse();
+	return mouse.buttons & 7;
+}
+
+char *m3[]	= { "next", "prev", "page n", "again", "bigger", "smaller", "pan", "quit?", 0 };
+char *m2[]	= { 0 };
+
+enum { Next = 0, Prev, Page, Again, Bigger, Smaller, Pan, Quit };
+
+Menu	mbut3	= { m3, 0, 0 };
+Menu	mbut2	= { m2, 0, 0 };
+
+int	last_hit;
+int	last_but;
+
+char *pan(void)
+{
+	Point dd, xy, lastxy, min, max;
+
+	esetcursor(&blot);
+	waitdown();
+	xy = mouse.xy;
+	do{
+		lastxy = mouse.xy;
+		mouse = emouse();
+		dd = subpt(mouse.xy, lastxy);
+		min = addpt(screen->clipr.min, dd);
+		max = addpt(screen->clipr.max, dd);
+		draw(screen, rectaddpt(screen->r, subpt(mouse.xy, lastxy)),
+			screen, nil, screen->r.min);
+		if(mouse.xy.x < lastxy.x)	/* moved left, clear right */
+			draw(screen, Rect(max.x, screen->r.min.y, screen->r.max.x, screen->r.max.y),
+				display->white, nil, ZP);
+		else	/* moved right, clear left*/
+			draw(screen, Rect(screen->r.min.x, screen->r.min.y, min.x, screen->r.max.y),
+				display->white, nil, ZP);
+		if(mouse.xy.y < lastxy.y)	/* moved up, clear down */
+			draw(screen, Rect(screen->r.min.x, max.y, screen->r.max.x, screen->r.max.y),
+				display->white, nil, ZP);
+		else		/* moved down, clear up */
+			draw(screen, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, min.y),
+				display->white, nil, ZP);
+		flushimage(display, 1);
+	}while(mouse.buttons);
+
+	xyoffset = addpt(xyoffset, subpt(mouse.xy, xy));
+
+	esetcursor(0);
+	return "p";
+}
+
+static char *getmousestr(void)
+{
+	static char buf[20];
+
+	checkmouse();
+	if (last_but == 1)
+		return "p";	/* repaint after panning */
+	if (last_but == 2) {
+		return "c";
+	} else if (last_but == 3) {
+		switch (last_hit) {
+		case Next:
+			return "";
+		case Prev:
+			return "-1";
+		case Page:
+			screenprint("page? ");
+			return "c";
+		case Again:
+			return "p";
+		case Bigger:
+			sprint(buf, "m%g", mag * 1.1);
+			return buf;
+		case Smaller:
+			sprint(buf, "m%g", mag / 1.1);
+			return buf;
+		case Pan:
+			return pan();
+		case Quit:
+			return "q";
+		default:
+			return "c";
+		}
+	} else {		/* button 1 or bail out */
+		return "c";
+	}
+}
+
+static int
+checkmouse(void)	/* return button touched if any */
+{
+	int c, b;
+	char *p;
+	extern int confirm(int);
+
+	b = waitdown();
+	last_but = 0;
+	last_hit = -1;
+	c = 0;
+	if (button3(b)) {
+		last_hit = emenuhit(3, &mouse, &mbut3);
+		last_but = 3;
+	} else if (button2(b)) {
+		last_hit = emenuhit(2, &mouse, &mbut2);
+		last_but = 2;
+	} else {		/* button1() */
+		pan();
+		last_but = 1;
+	}
+	waitup();
+	if (last_but == 3 && last_hit >= 0) {
+		p = m3[last_hit];
+		c = p[strlen(p) - 1];
+	}
+	if (c == '?' && !confirm(last_but))
+		last_hit = -1;
+	return last_but;
+}
+
+Cursor deadmouse = {
+	{ 0, 0},	/* offset */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
+	  0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
+	  0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0x00, 0x00, 0x00, 0x0C, 0x00, 0x82, 0x04, 0x41,
+	  0xFF, 0xE1, 0x5F, 0xF1, 0x3F, 0xFE, 0x17, 0xF0,
+	  0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
+};
+
+Cursor blot ={
+	{ 0, 0 },
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
+	{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }
+};
+
+Cursor skull ={
+	{ 0, 0 },
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
+	  0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
+	  0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
+	  0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
+	  0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
+	  0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
+	  0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
+};
+
+int
+confirm(int but)	/* ask for confirmation if menu item ends with '?' */
+{
+	int c;
+	static int but_cvt[8] = { 0, 1, 2, 0, 3, 0, 0, 0 };
+
+	esetcursor(&skull);
+	c = waitdown();
+	waitup();
+	esetcursor(0);
+	return but == but_cvt[c];
+}