432 lines · 7.2 KB · C
RawDownload
#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;}