#include <u.h>#include <sys/select.h>#include <libc.h>#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 nslave;static int newkey(ulong);static int extract(int canblock); staticEbuf*ebread(Slave *s){ Ebuf *eb; while(!s->head) extract(1); eb = s->head; s->head = s->head->next; if(s->head == 0) s->tail = 0; return eb;} ulongevent(Event *e){ return eread(~0UL, e);} ulongeread(ulong keys, Event *e){ Ebuf *eb; int i, id; if(keys == 0) return 0; for(;;){ for(i=0; i<nslave; i++) if((keys & (1<<i)) && eslave[i].head){ id = 1<<i; if(i == Smouse) e->mouse = emouse(); else if(i == Skeyboard) e->kbdc = ekbd(); else if(i == Stimer) eslave[i].head = 0; else{ eb = ebread(&eslave[i]); e->n = eb->n; if(eslave[i].fn) id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n); else memmove(e->data, eb->u.buf, eb->n); free(eb); } return id; } extract(1); } return 0;} intecanmouse(void){ if(Smouse < 0) drawerror(display, "events: mouse not initialized"); return ecanread(Emouse);} intecankbd(void){ if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); return ecanread(Ekeyboard);} intecanread(ulong keys){ int i; for(;;){ for(i=0; i<nslave; i++) if((keys & (1<<i)) && eslave[i].head) return 1; if(!extract(0)) return 0; } return -1;} ulongestartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)){ int i; if(fd < 0) drawerror(display, "events: bad file descriptor"); if(n <= 0 || n > EMAXMSG) n = EMAXMSG; i = newkey(key); eslave[i].fn = fn; eslave[i].fd = fd; eslave[i].n = n; return 1<<i;} ulongestart(ulong key, int fd, int n){ return estartfn(key, fd, n, nil);} ulongetimer(ulong key, int n){ if(Stimer != -1) drawerror(display, "events: timer started twice"); Stimer = newkey(key); if(n <= 0) n = 1000; eslave[Stimer].n = n; eslave[Stimer].nexttick = nsec()+n*1000000LL; return 1<<Stimer;} voideinit(ulong keys){ if(keys&Ekeyboard){ for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++) ; eslave[Skeyboard].inuse = 1; if(nslave <= Skeyboard) nslave = Skeyboard+1; } if(keys&Emouse){ for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++) ; eslave[Smouse].inuse = 1; if(nslave <= Smouse) nslave = Smouse+1; }} static Ebuf*newebuf(Slave *s, int n){ Ebuf *eb; 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 intfinishrpc(Muxrpc *r, Wsysmsg *w){ uchar *p; void *v; int n; if(!muxrpccanfinish(r, &v)) return 0; p = v; if(p == nil) /* eof on connection */ exit(0); GET(p, n); convM2W(p, n, w); free(p); return 1;} static intextract(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(canqlock(&display->qlock)){ if(display->bufp > display->buf) flushimage(display, 1); unlockdisplay(display); } }else if(display->bufp > display->buf) flushimage(display, 1); /* * 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){ /* if ready, don't block in select */ if(eslave[i].rpc->p) canblock = 0; 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){ /* if ready, don't block in select */ if(eslave[i].rpc->p) canblock = 0; 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){ tv.tv_sec = 0; tv.tv_usec = 0; }else{ tv.tv_sec = (eslave[i].nexttick-t0)/1000000000; tv.tv_usec = (eslave[i].nexttick-t0)%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(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){ eslave[i].nexttick += eslave[i].n*1000000LL; 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++; } } } return n;} static intnewkey(ulong key){ int i; for(i=0; i<MAXSLAVE; i++) if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){ if(nslave <= i) nslave = i + 1; eslave[i].inuse = 1; return i; } drawerror(display, "events: bad slave assignment"); return 0;} Mouseemouse(void){ Mouse m; Ebuf *eb; if(Smouse < 0) drawerror(display, "events: mouse not initialized"); eb = ebread(&eslave[Smouse]); m = eb->u.mouse; free(eb); return m;} intekbd(void){ Ebuf *eb; int c; if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); eb = ebread(&eslave[Skeyboard]); c = eb->u.rune; free(eb); return c;} voidemoveto(Point pt){ _displaymoveto(display, pt);} voidesetcursor(Cursor *c){ _displaycursor(display, c);} intereadmouse(Mouse *m){ int resized; resized = 0; if(_displayrdmouse(display, m, &resized) < 0) return -1; if(resized) eresized(1); return 1;}
#include <u.h>
#include <sys/select.h>
#include <libc.h>
#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 nslave;
static int newkey(ulong);
static int extract(int canblock);
static
Ebuf*
ebread(Slave *s)
{
Ebuf *eb;
while(!s->head)
extract(1);
eb = s->head;
s->head = s->head->next;
if(s->head == 0)
s->tail = 0;
return eb;
}
ulong
event(Event *e)
{
return eread(~0UL, e);
}
ulong
eread(ulong keys, Event *e)
{
Ebuf *eb;
int i, id;
if(keys == 0)
return 0;
for(;;){
for(i=0; i<nslave; i++)
if((keys & (1<<i)) && eslave[i].head){
id = 1<<i;
if(i == Smouse)
e->mouse = emouse();
else if(i == Skeyboard)
e->kbdc = ekbd();
else if(i == Stimer)
eslave[i].head = 0;
else{
eb = ebread(&eslave[i]);
e->n = eb->n;
if(eslave[i].fn)
id = (*eslave[i].fn)(id, e, eb->u.buf, eb->n);
else
memmove(e->data, eb->u.buf, eb->n);
free(eb);
}
return id;
}
extract(1);
}
return 0;
}
int
ecanmouse(void)
{
if(Smouse < 0)
drawerror(display, "events: mouse not initialized");
return ecanread(Emouse);
}
int
ecankbd(void)
{
if(Skeyboard < 0)
drawerror(display, "events: keyboard not initialzed");
return ecanread(Ekeyboard);
}
int
ecanread(ulong keys)
{
int i;
for(;;){
for(i=0; i<nslave; i++)
if((keys & (1<<i)) && eslave[i].head)
return 1;
if(!extract(0))
return 0;
}
return -1;
}
ulong
estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
{
int i;
if(fd < 0)
drawerror(display, "events: bad file descriptor");
if(n <= 0 || n > EMAXMSG)
n = EMAXMSG;
i = newkey(key);
eslave[i].fn = fn;
eslave[i].fd = fd;
eslave[i].n = n;
return 1<<i;
}
ulong
estart(ulong key, int fd, int n)
{
return estartfn(key, fd, n, nil);
}
ulong
etimer(ulong key, int n)
{
if(Stimer != -1)
drawerror(display, "events: timer started twice");
Stimer = newkey(key);
if(n <= 0)
n = 1000;
eslave[Stimer].n = n;
eslave[Stimer].nexttick = nsec()+n*1000000LL;
return 1<<Stimer;
}
void
einit(ulong keys)
{
if(keys&Ekeyboard){
for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
;
eslave[Skeyboard].inuse = 1;
if(nslave <= Skeyboard)
nslave = Skeyboard+1;
}
if(keys&Emouse){
for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
;
eslave[Smouse].inuse = 1;
if(nslave <= Smouse)
nslave = Smouse+1;
}
}
static Ebuf*
newebuf(Slave *s, int n)
{
Ebuf *eb;
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;
void *v;
int n;
if(!muxrpccanfinish(r, &v))
return 0;
p = v;
if(p == nil) /* eof on connection */
exit(0);
GET(p, n);
convM2W(p, n, w);
free(p);
return 1;
}
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(canqlock(&display->qlock)){
if(display->bufp > display->buf)
flushimage(display, 1);
unlockdisplay(display);
}
}else
if(display->bufp > display->buf)
flushimage(display, 1);
/*
* 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){
/* if ready, don't block in select */
if(eslave[i].rpc->p)
canblock = 0;
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){
/* if ready, don't block in select */
if(eslave[i].rpc->p)
canblock = 0;
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){
tv.tv_sec = 0;
tv.tv_usec = 0;
}else{
tv.tv_sec = (eslave[i].nexttick-t0)/1000000000;
tv.tv_usec = (eslave[i].nexttick-t0)%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(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){
eslave[i].nexttick += eslave[i].n*1000000LL;
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++;
}
}
}
return n;
}
static int
newkey(ulong key)
{
int i;
for(i=0; i<MAXSLAVE; i++)
if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){
if(nslave <= i)
nslave = i + 1;
eslave[i].inuse = 1;
return i;
}
drawerror(display, "events: bad slave assignment");
return 0;
}
Mouse
emouse(void)
{
Mouse m;
Ebuf *eb;
if(Smouse < 0)
drawerror(display, "events: mouse not initialized");
eb = ebread(&eslave[Smouse]);
m = eb->u.mouse;
free(eb);
return m;
}
int
ekbd(void)
{
Ebuf *eb;
int c;
if(Skeyboard < 0)
drawerror(display, "events: keyboard not initialzed");
eb = ebread(&eslave[Skeyboard]);
c = eb->u.rune;
free(eb);
return c;
}
void
emoveto(Point pt)
{
_displaymoveto(display, pt);
}
void
esetcursor(Cursor *c)
{
_displaycursor(display, c);
}
int
ereadmouse(Mouse *m)
{
int resized;
resized = 0;
if(_displayrdmouse(display, m, &resized) < 0)
return -1;
if(resized)
eresized(1);
return 1;
}