aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdraw/event.c')
-rw-r--r--src/libdraw/event.c482
1 files changed, 217 insertions, 265 deletions
diff --git a/src/libdraw/event.c b/src/libdraw/event.c
index 6e4d7f5c..1da3fb39 100644
--- a/src/libdraw/event.c
+++ b/src/libdraw/event.c
@@ -4,42 +4,52 @@
#include <draw.h>
#include <cursor.h>
#include <event.h>
+#include <mux.h>
+#include <drawfcall.h>
+typedef struct Slave Slave;
+typedef struct Ebuf Ebuf;
+struct Slave
+{
+ int inuse;
+ Ebuf *head; /* queue of messages for this descriptor */
+ Ebuf *tail;
+ int (*fn)(int, Event*, uchar*, int);
+ Muxrpc *rpc;
+ vlong nexttick;
+ int fd;
+ int n;
+};
+struct Ebuf
+{
+ Ebuf *next;
+ int n; /* number of bytes in buf */
+ union {
+ uchar buf[EMAXMSG];
+ Rune rune;
+ Mouse mouse;
+ } u;
+};
+
+static Slave eslave[MAXSLAVE];
static int Skeyboard = -1;
static int Smouse = -1;
static int Stimer = -1;
-static int logfid;
static int nslave;
-static int parentpid;
-static int epipe[2];
-static int eforkslave(ulong);
-static void extract(void);
-static void ekill(void);
-static int enote(void *, char *);
-static int mousefd;
-static int cursorfd;
+static int newkey(ulong);
+static int extract(int canblock);
static
Ebuf*
ebread(Slave *s)
{
Ebuf *eb;
- Dir *d;
- ulong l;
- for(;;){
- d = dirfstat(epipe[0]);
- if(d == nil)
- drawerror(display, "events: eread stat error");
- l = d->length;
- free(d);
- if(s->head && l==0)
- break;
- extract();
- }
+ while(!s->head)
+ extract(1);
eb = s->head;
s->head = s->head->next;
if(s->head == 0)
@@ -75,14 +85,14 @@ eread(ulong keys, Event *e)
eb = ebread(&eslave[i]);
e->n = eb->n;
if(eslave[i].fn)
- id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
+ id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n);
else
- memmove(e->data, eb->buf, eb->n);
+ memmove(e->data, eb->u.buf, eb->n);
free(eb);
}
return id;
}
- extract();
+ extract(0);
}
return 0;
}
@@ -106,22 +116,14 @@ ecankbd(void)
int
ecanread(ulong keys)
{
- Dir *d;
int i;
- ulong l;
for(;;){
for(i=0; i<nslave; i++)
if((keys & (1<<i)) && eslave[i].head)
return 1;
- d = dirfstat(epipe[0]);
- if(d == nil)
- drawerror(display, "events: ecanread stat error");
- l = d->length;
- free(d);
- if(l == 0)
+ if(!extract(0))
return 0;
- extract();
}
return -1;
}
@@ -129,26 +131,17 @@ ecanread(ulong keys)
ulong
estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
{
- char buf[EMAXMSG+1];
- int i, r;
+ int i;
if(fd < 0)
drawerror(display, "events: bad file descriptor");
if(n <= 0 || n > EMAXMSG)
n = EMAXMSG;
- i = eforkslave(key);
- if(i < MAXSLAVE){
- eslave[i].fn = fn;
- return 1<<i;
- }
- buf[0] = i - MAXSLAVE;
- while((r = read(fd, buf+1, n))>0)
- if(write(epipe[1], buf, r+1)!=r+1)
- break;
- buf[0] = MAXSLAVE;
- write(epipe[1], buf, 1);
- _exits(0);
- return 0;
+ i = newkey(key);
+ eslave[i].fn = fn;
+ eslave[i].fd = fd;
+ eslave[i].n = n;
+ return 1<<i;
}
ulong
@@ -160,110 +153,98 @@ estart(ulong key, int fd, int n)
ulong
etimer(ulong key, int n)
{
- char t[2];
-
if(Stimer != -1)
drawerror(display, "events: timer started twice");
- Stimer = eforkslave(key);
- if(Stimer < MAXSLAVE)
- return 1<<Stimer;
+ Stimer = newkey(key);
if(n <= 0)
n = 1000;
- t[0] = t[1] = Stimer - MAXSLAVE;
- do
- sleep(n);
- while(write(epipe[1], t, 2) == 2);
- t[0] = MAXSLAVE;
- write(epipe[1], t, 1);
- _exits(0);
- return 0;
-}
-
-static void
-ekeyslave(int fd)
-{
- Rune r;
- char t[3], k[10];
- int kr, kn, w;
-
- if(eforkslave(Ekeyboard) < MAXSLAVE)
- return;
- kn = 0;
- t[0] = Skeyboard;
- for(;;){
- while(!fullrune(k, kn)){
- kr = read(fd, k+kn, sizeof k - kn);
- if(kr <= 0)
- goto breakout;
- kn += kr;
- }
- w = chartorune(&r, k);
- kn -= w;
- memmove(k, &k[w], kn);
- t[1] = r;
- t[2] = r>>8;
- if(write(epipe[1], t, 3) != 3)
- break;
- }
-breakout:;
- t[0] = MAXSLAVE;
- write(epipe[1], t, 1);
- _exits(0);
+ eslave[Stimer].n = n;
+ eslave[Stimer].nexttick = nsec()+n*1000LL;
+ return 1<<Stimer;
}
void
einit(ulong keys)
{
- int ctl, fd;
- char buf[256];
-
- parentpid = getpid();
- if(pipe(epipe) < 0)
- drawerror(display, "events: einit pipe");
- atexit(ekill);
- atnotify(enote, 1);
- snprint(buf, sizeof buf, "%s/mouse", display->devdir);
- mousefd = open(buf, ORDWR|OCEXEC);
- if(mousefd < 0)
- drawerror(display, "einit: can't open mouse\n");
- snprint(buf, sizeof buf, "%s/cursor", display->devdir);
- cursorfd = open(buf, ORDWR|OCEXEC);
- if(cursorfd < 0)
- drawerror(display, "einit: can't open cursor\n");
if(keys&Ekeyboard){
- snprint(buf, sizeof buf, "%s/cons", display->devdir);
- fd = open(buf, OREAD);
- if(fd < 0)
- drawerror(display, "events: can't open console");
- snprint(buf, sizeof buf, "%s/consctl", display->devdir);
- ctl = open("/dev/consctl", OWRITE|OCEXEC);
- if(ctl < 0)
- drawerror(display, "events: can't open consctl");
- write(ctl, "rawon", 5);
for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
;
- ekeyslave(fd);
+ eslave[Skeyboard].inuse = 1;
+ if(nslave <= Skeyboard)
+ nslave = Skeyboard+1;
}
if(keys&Emouse){
- estart(Emouse, mousefd, 1+4*12);
for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
;
+ eslave[Smouse].inuse = 1;
+ if(nslave <= Smouse)
+ nslave = Smouse+1;
}
}
-static void
-extract(void)
+static Ebuf*
+newebuf(Slave *s, int n)
{
- Slave *s;
Ebuf *eb;
- int i, n;
- uchar ebuf[EMAXMSG+1];
+
+ eb = malloc(sizeof(*eb) - sizeof(eb->u.buf) + n);
+ if(eb == nil)
+ drawerror(display, "events: out of memory");
+ eb->n = n;
+ eb->next = 0;
+ if(s->head)
+ s->tail = s->tail->next = eb;
+ else
+ s->head = s->tail = eb;
+ return eb;
+}
+
+static Muxrpc*
+startrpc(int type)
+{
+ uchar buf[100];
+ Wsysmsg w;
+
+ w.type = type;
+ convW2M(&w, buf, sizeof buf);
+ return muxrpcstart(display->mux, buf);
+}
+
+static int
+finishrpc(Muxrpc *r, Wsysmsg *w)
+{
+ uchar *p;
+ int n;
+
+ if((p = muxrpccanfinish(r)) == nil)
+ return 0;
+ GET(p, n);
+ convM2W(p, n, w);
+ free(p);
+ return 1;
+}
- /* avoid generating a message if there's nothing to show. */
- /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
- /* also: make sure we don't interfere if we're multiprocessing the display */
+static int
+extract(int canblock)
+{
+ Ebuf *eb;
+ int i, n, max;
+ fd_set rset, wset, xset;
+ struct timeval tv, *timeout;
+ Wsysmsg w;
+ vlong t0;
+
+ /*
+ * Flush draw buffer before waiting for responses.
+ * Avoid doing so if buffer is empty.
+ * Also make sure that we don't interfere with app-specific locking.
+ */
if(display->locking){
- /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
+ /*
+ * if locking is being done by program,
+ * this means it can't depend on automatic
+ * flush in emouse() etc.
+ */
if(canqlock(&display->qlock)){
if(display->bufp > display->buf)
flushimage(display, 1);
@@ -272,128 +253,130 @@ extract(void)
}else
if(display->bufp > display->buf)
flushimage(display, 1);
-loop:
- if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
- || ebuf[0] >= MAXSLAVE)
- drawerror(display, "eof on event pipe");
- if(n == 0)
- goto loop;
- i = ebuf[0];
- if(i >= nslave || n <= 1)
- drawerror(display, "events: protocol error: short read");
- s = &eslave[i];
- if(i == Stimer){
- s->head = (Ebuf *)1;
- return;
+
+ /*
+ * Set up for select.
+ */
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_ZERO(&xset);
+ max = -1;
+ timeout = nil;
+ for(i=0; i<nslave; i++){
+ if(!eslave[i].inuse)
+ continue;
+ if(i == Smouse){
+ if(eslave[i].rpc == nil)
+ eslave[i].rpc = startrpc(Trdmouse);
+ if(eslave[i].rpc){
+ FD_SET(display->srvfd, &rset);
+ FD_SET(display->srvfd, &xset);
+ if(display->srvfd > max)
+ max = display->srvfd;
+ }
+ }else if(i == Skeyboard){
+ if(eslave[i].rpc == nil)
+ eslave[i].rpc = startrpc(Trdkbd);
+ if(eslave[i].rpc){
+ FD_SET(display->srvfd, &rset);
+ FD_SET(display->srvfd, &xset);
+ if(display->srvfd > max)
+ max = display->srvfd;
+ }
+ }else if(i == Stimer){
+ t0 = nsec();
+ if(t0-eslave[i].nexttick <= 0){
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }else{
+ tv.tv_sec = (t0-eslave[i].nexttick)/1000000000;
+ tv.tv_usec = (t0-eslave[i].nexttick)%1000000000 / 1000;
+ }
+ timeout = &tv;
+ }else{
+ FD_SET(eslave[i].fd, &rset);
+ FD_SET(eslave[i].fd, &xset);
+ if(eslave[i].fd > max)
+ max = eslave[i].fd;
+ }
+ }
+
+ if(!canblock){
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ timeout = &tv;
}
- if(i == Skeyboard && n != 3)
- drawerror(display, "events: protocol error: keyboard");
- if(i == Smouse){
- if(n < 1+1+2*12)
- drawerror(display, "events: protocol error: mouse");
- if(ebuf[1] == 'r')
- eresized(1);
- /* squash extraneous mouse events */
- if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){
- memmove(eb->buf, &ebuf[1], n - 1);
- return;
+
+ if(select(max+1, &rset, &wset, &xset, timeout) < 0)
+ drawerror(display, "select failure");
+
+ /*
+ * Look to see what can proceed.
+ */
+ n = 0;
+ for(i=0; i<nslave; i++){
+ if(!eslave[i].inuse)
+ continue;
+ if(i == Smouse){
+ if(finishrpc(eslave[i].rpc, &w)){
+ eslave[i].rpc = nil;
+ eb = newebuf(&eslave[i], sizeof(Mouse));
+ eb->u.mouse = w.mouse;
+ if(w.resized)
+ eresized(1);
+ n++;
+ }
+ }else if(i == Skeyboard){
+ if(finishrpc(eslave[i].rpc, &w)){
+ eslave[i].rpc = nil;
+ eb = newebuf(&eslave[i], sizeof(Rune)+2); /* +8: alignment */
+ eb->u.rune = w.rune;
+ n++;
+ }
+ }else if(i == Stimer){
+ t0 = nsec();
+ while(t0-eslave[i].nexttick > 0){
+ eslave[i].nexttick += eslave[i].n*1000LL;
+ eslave[i].head = (Ebuf*)1;
+ n++;
+ }
+ }else{
+ if(FD_ISSET(eslave[i].fd, &rset)){
+ eb = newebuf(&eslave[i], eslave[i].n);
+ eb->n = read(eslave[i].fd, eb->u.buf, eslave[i].n);
+ n++;
+ }
}
}
- /* try to save space by only allocating as much buffer as we need */
- eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1);
- if(eb == 0)
- drawerror(display, "events: protocol error 4");
- eb->n = n - 1;
- memmove(eb->buf, &ebuf[1], n - 1);
- eb->next = 0;
- if(s->head)
- s->tail = s->tail->next = eb;
- else
- s->head = s->tail = eb;
+ return n;
}
static int
-eforkslave(ulong key)
+newkey(ulong key)
{
- int i, pid;
+ int i;
for(i=0; i<MAXSLAVE; i++)
- if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){
+ if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){
if(nslave <= i)
nslave = i + 1;
- /*
- * share the file descriptors so the last child
- * out closes all connections to the window server.
- */
- switch(pid = rfork(RFPROC)){
- case 0:
- return MAXSLAVE+i;
- case -1:
- fprint(2, "events: fork error\n");
- exits("fork");
- }
- eslave[i].pid = pid;
- eslave[i].head = eslave[i].tail = 0;
+ eslave[i].inuse = 1;
return i;
}
drawerror(display, "events: bad slave assignment");
return 0;
}
-static int
-enote(void *v, char *s)
-{
- char t[1];
- int i, pid;
-
- USED(v, s);
- pid = getpid();
- if(pid != parentpid){
- for(i=0; i<nslave; i++){
- if(pid == eslave[i].pid){
- t[0] = MAXSLAVE;
- write(epipe[1], t, 1);
- break;
- }
- }
- return 0;
- }
- close(epipe[0]);
- epipe[0] = -1;
- close(epipe[1]);
- epipe[1] = -1;
- for(i=0; i<nslave; i++){
- if(pid == eslave[i].pid)
- continue; /* don't kill myself */
- postnote(PNPROC, eslave[i].pid, "die");
- }
- return 0;
-}
-
-static void
-ekill(void)
-{
- enote(0, 0);
-}
-
Mouse
emouse(void)
{
Mouse m;
Ebuf *eb;
- static but[2];
- int b;
if(Smouse < 0)
drawerror(display, "events: mouse not initialized");
eb = ebread(&eslave[Smouse]);
- m.xy.x = atoi((char*)eb->buf+1+0*12);
- m.xy.y = atoi((char*)eb->buf+1+1*12);
- b = atoi((char*)eb->buf+1+2*12);
- m.buttons = b&7;
- m.msec = atoi((char*)eb->buf+1+3*12);
- if (logfid)
- fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy);
+ m = eb->u.mouse;
free(eb);
return m;
}
@@ -407,7 +390,7 @@ ekbd(void)
if(Skeyboard < 0)
drawerror(display, "events: keyboard not initialzed");
eb = ebread(&eslave[Skeyboard]);
- c = eb->buf[0] + (eb->buf[1]<<8);
+ c = eb->u.rune;
free(eb);
return c;
}
@@ -415,56 +398,25 @@ ekbd(void)
void
emoveto(Point pt)
{
- char buf[2*12+2];
- int n;
-
- n = sprint(buf, "m%d %d", pt.x, pt.y);
- write(mousefd, buf, n);
+ _displaymoveto(display, pt);
}
void
esetcursor(Cursor *c)
{
- uchar curs[2*4+2*2*16];
-
- if(c == 0)
- write(cursorfd, curs, 0);
- else{
- BPLONG(curs+0*4, c->offset.x);
- BPLONG(curs+1*4, c->offset.y);
- memmove(curs+2*4, c->clr, 2*2*16);
- write(cursorfd, curs, sizeof curs);
- }
+ _displaycursor(display, c);
}
int
ereadmouse(Mouse *m)
{
- int n;
- char buf[128];
-
- do{
- n = read(mousefd, buf, sizeof(buf));
- if(n < 0) /* probably interrupted */
- return -1;
- n = eatomouse(m, buf, n);
- }while(n == 0);
- return n;
-}
+ int resized;
-int
-eatomouse(Mouse *m, char *buf, int n)
-{
- if(n != 1+4*12){
- werrstr("atomouse: bad count");
+ resized = 0;
+ if(_displayrdmouse(display, m, &resized) < 0)
return -1;
- }
-
- if(buf[0] == 'r')
+ if(resized)
eresized(1);
- m->xy.x = atoi(buf+1+0*12);
- m->xy.y = atoi(buf+1+1*12);
- m->buttons = atoi(buf+1+2*12);
- m->msec = atoi(buf+1+3*12);
- return n;
+ return 1;
}
+