496 lines · 7.7 KB · C
RawDownload
/* * Window system protocol server. * Use select and a single proc and single stack * to avoid aggravating the X11 library, which is * subtle and quick to anger. */ #include <u.h>#include <mingwsock.h>#include <libc.h>#include <thread.h>#include <draw.h>#include <memdraw.h>#include <memlayer.h>#include <keyboard.h>#include <mouse.h>#include <cursor.h>#include <drawfcall.h>#include "devdraw.h"#include "if.h" extern	int	utoplan9kbd(int); enum {	STACK	= 32768,}; #define MouseMask (\	ButtonPressMask|\	ButtonReleaseMask|\	PointerMotionMask|\	Button1MotionMask|\	Button2MotionMask|\	Button3MotionMask) #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask typedef struct Kbdbuf Kbdbuf;typedef struct Mousebuf Mousebuf;typedef struct Fdbuf Fdbuf;typedef struct Tagbuf Tagbuf; struct Kbdbuf{	Rune r[32];	int ri;	int wi;	int stall;}; struct Mousebuf{	Mouse m[32];	int ri;	int wi;	int stall;}; struct Tagbuf{	int t[32];	int ri;	int wi;}; struct Fdbuf{	uchar buf[2*MAXWMSG];	uchar *rp;	uchar *wp;	uchar *ep;}; Kbdbuf kbd;Mousebuf mouse;int mresized;Fdbuf fdin;Fdbuf fdout;Tagbuf kbdtags;Tagbuf mousetags; void fdslide(Fdbuf*);void runmsg(Wsysmsg*);void replymsg(Wsysmsg*);void matchkbd(void);void matchmouse(void);int fdnoblock(int); int chatty;int drawsleep;int fullscreen; Rectangle windowrect;Rectangle screenrect; Channel *cmouse;Channel *ckbd; static Channel *cwaitmore; static int cfd; voidkbdthread(void *ch){	int	c; 	for(;;) {		c = recvul(ch);		if(kbd.stall)			continue;		c = utoplan9kbd(c);		if (c<0)			continue;		kbd.r[kbd.wi++] = c;		if(kbd.wi == nelem(kbd.r))			kbd.wi = 0;		if(kbd.ri == kbd.wi)			kbd.stall = 1;		matchkbd();	}}voidmousethread(void *ch){	Mouse m; 	for(;;) {		recv(ch, &m);		if(mouse.stall)			continue;		mouse.m[mouse.wi] = m;		mouse.wi++;		if(mouse.wi == nelem(mouse.m))			mouse.wi = 0;		if(mouse.wi == mouse.ri){			mouse.stall = 1;			mouse.ri = 0;			mouse.wi = 1;			mouse.m[0] = m;			/* fprint(2, "mouse stall\n"); */		}		matchmouse();	}} voidwritethread(void *cnotew){	int n;	Ioproc *io;		io = ioproc();	for(;;) {		/* write what we can */		n = 1;		while(fdout.rp < fdout.wp && (n = iowrite(io, cfd, fdout.rp, fdout.wp-fdout.rp)) > 0)			fdout.rp += n;		if(n == 0)			sysfatal("short write writing wsys");		if(n < 0)			sysfatal("writing wsys msg: %r"); 		/* slide data to beginning of buf */		fdslide(&fdout); 		/* tell the reading thread that something has been written */		nbsendul(cnotew, 1); 		if (fdout.rp >= fdout.wp)			recvul(cwaitmore);	}} voidusage(void){	fprint(2, "usage: devdraw (don't run directly)\n");	threadexitsall("usage");} voidbell(void *v, char *msg){	if(strcmp(msg, "alarm") == 0)		drawsleep = drawsleep ? 0 : 1000;	noted(NCONT);} voidthreadmain(int argc, char **argv){	int fd[2];	int n, top;	fd_set rd, wr, xx;	Wsysmsg m;	Channel *cnotew;	Ioproc *io; 	pipe(fd);	if(sendfd(1, fd[1]) == -1)		sysfatal("sendfd: %r");		cfd = fd[0]; 	/*	 * Move the protocol off stdin/stdout so that	 * any inadvertent prints don't screw things up.	 */	close(0);	close(1);	open("/dev/null", OREAD);	open("/dev/null", OWRITE); 	fmtinstall('H', encodefmt);	fmtinstall('W', drawfcallfmt); 	ARGBEGIN{	case 'D':		chatty++;		break;	default:		usage();	}ARGEND 	/*	 * Ignore arguments.  They're only for good ps -a listings.	 */		notify(bell); 	fdin.rp = fdin.wp = fdin.buf;	fdin.ep = fdin.buf+sizeof fdin.buf;		fdout.rp = fdout.wp = fdout.buf;	fdout.ep = fdout.buf+sizeof fdout.buf; 	ckbd = chancreate(sizeof(ulong), 32);	cmouse = chancreate(sizeof(Mouse), 32); 	threadcreate(kbdthread, ckbd, STACK);	threadcreate(mousethread, cmouse, STACK); 	cwaitmore = chancreate(sizeof(ulong), 0);	cnotew = chancreate(sizeof(ulong), 0);	threadcreate(writethread, cnotew, STACK); 	io = ioproc();	for(;;){		/*		 * Don't read unless there's room *and* we haven't		 * already filled the output buffer too much.		 */		while(fdout.wp > fdout.buf+MAXWMSG) 			recvul(cnotew); 		/* read what we can */		n = 1;		if (fdin.wp < fdin.ep) {			n = ioread(io, cfd, fdin.wp, fdin.ep-fdin.wp);			if (n>0)				fdin.wp += n;		}		if(n == 0){			if(chatty)				fprint(2, "eof\n");			closeioproc(io);			threadexitsall(0);		}		if(n < 0)			sysfatal("reading wsys msg: %r"); 		/* pick off messages one by one */		while((n = convM2W(fdin.rp, fdin.wp-fdin.rp, &m)) > 0){//			fprint(2, "<- %W\n", &m);			runmsg(&m);			fdin.rp += n;		}					/* slide data to beginning of buf */		fdslide(&fdin);	}} voidfdslide(Fdbuf *fb){	int n; 	n = fb->wp - fb->rp;	if(n > 0)		memmove(fb->buf, fb->rp, n);	fb->rp = fb->buf;	fb->wp = fb->rp+n;} voidreplyerror(Wsysmsg *m){	char err[256];		rerrstr(err, sizeof err);	m->type = Rerror;	m->error = err;	replymsg(m);}   /*  * Handle a single wsysmsg.  * Might queue for later (kbd, mouse read) */voidrunmsg(Wsysmsg *m){	uchar buf[65536];	int n;	Memimage *i; 	switch(m->type){	case Tinit:		memimageinit();		i = _xattach(m->label, m->winsize);		_initdisplaymemimage(i);		replymsg(m);		break; 	case Trdmouse:		mousetags.t[mousetags.wi++] = m->tag;		if(mousetags.wi == nelem(mousetags.t))			mousetags.wi = 0;		if(mousetags.wi == mousetags.ri)			sysfatal("too many queued mouse reads");		/* fprint(2, "mouse unstall\n"); */		mouse.stall = 0;		matchmouse();		break; 	case Trdkbd:		kbdtags.t[kbdtags.wi++] = m->tag;		if(kbdtags.wi == nelem(kbdtags.t))			kbdtags.wi = 0;		if(kbdtags.wi == kbdtags.ri)			sysfatal("too many queued keyboard reads");		kbd.stall = 0;		matchkbd();		break; 	case Tmoveto:		_xmoveto(m->mouse.xy);		replymsg(m);		break; 	case Tcursor:		if(m->arrowcursor)			_xsetcursor(nil);		else			_xsetcursor(&m->cursor);		replymsg(m);		break;				case Tbouncemouse:		_xbouncemouse(&m->mouse);		replymsg(m);		break; 	case Tlabel:		_xsetlabel(m->label);		replymsg(m);		break; 	case Trdsnarf:		m->snarf = _xgetsnarf();		replymsg(m);		free(m->snarf);		break; 	case Twrsnarf:		_xputsnarf(m->snarf);		replymsg(m);		break; 	case Trddraw:		n = m->count;		if(n > sizeof buf)			n = sizeof buf;		n = _drawmsgread(buf, n);		if(n < 0)			replyerror(m);		else{			m->count = n;			m->data = buf;			replymsg(m);		}		break; 	case Twrdraw:		if(_drawmsgwrite(m->data, m->count) < 0)			replyerror(m);		else			replymsg(m);		break;		case Ttop:		_xtopwindow();		replymsg(m);		break;		case Tresize:		_xresizewindow(m->rect);		replymsg(m);		break;	}} /* * Reply to m. */voidreplymsg(Wsysmsg *m){	int n; 	/* T -> R msg */	if(m->type%2 == 0)		m->type++; //	fprint(2, "-> %W\n", m);	/* copy to output buffer */	n = sizeW2M(m);	if(fdout.wp+n > fdout.ep)		sysfatal("out of space for reply message");	convW2M(m, fdout.wp, n);	fdout.wp += n;	nbsendul(cwaitmore, 1);} /* * Match queued kbd reads with queued kbd characters. */voidmatchkbd(void){	Wsysmsg m;		if(kbd.stall)		return;	while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){		m.type = Rrdkbd;		m.tag = kbdtags.t[kbdtags.ri++];		if(kbdtags.ri == nelem(kbdtags.t))			kbdtags.ri = 0;		m.rune = kbd.r[kbd.ri++];		if(kbd.ri == nelem(kbd.r))			kbd.ri = 0;		replymsg(&m);	}} /* * Match queued mouse reads with queued mouse events. */voidmatchmouse(void){	Wsysmsg m;		while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){		m.type = Rrdmouse;		m.tag = mousetags.t[mousetags.ri++];		if(mousetags.ri == nelem(mousetags.t))			mousetags.ri = 0;		m.mouse = mouse.m[mouse.ri];		m.resized = mresized;		/*		if(m.resized)			fprint(2, "sending resize\n");		*/		mresized = 0;		mouse.ri++;		if(mouse.ri == nelem(mouse.m))			mouse.ri = 0;		replymsg(&m);	}} int_xsetlabel(char *label){	return 0;}void_xbouncemouse(Mouse *m){}