This commit is contained in:
rsc 2006-06-25 21:04:07 +00:00
parent e0ef95dce1
commit 150f88023b
6 changed files with 273 additions and 1905 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/* Copyright (c) 2006 Russ Cox */ /* Copyright (c) 2006 Russ Cox */
#include <u.h> #include <u.h>
#include <sys/select.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <mouse.h> #include <mouse.h>
@ -12,8 +13,10 @@ int chattydrawclient;
static int drawgettag(Mux *mux, void *vmsg); static int drawgettag(Mux *mux, void *vmsg);
static void* drawrecv(Mux *mux); static void* drawrecv(Mux *mux);
static void* drawnbrecv(Mux *mux);
static int drawsend(Mux *mux, void *vmsg); static int drawsend(Mux *mux, void *vmsg);
static int drawsettag(Mux *mux, void *vmsg, uint tag); static int drawsettag(Mux *mux, void *vmsg, uint tag);
static int canreadfd(int);
int int
_displayconnect(Display *d) _displayconnect(Display *d)
@ -35,8 +38,8 @@ _displayconnect(Display *d)
dup(p[1], 0); dup(p[1], 0);
dup(p[1], 1); dup(p[1], 1);
/* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */ /* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
execl("drawsrv", "drawsrv", nil); execl("devdraw", "devdraw", nil);
sysfatal("exec drawsrv: %r"); sysfatal("exec devdraw: %r");
} }
close(p[1]); close(p[1]);
d->srvfd = p[0]; d->srvfd = p[0];
@ -53,6 +56,7 @@ _displaymux(Display *d)
d->mux->maxtag = 255; d->mux->maxtag = 255;
d->mux->send = drawsend; d->mux->send = drawsend;
d->mux->recv = drawrecv; d->mux->recv = drawrecv;
d->mux->nbrecv = drawnbrecv;
d->mux->gettag = drawgettag; d->mux->gettag = drawgettag;
d->mux->settag = drawsettag; d->mux->settag = drawsettag;
d->mux->aux = d; d->mux->aux = d;
@ -61,9 +65,6 @@ _displaymux(Display *d)
return 0; return 0;
} }
#define GET(p, x) \
((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3])))
static int static int
drawsend(Mux *mux, void *vmsg) drawsend(Mux *mux, void *vmsg)
{ {
@ -78,17 +79,17 @@ drawsend(Mux *mux, void *vmsg)
} }
static void* static void*
drawrecv(Mux *mux) _drawrecv(Mux *mux, int nb)
{ {
int n; int n;
uchar buf[4], *p; uchar buf[4], *p;
Display *d; Display *d;
d = mux->aux; d = mux->aux;
if((n=readn(d->srvfd, buf, 4)) != 4){ if(nb && !canreadfd(d->srvfd))
fprint(2, "readn 4 got %d: %r\n", n); return nil;
if((n=readn(d->srvfd, buf, 4)) != 4)
return nil; return nil;
}
GET(buf, n); GET(buf, n);
p = malloc(n); p = malloc(n);
if(p == nil){ if(p == nil){
@ -96,13 +97,23 @@ fprint(2, "readn 4 got %d: %r\n", n);
return nil; return nil;
} }
memmove(p, buf, 4); memmove(p, buf, 4);
if(readn(d->srvfd, p+4, n-4) != n-4){ if(readn(d->srvfd, p+4, n-4) != n-4)
fprint(2, "short readn\n");
return nil; return nil;
}
return p; return p;
} }
static void*
drawrecv(Mux *mux)
{
return _drawrecv(mux, 0);
}
static void*
drawnbrecv(Mux *mux)
{
return _drawrecv(mux, 1);
}
static int static int
drawgettag(Mux *mux, void *vmsg) drawgettag(Mux *mux, void *vmsg)
{ {
@ -186,8 +197,8 @@ _displayinit(Display *d, char *label, char *winsize)
Wsysmsg tx, rx; Wsysmsg tx, rx;
tx.type = Tinit; tx.type = Tinit;
tx.label = ""; tx.label = label;
tx.winsize = ""; tx.winsize = winsize;
return displayrpc(d, &tx, &rx, nil); return displayrpc(d, &tx, &rx, nil);
} }
@ -334,3 +345,23 @@ _displayresize(Display *d, Rectangle r)
return displayrpc(d, &tx, &rx, nil); return displayrpc(d, &tx, &rx, nil);
} }
static int
canreadfd(int fd)
{
fd_set rs, ws, xs;
struct timeval tv;
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&xs);
FD_SET(fd, &rs);
FD_SET(fd, &xs);
tv.tv_sec = 0;
tv.tv_usec = 0;
if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
return 0;
if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
return 1;
return 0;
}

View file

@ -5,25 +5,11 @@
#include <cursor.h> #include <cursor.h>
#include <drawfcall.h> #include <drawfcall.h>
#define PUT(p, x) \
(p)[0] = ((x) >> 24)&0xFF, \
(p)[1] = ((x) >> 16)&0xFF, \
(p)[2] = ((x) >> 8)&0xFF, \
(p)[3] = (x)&0xFF
#define GET(p, x) \
((x) = (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3])))
#define PUT2(p, x) \
(p)[0] = ((x) >> 8)&0xFF, \
(p)[1] = (x)&0xFF
#define GET2(p, x) \
((x) = (((p)[0] << 8) | ((p)[1])))
static int static int
_stringsize(char *s) _stringsize(char *s)
{ {
if(s == nil)
s = "";
return 4+strlen(s); return 4+strlen(s);
} }

View file

@ -4,42 +4,52 @@
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <cursor.h>
#include <event.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 Skeyboard = -1;
static int Smouse = -1; static int Smouse = -1;
static int Stimer = -1; static int Stimer = -1;
static int logfid;
static int nslave; static int nslave;
static int parentpid; static int newkey(ulong);
static int epipe[2]; static int extract(int canblock);
static int eforkslave(ulong);
static void extract(void);
static void ekill(void);
static int enote(void *, char *);
static int mousefd;
static int cursorfd;
static static
Ebuf* Ebuf*
ebread(Slave *s) ebread(Slave *s)
{ {
Ebuf *eb; Ebuf *eb;
Dir *d;
ulong l;
for(;;){ while(!s->head)
d = dirfstat(epipe[0]); extract(1);
if(d == nil)
drawerror(display, "events: eread stat error");
l = d->length;
free(d);
if(s->head && l==0)
break;
extract();
}
eb = s->head; eb = s->head;
s->head = s->head->next; s->head = s->head->next;
if(s->head == 0) if(s->head == 0)
@ -75,14 +85,14 @@ eread(ulong keys, Event *e)
eb = ebread(&eslave[i]); eb = ebread(&eslave[i]);
e->n = eb->n; e->n = eb->n;
if(eslave[i].fn) 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 else
memmove(e->data, eb->buf, eb->n); memmove(e->data, eb->u.buf, eb->n);
free(eb); free(eb);
} }
return id; return id;
} }
extract(); extract(0);
} }
return 0; return 0;
} }
@ -106,22 +116,14 @@ ecankbd(void)
int int
ecanread(ulong keys) ecanread(ulong keys)
{ {
Dir *d;
int i; int i;
ulong l;
for(;;){ for(;;){
for(i=0; i<nslave; i++) for(i=0; i<nslave; i++)
if((keys & (1<<i)) && eslave[i].head) if((keys & (1<<i)) && eslave[i].head)
return 1; return 1;
d = dirfstat(epipe[0]); if(!extract(0))
if(d == nil)
drawerror(display, "events: ecanread stat error");
l = d->length;
free(d);
if(l == 0)
return 0; return 0;
extract();
} }
return -1; return -1;
} }
@ -129,26 +131,17 @@ ecanread(ulong keys)
ulong ulong
estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
{ {
char buf[EMAXMSG+1]; int i;
int i, r;
if(fd < 0) if(fd < 0)
drawerror(display, "events: bad file descriptor"); drawerror(display, "events: bad file descriptor");
if(n <= 0 || n > EMAXMSG) if(n <= 0 || n > EMAXMSG)
n = EMAXMSG; n = EMAXMSG;
i = eforkslave(key); i = newkey(key);
if(i < MAXSLAVE){ eslave[i].fn = fn;
eslave[i].fn = fn; eslave[i].fd = fd;
return 1<<i; eslave[i].n = n;
} 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;
} }
ulong ulong
@ -160,110 +153,98 @@ estart(ulong key, int fd, int n)
ulong ulong
etimer(ulong key, int n) etimer(ulong key, int n)
{ {
char t[2];
if(Stimer != -1) if(Stimer != -1)
drawerror(display, "events: timer started twice"); drawerror(display, "events: timer started twice");
Stimer = eforkslave(key); Stimer = newkey(key);
if(Stimer < MAXSLAVE)
return 1<<Stimer;
if(n <= 0) if(n <= 0)
n = 1000; n = 1000;
t[0] = t[1] = Stimer - MAXSLAVE; eslave[Stimer].n = n;
do eslave[Stimer].nexttick = nsec()+n*1000LL;
sleep(n); return 1<<Stimer;
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);
} }
void void
einit(ulong keys) 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){ 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++) for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
; ;
ekeyslave(fd); eslave[Skeyboard].inuse = 1;
if(nslave <= Skeyboard)
nslave = Skeyboard+1;
} }
if(keys&Emouse){ if(keys&Emouse){
estart(Emouse, mousefd, 1+4*12);
for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++) for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
; ;
eslave[Smouse].inuse = 1;
if(nslave <= Smouse)
nslave = Smouse+1;
} }
} }
static void static Ebuf*
extract(void) newebuf(Slave *s, int n)
{ {
Slave *s;
Ebuf *eb; 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;
}
/* avoid generating a message if there's nothing to show. */ static Muxrpc*
/* this test isn't perfect, though; could do flushimage(display, 0) then call extract */ startrpc(int type)
/* also: make sure we don't interfere if we're multiprocessing the display */ {
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;
}
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(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(canqlock(&display->qlock)){
if(display->bufp > display->buf) if(display->bufp > display->buf)
flushimage(display, 1); flushimage(display, 1);
@ -272,128 +253,130 @@ extract(void)
}else }else
if(display->bufp > display->buf) if(display->bufp > display->buf)
flushimage(display, 1); flushimage(display, 1);
loop:
if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0 /*
|| ebuf[0] >= MAXSLAVE) * Set up for select.
drawerror(display, "eof on event pipe"); */
if(n == 0) FD_ZERO(&rset);
goto loop; FD_ZERO(&wset);
i = ebuf[0]; FD_ZERO(&xset);
if(i >= nslave || n <= 1) max = -1;
drawerror(display, "events: protocol error: short read"); timeout = nil;
s = &eslave[i]; for(i=0; i<nslave; i++){
if(i == Stimer){ if(!eslave[i].inuse)
s->head = (Ebuf *)1; continue;
return; if(i == Smouse){
} if(eslave[i].rpc == nil)
if(i == Skeyboard && n != 3) eslave[i].rpc = startrpc(Trdmouse);
drawerror(display, "events: protocol error: keyboard"); if(eslave[i].rpc){
if(i == Smouse){ FD_SET(display->srvfd, &rset);
if(n < 1+1+2*12) FD_SET(display->srvfd, &xset);
drawerror(display, "events: protocol error: mouse"); if(display->srvfd > max)
if(ebuf[1] == 'r') max = display->srvfd;
eresized(1); }
/* squash extraneous mouse events */ }else if(i == Skeyboard){
if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){ if(eslave[i].rpc == nil)
memmove(eb->buf, &ebuf[1], n - 1); eslave[i].rpc = startrpc(Trdkbd);
return; 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;
} }
} }
/* try to save space by only allocating as much buffer as we need */
eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1); if(!canblock){
if(eb == 0) tv.tv_sec = 0;
drawerror(display, "events: protocol error 4"); tv.tv_usec = 0;
eb->n = n - 1; timeout = &tv;
memmove(eb->buf, &ebuf[1], n - 1); }
eb->next = 0;
if(s->head) if(select(max+1, &rset, &wset, &xset, timeout) < 0)
s->tail = s->tail->next = eb; drawerror(display, "select failure");
else
s->head = s->tail = eb; /*
* 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++;
}
}
}
return n;
} }
static int static int
eforkslave(ulong key) newkey(ulong key)
{ {
int i, pid; int i;
for(i=0; i<MAXSLAVE; 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) if(nslave <= i)
nslave = i + 1; nslave = i + 1;
/* eslave[i].inuse = 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;
return i; return i;
} }
drawerror(display, "events: bad slave assignment"); drawerror(display, "events: bad slave assignment");
return 0; 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 Mouse
emouse(void) emouse(void)
{ {
Mouse m; Mouse m;
Ebuf *eb; Ebuf *eb;
static but[2];
int b;
if(Smouse < 0) if(Smouse < 0)
drawerror(display, "events: mouse not initialized"); drawerror(display, "events: mouse not initialized");
eb = ebread(&eslave[Smouse]); eb = ebread(&eslave[Smouse]);
m.xy.x = atoi((char*)eb->buf+1+0*12); m = eb->u.mouse;
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);
free(eb); free(eb);
return m; return m;
} }
@ -407,7 +390,7 @@ ekbd(void)
if(Skeyboard < 0) if(Skeyboard < 0)
drawerror(display, "events: keyboard not initialzed"); drawerror(display, "events: keyboard not initialzed");
eb = ebread(&eslave[Skeyboard]); eb = ebread(&eslave[Skeyboard]);
c = eb->buf[0] + (eb->buf[1]<<8); c = eb->u.rune;
free(eb); free(eb);
return c; return c;
} }
@ -415,56 +398,25 @@ ekbd(void)
void void
emoveto(Point pt) emoveto(Point pt)
{ {
char buf[2*12+2]; _displaymoveto(display, pt);
int n;
n = sprint(buf, "m%d %d", pt.x, pt.y);
write(mousefd, buf, n);
} }
void void
esetcursor(Cursor *c) esetcursor(Cursor *c)
{ {
uchar curs[2*4+2*2*16]; _displaycursor(display, c);
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);
}
} }
int int
ereadmouse(Mouse *m) ereadmouse(Mouse *m)
{ {
int n; int resized;
char buf[128];
do{ resized = 0;
n = read(mousefd, buf, sizeof(buf)); if(_displayrdmouse(display, m, &resized) < 0)
if(n < 0) /* probably interrupted */
return -1;
n = eatomouse(m, buf, n);
}while(n == 0);
return n;
}
int
eatomouse(Mouse *m, char *buf, int n)
{
if(n != 1+4*12){
werrstr("atomouse: bad count");
return -1; return -1;
} if(resized)
if(buf[0] == 'r')
eresized(1); eresized(1);
m->xy.x = atoi(buf+1+0*12); return 1;
m->xy.y = atoi(buf+1+1*12);
m->buttons = atoi(buf+1+2*12);
m->msec = atoi(buf+1+3*12);
return n;
} }

View file

@ -23,6 +23,7 @@ OFILES=\
egetrect.$O\ egetrect.$O\
ellipse.$O\ ellipse.$O\
emenuhit.$O\ emenuhit.$O\
event.$O\
font.$O\ font.$O\
freesubfont.$O\ freesubfont.$O\
getdefont.$O\ getdefont.$O\

View file

@ -22,3 +22,9 @@ bouncemouse(Mouse *m)
_displaybouncemouse(display, m); _displaybouncemouse(display, m);
} }
void
drawresizewindow(Rectangle r)
{
_displayresize(display, r);
}