555 lines · 9.5 KB · C
RawDownload
/* * Mouse device.  Also provides /dev/snarf, because it was convenient. * In a perfect world, this would be autogenerated from a * Plan 9 devmouse. */#include	"u.h"#include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h" #define	Image	IMAGE#include	<draw.h>#include	<memdraw.h>#include	<cursor.h>#include	"screen.h" typedef struct Cursor Cursor; 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, 	},}; enum {	ScrollUp = 0x08,	ScrollDown = 0x10,	ScrollLeft = 0x20,	ScrollRight = 0x40,}; enum{	CMbuttonmap,	CMscrollswap,	CMswap,}; static Cmdtab mousectlmsg[] ={	CMbuttonmap,	"buttonmap",	0,	CMscrollswap,	"scrollswap",	0,	CMswap,		"swap",		1,}; Mouseinfo	mouse;Cursorinfo	cursor;int		mouseshifted;Cursor		curs; void	Cursortocursor(Cursor*);int	mousechanged(void*); enum{	Qdir,	Qcursor,	Qmouse,	Qmousectl,	Qsnarf,}; static Dirtab mousedir[]={	".",	{Qdir, 0, QTDIR},	0,			DMDIR|0555,	"cursor",	{Qcursor},	0,			0666,	"mouse",	{Qmouse},	0,			0666,	"mousectl",	{Qmousectl},	0,			0220,	"snarf",	{Qsnarf},	0,	0666,}; static uchar buttonmap[8] = {	0, 1, 2, 3, 4, 5, 6, 7,};static int mouseswap;static int scrollswap;static ulong mousetime; Rectangle mouserect;	/* maintained by x11 for us */ static voidmousereset(void){	if(!conf.monitor)		return;} static intmousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp){	int rc; 	rc = devgen(c, name, tab, ntab, i, dp);	if(rc != -1)		dp->atime = mousetime;	return rc;} static voidmouseinit(void){	if(!conf.monitor)		return;	mousetime = seconds();} static Chan*mouseattach(char *spec){	if(!conf.monitor)		error(Egreg);	curs = arrow;	Cursortocursor(&arrow);	return devattach('m', spec);} static Walkqid*mousewalk(Chan *c, Chan *nc, char **name, int nname){	Walkqid *wq; 	/*	 * We use devgen() and not mousedevgen() here	 * see "Ugly problem" in dev.c/devwalk()	 */	wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);	if(wq != nil && wq->clone != c && wq->clone != nil && (wq->clone->qid.type&QTDIR)==0)		incref(&mouse.ref);	return wq;} static intmousestat(Chan *c, uchar *db, int n){	return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);} static Chan*mouseopen(Chan *c, int omode){	switch((ulong)c->qid.path){	case Qdir:		if(omode != OREAD)			error(Eperm);		break;	case Qmouse:		lock(&mouse.ref.lk);		if(mouse.open){			unlock(&mouse.ref.lk);			error(Einuse);		}		mouse.open = 1;		mouse.ref.ref++;		mouse.lastresize = mouse.resize;		unlock(&mouse.ref.lk);		break;	case Qsnarf:		if(omode == ORDWR)			error(Eperm);	/* one at a time please */		c->aux = nil;		incref(&mouse.ref);		break;	default:		incref(&mouse.ref);	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidmousecreate(Chan *c, char *name, int perm, ulong mode){	if(!conf.monitor)		error(Egreg);	error(Eperm);} static voidmouseclose(Chan *c){	if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){		if(c->qid.path == Qsnarf){			if(c->mode == OWRITE){				if(c->aux)					putsnarf(c->aux);				else					putsnarf("");			}			free(c->aux);		}		lock(&mouse.ref.lk);		if(c->qid.path == Qmouse)			mouse.open = 0;		if(--mouse.ref.ref == 0){			curs = arrow;			Cursortocursor(&arrow);		}		unlock(&mouse.ref.lk);		if(c->qid.path == Qmouse)			termredraw();	}} static longmouseread(Chan *c, void *va, long n, vlong off){	char buf[1+4*12+1], *s;	uchar *p;	ulong offset = off;	Mousestate m;	int b; 	p = va;	switch((ulong)c->qid.path){	case Qdir:		return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen); 	case Qcursor:		if(offset != 0)			return 0;		if(n < 2*4+2*2*16)			error(Eshort);		n = 2*4+2*2*16;		lock(&cursor.lk);		BPLONG(p+0, curs.offset.x);		BPLONG(p+4, curs.offset.y);		memmove(p+8, curs.clr, 2*16);		memmove(p+40, curs.set, 2*16);		unlock(&cursor.lk);		return n; 	case Qmouse:		while(mousechanged(0) == 0)			sleep(&mouse.r, mousechanged, 0); 		mouse.qfull = 0;		mousetime = seconds(); 		/*		 * No lock of the indices is necessary here, because ri is only		 * updated by us, and there is only one mouse reader		 * at a time.  I suppose that more than one process		 * could try to read the fd at one time, but such behavior		 * is degenerate and already violates the calling		 * conventions for sleep above.		 */		if(mouse.ri != mouse.wi) {			m = mouse.queue[mouse.ri];			if(++mouse.ri == nelem(mouse.queue))				mouse.ri = 0;		} else {			while(!canlock(&cursor.lk))				tsleep(&up->sleep, return0, 0, TK2MS(1)); 			m = mouse.mstate;			unlock(&cursor.lk);		} 		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;		}		sprint(buf, "m%11d %11d %11d %11lud ",			m.xy.x, m.xy.y,			b,			m.msec);		mouse.lastcounter = m.counter;		if(n > 1+4*12)			n = 1+4*12;		if(mouse.lastresize != mouse.resize){			mouse.lastresize = mouse.resize;			buf[0] = 'r';		}		memmove(va, buf, n);		return n;		case Qsnarf:		if(offset == 0){			s = getsnarf();			if(c->aux)				free(c->aux);			c->aux = s;		}		if(c->aux == nil)			return 0;		return readstr(offset, va, n, c->aux);	}	return 0;} static voidsetbuttonmap(char* map){	int i, x, one, two, three; 	one = two = three = 0;	for(i = 0; i < 3; i++){		if(map[i] == 0)			error(Ebadarg);		if(map[i] == '1'){			if(one)				error(Ebadarg);			one = 1<<i;		}		else if(map[i] == '2'){			if(two)				error(Ebadarg);			two = 1<<i;		}		else if(map[i] == '3'){			if(three)				error(Ebadarg);			three = 1<<i;		}		else			error(Ebadarg);	}	if(map[i])		error(Ebadarg); 	memset(buttonmap, 0, 8);	for(i = 0; i < 8; i++){		x = 0;		if(i & 1)			x |= one;		if(i & 2)			x |= two;		if(i & 4)			x |= three;		buttonmap[x] = i;	}} static longmousewrite(Chan *c, void *va, long n, vlong offset){	char *p;	Point pt;	Cmdbuf *cb;	Cmdtab *ct;	char buf[64];	int nn; 	p = va;	switch((ulong)c->qid.path){	case Qdir:		error(Eisdir); 	case Qcursor:		if(n < 2*4+2*2*16){			curs = arrow;			Cursortocursor(&arrow);		}else{			n = 2*4+2*2*16;			curs.offset.x = BGLONG(p+0);			curs.offset.y = BGLONG(p+4);			memmove(curs.clr, p+8, 2*16);			memmove(curs.set, p+40, 2*16);			Cursortocursor(&curs);		}		qlock(&mouse.qlk);		mouse.redraw = 1;		qunlock(&mouse.qlk);		return n; 	case Qmousectl:		cb = parsecmd(va, n);		if(waserror()){			free(cb);			nexterror();		} 		ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg)); 		switch(ct->index){		case CMswap:			if(mouseswap)				setbuttonmap("123");			else				setbuttonmap("321");			mouseswap ^= 1;			break; 		case CMscrollswap:			scrollswap ^= 1;			break; 		case CMbuttonmap:			if(cb->nf == 1)				setbuttonmap("123");			else				setbuttonmap(cb->f[1]);			break;		} 		free(cb);		poperror();		return n; 	case Qmouse:		if(n > sizeof buf-1)			n = sizeof buf -1;		memmove(buf, va, n);		buf[n] = 0;		p = 0;		pt.x = strtoul(buf+1, &p, 0);		if(p == 0)			error(Eshort);		pt.y = strtoul(p, 0, 0);		qlock(&mouse.qlk);		if(ptinrect(pt, mouserect)){			mouse.mstate.xy = pt;			mouse.redraw = 1;			mouse.track = 1;		}		qunlock(&mouse.qlk);		setmouse(pt);		return n;		case Qsnarf:		if(offset+n >= SnarfSize)			error("too much snarf");		if(n == 0)			return 0;		assert(mousedir[Qsnarf].qid.path == Qsnarf);		mousedir[Qsnarf].qid.vers++;		if(c->aux == nil)			nn = 0;		else			nn = strlen(c->aux);		if(offset+n > nn){			nn = offset+n;			p = smalloc(nn+1);			if(c->aux){				strcpy(p, c->aux);				free(c->aux);			}			c->aux = p;		}		memmove(c->aux+offset, va, n);		return n;	} 	error(Egreg);	return -1;} Dev mousedevtab = {	'm',	"mouse", 	mousereset,	mouseinit,	devshutdown,	mouseattach,	mousewalk,	mousestat,	mouseopen,	mousecreate,	mouseclose,	mouseread,	devbread,	mousewrite,	devbwrite,	devremove,	devwstat,}; voidCursortocursor(Cursor *c){	lock(&cursor.lk);	cursor.cursor = *c;	unlock(&cursor.lk);	setcursor(c);} intmousechanged(void *v){	return mouse.lastcounter != mouse.mstate.counter ||		mouse.lastresize != mouse.resize;} Point

Lines 1–500 of 555.