#include <9pm/u.h>
#include <9pm/libc.h>
#include <9pm/draw.h>
#include <9pm/memdraw.h>
#include <9pm/cursor.h>
#include <9pm/mouse.h>
#include "dat.h"
#include "fns.h"
#include "screen.h"
enum{
Qdir,
Qcursor,
Qmouse,
Qmousectl,
};
static Dirtab mousedir[]={
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"cursor", {Qcursor}, 0, 0666,
"mouse", {Qmouse}, 0, 0666,
};
static void
mousereset(void)
{
curs = arrow;
Cursortocursor(&arrow);
}
static Chan*
mouseattach(char *spec)
{
int i;
char *p;
Chan *c;
Drawgrp *dg;
i = strtol(spec, &p, 10);
if(i == 0 || *p != '\0' || (dg = lookupdrawgrp(i)) == nil)
error(Ebadspec);
c = devattach('m', spec);
c->aux = dg;
return c;
}
static Walkqid*
mousewalk(Chan *c, Chan *nc, char **name, int nname)
{
Drawgrp *dg;
Walkqid *wq;
wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
if(wq != nil && wq->clone != c && (wq->clone->qid.type&QTDIR)==0){
dg = c->aux;
incref(&dg->ref);
wq->aux = dg;
}
return wq;
}
static int
mousestat(Chan *c, uchar *db, int n)
{
return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
}
static Chan*
mouseopen(Chan *c, int omode)
{
switch((ulong)c->qid.path){
case Qdir:
if(omode != OREAD)
error(Eperm);
break;
case Qmouse:
lock(&mouse.lk);
if(mouse.open){
unlock(&mouse.lk);
error(Einuse);
}
mouse.open = 1;
incref(&mouse.ref);
unlock(&mouse.lk);
break;
default:
incref(&mouse.ref);
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void
mouseclose(Chan *c)
{
Drawgrp *dg;
dg = c->aux;
if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
lock(&dg->mouse.lk);
if(c->qid.path == Qmouse)
dg->mouse.open = 0;
if(decref(&dg->mouse.ref) == 0){
curs = arrow;
Cursortocursor(&arrow);
}
unlock(&dg->mouse.lk);
}
c->aux = nil;
closedrawgrp(dg);
}
static long
mouseread(Chan *c, void *va, long n, vlong off)
{
int nresize;
char buf[4*12+1];
uchar *p;
ulong offset = off;
Drawgrp *dg;
Kmouse m;
p = va;
dg = c->aux;
switch((ulong)c->qid.path){
default:
error(Egreg);
case Qdir:
return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
case Qcursor:
if(offset != 0)
return 0;
if(n < 2*4+2*2*16)
error(Eshort);
n = 2*4+2*2*16;
lock(&dg->cursor.lk);
BPLONG(p+0, dg->cursor.c.offset.x);
BPLONG(p+4, dg->cursor.c.offset.y);
memmove(p+8, dg->cursor.c.clr, 2*16);
memmove(p+40, dg->cursor.c.set, 2*16);
unlock(&dg->cursor.lk);
return n;
case Qmouse:
while(mousechanged(dg) == 0)
rendsleep(&dg->mouse.r, mousechanged, dg);
dg->mouse.qfull = 0;
/*
* No lock of the indicies is necessary here, because ri is only
* updated by us, and there is only one mouse fd
* 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(dg->mouse.ri != dg->mouse.wi) {
m = dg->mouse.queue[dg->mouse.ri];
if(++dg->mouse.ri == nelem(dg->mouse.queue))
dg->mouse.ri = 0;
} else {
lock(&dg->mouse.lk);
m = dg->mouse.m;
unlock(&dg->mouse.lk);
}
sprint(buf, "m%11d %11d %11d %11lud",
m.m.xy.x, m.m.xy.y,
m.m.buttons,
m.m.msec);
nresize = dg->mouse.nresize;
if(dg->mouse.mresize < nresize){
dg->mouse.mresize = nresize;
buf[0] = 'r';
}
dg->mouse.lastcounter = m.counter;
if(n > 1+4*12)
n = 1+4*12;
memmove(va, buf, n);
return n;
}
}
static long
mousewrite(Chan *c, void *va, long n, vlong offset)
{
char *p;
Point pt;
char buf[64];
Drawgrp *dg;
USED(offset);
p = va;
dg = c->aux;
switch((ulong)c->qid.path){
default:
error(Egreg);
case Qdir:
error(Eisdir);
case Qcursor:
lock(&dg->cursor.lk);
if(n < 2*4+2*2*16)
dg->cursor.c = arrow;
else{
n = 2*4+2*2*16;
dg->cursor.c.offset.x = BGLONG(p+0);
dg->cursor.c.offset.y = BGLONG(p+4);
memmove(dg->cursor.c.clr, p+8, 2*16);
memmove(dg->cursor.c.set, p+40, 2*16);
}
unlock(&dg->cursor.lk);
Cursortocursor(&curs);
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);
if(ptinrect(pt, dg->screenimage->r))
movecursor(dg, pt);
return n;
}
}
Dev devmouse = {
'm',
"mouse",
mousereset,
mouseattach,
mousewalk,
mousestat,
mouseopen,
devcreate,
mouseclose,
mouseread,
devbread,
mousewrite,
devbwrite,
devremove,
devwstat,
};
void
Cursortocursor(Cursor *c)
{
lock(&cursor.lk);
memmove(&cursor.c, c, sizeof(Cursor));
cursorload(c);
unlock(&cursor.lk);
}
/*
* called at interrupt level to update the structure and
* awaken any waiting procs.
*/
void
mousetrack(Point xy, int b, int msec)
{
int lastb;
lastb = mouse.m.buttons;
mouse.m.xy = xy;
mouse.m.buttons = b;
mouse.m.counter++;
if(msec == 0)
msec = nsec()/1000000;
mouse.m.msec = msec;
/*
* if the queue fills, we discard the entire queue and don't
* queue any more events until a reader polls the mouse.
*/
if(!mouse.qfull && lastb != b) { /* add to ring */
mouse.queue[mouse.wi] = mouse.m;
if(++mouse.wi == nelem(mouse.queue))
mouse.wi = 0;
if(mouse.wi == mouse.ri)
mouse.qfull = 1;
}
rendwakeup(&mouse.r);
}
int
mousechanged(void *a)
{
USED(a);
return mouse.lastcounter != mouse.m.counter;
}
Point
mousexy(void)
{
return mouse.m.xy;
}
syntax highlighted by Code2HTML, v. 0.9.1