shithub: drawfs

Download patch

ref: 15fb95683835a788826d0826f28e88fcd68ea85d
parent: d2a70ae3ee19a6e74e3ad1fcc568c26d1dbe227b
author: sirjofri <sirjofri@sirjofri.de>
date: Mon Jan 6 17:17:52 EST 2025

adds rudimentary mousefs implementation

--- /dev/null
+++ b/mousefs/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TARG=mousefs
+OFILES=mousefs.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/mousefs/mousefs.c
@@ -1,0 +1,538 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <cursor.h>
+#include <mouse.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-n name]\n", argv0);
+	exits("usage");
+}
+
+static char Enofile[] = "file not found";
+static char Eshort[] = "short read";
+static char Enoread[] = "read not supported";
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+QLock drawlock;
+
+Cursor arrow = {
+	{ -1, -1 },
+	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+	},
+	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+	},
+};
+
+Cursor cursor;
+
+static void
+Cursortocursor(Cursor *c)
+{
+	qlock(&drawlock);
+	memmove(&cursor, c, sizeof(Cursor));
+	qunlock(&drawlock);
+}
+
+typedef struct Mouseinfo Mouseinfo;
+typedef struct Mousestate Mousestate;
+
+struct Mousestate {
+	Point xy;
+	int buttons;
+	ulong counter;
+	ulong msec;
+};
+
+struct Mouseinfo {
+	QLock;
+	Mousestate;
+	int inbuttons;
+	int redraw;
+	Rendez redrawr;
+	ulong lastcounter;
+	int resize;
+	Rendez r;
+	Ref;
+	int open;
+	int acceleration;
+	int maxacc;
+	Mousestate queue[16];
+	ulong ri;
+	ulong wi;
+};
+
+Mouseinfo mouse;
+
+static uchar buttonmap[8] = {
+	0, 1, 2, 3, 4, 5, 6, 7,
+};
+
+static int mouseswap;
+static int scrollswap;
+static ulong mousetime;
+
+Rectangle screenr;
+
+void
+absmousetrack(int x, int y, int b, ulong msec)
+{
+	int lastb;
+	
+	if (x < screenr.min.x)
+		x = screenr.min.x;
+	if (x >= screenr.max.x)
+		x = screenr.max.x - 1;
+	if (y < screenr.min.y)
+		y = screenr.min.y;
+	if (y >= screenr.max.y)
+		y = screenr.max.y - 1;
+	
+	qlock(&mouse);
+	mouse.xy = Pt(x, y);
+	lastb = mouse.buttons;
+	b |= mouse.inbuttons;
+	mouse.buttons = b;
+	mouse.msec = msec;
+	mouse.counter++;
+	
+	if (b != lastb && (mouse.wi - mouse.ri) < nelem(mouse.queue))
+		mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
+	qunlock(&mouse);
+	// TODO: wakeup?
+}
+
+void
+scmousetrack(int x, int y, int b, ulong msec)
+{
+	vlong vx, vy;
+	
+	vx = (vlong)(uint)x * (screenr.max.x - screenr.min.x);
+	x = (vx + (1<<30) - (~vx>>31&1) >> 31) + screenr.min.x;
+	vy = (vlong)(uint)y * (screenr.max.y - screenr.min.y);
+	y = (vy + (1<<30) - (~vy>>31&1) >> 31) + screenr.min.y;
+	
+	absmousetrack(x, y, b, msec);
+}
+
+static int
+scale(int x)
+{
+	int sign = 1;
+	if (x < 0) {
+		sign = -1;
+		x = -x;
+	}
+	switch (x) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+		break;
+	case 4:
+		x = 6 + (mouse.acceleration>>2);
+		break;
+	case 5:
+		x = 9 + (mouse.acceleration>>1);
+		break;
+	default:
+		x *= mouse.maxacc;
+		break;
+	}
+	return sign * x;
+}
+
+/* called at interrupt level */
+void
+mousetrack(int dx, int dy, int b, ulong msec)
+{
+	if (mouse.acceleration) {
+		dx = scale(dx);
+		dy = scale(dy);
+	}
+	absmousetrack(mouse.xy.x + dx, mouse.xy.y + dy, b, msec);
+}
+
+enum {
+	Qroot,
+	Qmouse,
+	Qmousein,
+	Qmousectl,
+	Qcursor,
+	Qmax
+};
+
+typedef struct Qfile Qfile;
+struct Qfile {
+	char *name;
+	int mode;
+};
+
+Qfile qfiles[] = {
+	[Qroot] { nil, 0555 | DMDIR },
+	[Qmouse] { "mouse", 0666 },
+	[Qmousein] { "mousein", 0666 },
+	[Qmousectl] { "mousectl", 0222 },
+	[Qcursor] { "cursor", 0666 },
+};
+
+void
+mkqid(Qid *qid, int q)
+{
+	qid->vers = 0;
+	qid->path = q;
+	qid->type = qfiles[q].mode&DMDIR ? QTDIR : QTFILE;
+}
+
+int
+mkqdir(Dir *d, int q)
+{
+	if (q < Qroot || q >= Qmax)
+		return -1;
+	mkqid(&d->qid, q);
+	d->name = qfiles[q].name ? estrdup9p(qfiles[q].name) : nil;
+	d->mode = qfiles[q].mode;
+	d->uid = estrdup9p(getuser());
+	d->gid = estrdup9p(d->uid);
+	d->muid = estrdup9p(d->uid);
+	d->atime = d->mtime = time(0);
+	d->length = 0;
+	return 0;
+}
+
+int
+genroot(int n, Dir *dir, void*)
+{
+	n++; /* skip Qroot */
+	return mkqdir(dir, n);
+}
+
+void
+fsopen(Req *r)
+{
+	switch (r->fid->qid.path) {
+	default:
+		respond(r, nil);
+		return;
+	case Qmousein:
+		r->fid->aux = mallocz(sizeof(Mousestate), 1);
+		respond(r, nil);
+		return;
+	case Qmouse:
+		qlock(&mouse);
+		mouse.lastcounter = mouse.counter;
+		mouse.resize = 0;
+		qunlock(&mouse);
+		/* wet floor */
+	case Qcursor:
+		incref(&mouse);
+		respond(r, nil);
+	}
+}
+
+void
+fsclose(Fid *fid)
+{
+	Mousestate *m;
+	
+	switch (fid->qid.path) {
+	case Qmousein:
+		m = (Mousestate*)fid->aux;
+		qlock(&mouse);
+		mouse.inbuttons &= ~m->buttons;
+		qunlock(&mouse);
+		free(fid->aux);
+		fid->aux = nil;
+		return;
+	case Qmouse:
+		qlock(&mouse);
+		mouse.open = 0;
+		qunlock(&mouse);
+		/* wet floor */
+	case Qcursor:
+		if (decref(&mouse) != 0)
+			return;
+		Cursortocursor(&arrow);
+	}
+}
+
+void
+fsread(Req *r)
+{
+	Mousestate m;
+	int b;
+	char buf[1+4*12+1];
+	char t;
+	
+	switch (r->fid->qid.path) {
+	case Qmousectl:
+		respond(r, Enoread);
+		return;
+	case Qroot:
+		dirread9p(r, genroot, nil);
+		respond(r, nil);
+		return;
+	
+	case Qcursor:
+		if (r->ifcall.offset != 0) {
+			respond(r, nil);
+			return;
+		}
+		if (r->ifcall.count < 2*4+2*2*16) {
+			respond(r, Eshort);
+			return;
+		}
+		BPLONG(r->ofcall.data+0, arrow.offset.x);
+		BPLONG(r->ofcall.data+4, arrow.offset.y);
+		memmove(r->ofcall.data+8, arrow.clr, 2*16);
+		memmove(r->ofcall.data+40, arrow.set, 2*16);
+		r->ofcall.count = 2*4+2*2*16;
+		respond(r, nil);
+		return;
+	
+	case Qmouse:
+		qlock(&mouse);
+		if (mouse.ri != mouse.wi)
+			m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
+		else
+			m = mouse.Mousestate;
+		qunlock(&mouse);
+	
+		if(0) {
+	case Qmousein:
+			if (r->ifcall.offset != 0) {
+				respond(r, nil);
+				return;
+			}
+			qlock(&mouse);
+			m = mouse.Mousestate;
+			qunlock(&mouse);
+			t = 'm';
+		} else {
+			/* Qmouse */
+			mouse.lastcounter = m.counter;
+			if (mouse.resize) {
+				mouse.resize = 0;
+				t = 'r';
+			} else {
+				t = 'm';
+			}
+		}
+		
+		b = buttonmap[m.buttons&7];
+		/* put buttons 4 and 5 back in */
+		b |= m.buttons & (3<<3);
+		
+		if (scrollswap)
+			if (b == 8)
+				b = 16;
+			else if (b == 16)
+				b = 8;
+		
+		snprint(buf, sizeof(buf), "%c%11d %11d %11d %11ld ",
+			t, m.xy.x, m.xy.y, b, m.msec);
+		r->ofcall.count = 1+4*12;
+		memmove(r->ofcall.data, buf, r->ofcall.count);
+		respond(r, nil);
+		return;
+	}
+	respond(r, Enofile);
+}
+
+void
+fswrite(Req *r)
+{
+	Point pt;
+	char *p;
+	Cursor curs;
+	char buf[64];
+	int b, z, msec;
+	Mousestate *m;
+	
+	switch (r->fid->qid.path) {
+	case Qcursor:
+		if (r->ifcall.count < 2*4+2*2*16) {
+			Cursortocursor(&arrow);
+			r->ofcall.count = r->ifcall.count;
+			respond(r, nil);
+			return;
+		}
+		r->ofcall.count = 2*4+2*2*16;
+		curs.offset.x = BGLONG(r->ifcall.data+0);
+		curs.offset.y = BGLONG(r->ifcall.data+4);
+		memmove(curs.clr, r->ifcall.data+8, 2*16);
+		memmove(curs.set, r->ifcall.data+40, 2*16);
+		Cursortocursor(&curs);
+		respond(r, nil);
+		return;
+	
+	case Qmousectl:
+		/* TODO */
+		break;
+	
+	case Qmousein:
+		r->ofcall.count = sizeof(buf) - 1;
+		memmove(buf, r->ifcall.data, min(r->ifcall.count, sizeof(buf)-1));
+		buf[r->ifcall.count] = 0;
+		
+		pt.x = strtol(buf+1, &p, 0);
+		if (*p == 0) {
+			respond(r, Eshort);
+			return;
+		}
+		pt.y = strtol(p, &p, 0);
+		if (*p == 0) {
+			respond(r, Eshort);
+			return;
+		}
+		b = strtol(p, &p, 0);
+		msec = (ulong)strtoll(p, 0, 0);
+	//	if (msec == 0)
+	//		msec = TK2MS(MACHP(0)->ticks); // TODO
+		
+		/* exclude wheel */
+		z = b & (8|16);
+		b ^= z;
+		
+		m = (Mousestate*)r->fid->aux;
+		m->xy = pt;
+		m->msec = msec;
+		b ^= m->buttons;
+		m->buttons ^= b;
+		
+		qlock(&mouse);
+		mouse.inbuttons = (m->buttons & b) | (mouse.inbuttons & ~b);
+		b = mouse.buttons & ~b;
+		qunlock(&mouse);
+		
+		/* include wheel */
+		b &= ~(8|16);
+		b ^= z;
+		
+		if (buf[0] == 'A')
+			absmousetrack(pt.x, pt.y, b, msec);
+		else if (buf[0] == 'a')
+			scmousetrack(pt.x, pt.y, b, msec);
+		else
+			mousetrack(pt.x, pt.y, b, msec);
+		respond(r, nil);
+		return;
+	
+	case Qmouse:
+		r->ofcall.count = r->ifcall.count;
+		memmove(buf, r->ifcall.data, r->ifcall.count);
+		buf[r->ifcall.count] = 0;
+		
+		pt.x = strtol(buf+1, &p, 0);
+		if (*p == 0) {
+			respond(r, Eshort);
+			return;
+		}
+		pt.y = strtol(p, 0, 0);
+		absmousetrack(pt.x, pt.y, mouse.buttons, 0);
+		respond(r, nil);
+		return;
+	}
+	
+	respond(r, "not implemented");
+}
+
+char*
+fswalk(Fid *fid, char *name, Qid *qid)
+{
+	switch (fid->qid.path) {
+	case Qroot:
+		if (strcmp(name, "..") == 0) {
+			*qid = fid->qid;
+			return nil;
+		}
+		for (int q = Qmouse; q < Qmax; q++) {
+			if (strcmp(qfiles[q].name, name) == 0) {
+				mkqid(&fid->qid, q);
+				*qid = fid->qid;
+				return nil;
+			}
+		}
+		break;
+	}
+	return Enofile;
+}
+
+void
+fsstat(Req *r)
+{
+	if (mkqdir(&r->d, r->fid->qid.path) < 0)
+		respond(r, Enofile);
+	else
+		respond(r, nil);
+}
+
+void
+fsattach(Req *r)
+{
+	mkqid(&r->fid->qid, Qroot);
+	r->ofcall.qid = r->fid->qid;
+	respond(r, nil);
+}
+
+Srv fs = {
+	.attach = fsattach,
+	.walk1 = fswalk,
+	.stat = fsstat,
+	.open = fsopen,
+	.destroyfid = fsclose,
+	.read = fsread,
+	.write = fswrite,
+};
+
+static void
+mouseinit(void)
+{
+	Cursortocursor(&arrow);
+	screenr = Rect(0, 0, 1024, 768);
+}
+
+void
+main(int argc, char **argv)
+{
+	char *name = nil;
+	char *srvname;
+	char buf[16];
+	
+	ARGBEGIN{
+	case 'D':
+		chatty9p++;
+		fprint(2, "enable chatty 9p\n");
+		break;
+	case 'n':
+		name = EARGF(usage());
+		break;
+	default:
+		usage();
+	}ARGEND;
+	
+	if (!name) {
+		snprint(buf, sizeof buf, "%d", getpid());
+		name = buf;
+	}
+	
+	srvname = smprint("mousefs.%s", name);
+	if (!srvname)
+		sysfatal("%r");
+	
+	mouseinit();
+	
+	postsrv(&fs, srvname);
+}
--- /dev/null
+++ b/mousefs/t.rc
@@ -1,0 +1,11 @@
+#!/bin/rc
+
+rfork en
+mk
+rm /srv/mousefs.test >[2]/dev/null
+6.out -n test $*
+mount /srv/mousefs.test /mnt/mousetest
+cd /mnt/mousetest
+prompt=('mousefs; ' '	')
+rc
+rm /srv/mousefs.test >[2]/dev/null
--