⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfid.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h"#define	MAXSNARF	100*1024char Einuse[] =		"file in use";char Edeleted[] =	"window deleted";char Ebadreq[] =	"bad graphics request";char Etooshort[] =	"buffer too small";char Ebadtile[] =	"unknown tile";char Eshort[] =		"short i/o request";char Elong[] = 		"snarf buffer too long";char Eunkid[] = 	"unknown id in attach";char Ebadrect[] = 	"bad rectangle in attach";char Ewindow[] = 	"cannot make window";char Enowindow[] = 	"window has no image";char Ebadmouse[] = 	"bad format on /dev/mouse";char Ebadwrect[] = 	"rectangle outside screen";char Ebadoffset[] = 	"window read not on scan line boundary";extern char Eperm[];static	Xfid	*xfidfree;static	Xfid	*xfid;static	Channel	*cxfidalloc;	/* chan(Xfid*) */static	Channel	*cxfidfree;	/* chan(Xfid*) */static	char	*tsnarf;static	int	ntsnarf;voidxfidallocthread(void*){	Xfid *x;	enum { Alloc, Free, N };	static Alt alts[N+1];	alts[Alloc].c = cxfidalloc;	alts[Alloc].v = nil;	alts[Alloc].op = CHANRCV;	alts[Free].c = cxfidfree;	alts[Free].v = &x;	alts[Free].op = CHANRCV;	alts[N].op = CHANEND;	for(;;){		switch(alt(alts)){		case Alloc:			x = xfidfree;			if(x)				xfidfree = x->free;			else{				x = emalloc(sizeof(Xfid));				x->c = chancreate(sizeof(void(*)(Xfid*)), 0);				x->flushc = chancreate(sizeof(int), 0);	/* notification only; no data */				x->flushtag = -1;				x->next = xfid;				xfid = x;				threadcreate(xfidctl, x, 16384);			}			if(x->ref != 0){				fprint(2, "%p incref %ld\n", x, x->ref);				error("incref");			}			if(x->flushtag != -1)				error("flushtag in allocate");			incref(x);			sendp(cxfidalloc, x);			break;		case Free:			if(x->ref != 0){				fprint(2, "%p decref %ld\n", x, x->ref);				error("decref");			}			if(x->flushtag != -1)				error("flushtag in free");			x->free = xfidfree;			xfidfree = x;			break;		}	}}Channel*xfidinit(void){	cxfidalloc = chancreate(sizeof(Xfid*), 0);	cxfidfree = chancreate(sizeof(Xfid*), 0);	threadcreate(xfidallocthread, nil, STACK);	return cxfidalloc;}voidxfidctl(void *arg){	Xfid *x;	void (*f)(Xfid*);	char buf[64];	x = arg;	snprint(buf, sizeof buf, "xfid.%p", x);	threadsetname(buf);	for(;;){		f = recvp(x->c);		(*f)(x);		if(decref(x) == 0)			sendp(cxfidfree, x);	}}voidxfidflush(Xfid *x){	Fcall t;	Xfid *xf;	for(xf=xfid; xf; xf=xf->next)		if(xf->flushtag == x->oldtag){			xf->flushtag = -1;			xf->flushing = TRUE;			incref(xf);	/* to hold data structures up at tail of synchronization */			if(xf->ref == 1)				error("ref 1 in flush");			if(canqlock(&xf->active)){				qunlock(&xf->active);				sendul(xf->flushc, 0);			}else{				qlock(&xf->active);	/* wait for him to finish */				qunlock(&xf->active);			}			xf->flushing = FALSE;			if(decref(xf) == 0)				sendp(cxfidfree, xf);			break;		}	filsysrespond(x->fs, x, &t, nil);}voidxfidattach(Xfid *x){	Fcall t;	int id, hideit, scrollit;	Window *w;	char *err, *n, *dir, errbuf[ERRMAX];	int pid, newlymade;	Rectangle r;	Image *i;	t.qid = x->f->qid;	qlock(&all);	w = nil;	err = Eunkid;	newlymade = FALSE;	hideit = 0;	if(x->aname[0] == 'N'){	/* N 100,100, 200, 200 - old syntax */		n = x->aname+1;		pid = strtoul(n, &n, 0);		if(*n == ',')			n++;		r.min.x = strtoul(n, &n, 0);		if(*n == ',')			n++;		r.min.y = strtoul(n, &n, 0);		if(*n == ',')			n++;		r.max.x = strtoul(n, &n, 0);		if(*n == ',')			n++;		r.max.y = strtoul(n, &n, 0);  Allocate:		if(!goodrect(r))			err = Ebadrect;		else{			if(hideit)				i = allocimage(display, r, screen->chan, 0, DWhite);			else				i = allocwindow(wscreen, r, Refbackup, DWhite);			if(i){				border(i, r, Selborder, display->black, ZP);				if(pid == 0)					pid = -1;	/* make sure we don't pop a shell! - UGH */				w = new(i, hideit, scrolling, pid, nil, nil, nil);				flushimage(display, 1);				newlymade = TRUE;			}else				err = Ewindow;		}	}else if(strncmp(x->aname, "new", 3) == 0){	/* new -dx -dy - new syntax, as in wctl */		pid = 0;		if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)			err = errbuf;		else			goto Allocate;	}else{		id = atoi(x->aname);		w = wlookid(id);	}	x->f->w = w;	if(w == nil){		qunlock(&all);		x->f->busy = FALSE;		filsysrespond(x->fs, x, &t, err);		return;	}	if(!newlymade)	/* counteract dec() in winshell() */		incref(w);	qunlock(&all);	filsysrespond(x->fs, x, &t, nil);}voidxfidopen(Xfid *x){	Fcall t;	Window *w;	w = x->f->w;	if(w->deleted){		filsysrespond(x->fs, x, &t, Edeleted);		return;	}	switch(FILE(x->f->qid)){	case Qconsctl:		if(w->ctlopen){			filsysrespond(x->fs, x, &t, Einuse);			return;		}		w->ctlopen = TRUE;		break;	case Qkbdin:		if(w !=  wkeyboard){			filsysrespond(x->fs, x, &t, Eperm);			return;		}		break;	case Qmouse:		if(w->mouseopen){			filsysrespond(x->fs, x, &t, Einuse);			return;		}		/*		 * Reshaped: there's a race if the appl. opens the		 * window, is resized, and then opens the mouse,		 * but that's rare.  The alternative is to generate		 * a resized event every time a new program starts		 * up in a window that has been resized since the		 * dawn of time.  We choose the lesser evil.		 */		w->resized = FALSE;		w->mouseopen = TRUE;		break;	case Qsnarf:		if(x->mode==ORDWR || x->mode==OWRITE){			if(tsnarf)				free(tsnarf);	/* collision, but OK */			ntsnarf = 0;			tsnarf = malloc(1);		}		break;	case Qwctl:		if(x->mode==OREAD || x->mode==ORDWR){			/*			 * It would be much nicer to implement fan-out for wctl reads,			 * so multiple people can see the resizings, but rio just isn't			 * structured for that.  It's structured for /dev/cons, which gives			 * alternate data to alternate readers.  So to keep things sane for			 * wctl, we compromise and give an error if two people try to			 * open it.  Apologies.			 */			if(w->wctlopen){				filsysrespond(x->fs, x, &t, Einuse);				return;			}			w->wctlopen = TRUE;			w->wctlready = 1;			wsendctlmesg(w, Wakeup, ZR, nil);		}		break;	}	t.qid = x->f->qid;	t.iounit = messagesize-IOHDRSZ;	x->f->open = TRUE;	x->f->mode = x->mode;	filsysrespond(x->fs, x, &t, nil);}voidxfidclose(Xfid *x){	Fcall t;	Window *w;	int nb, nulls;	w = x->f->w;	switch(FILE(x->f->qid)){	case Qconsctl:		if(w->rawing){			w->rawing = FALSE;			wsendctlmesg(w, Rawoff, ZR, nil);		}		if(w->holding){			w->holding = FALSE;			wsendctlmesg(w, Holdoff, ZR, nil);		}		w->ctlopen = FALSE;		break;	case Qcursor:		w->cursorp = nil;		wsetcursor(w, FALSE);		break;	case Qmouse:		w->resized = FALSE;		w->mouseopen = FALSE;		if(w->i != nil)			wsendctlmesg(w, Refresh, w->i->r, nil);		break;	/* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */	case Qsnarf:		if(x->f->mode==ORDWR || x->f->mode==OWRITE){			snarf = runerealloc(snarf, ntsnarf+1);			cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);			free(tsnarf);			tsnarf = nil;			ntsnarf = 0;		}		break;	case Qwctl:		if(x->f->mode==OREAD || x->f->mode==ORDWR)			w->wctlopen = FALSE;		break;	}	wclose(w);	filsysrespond(x->fs, x, &t, nil);}voidxfidwrite(Xfid *x){	Fcall fc;	int c, cnt, qid, nb, off, nr;	char buf[256], *p;	Point pt;	Window *w;	Rune *r;	Conswritemesg cwm;	Stringpair pair;	enum { CWdata, CWflush, NCW };	Alt alts[NCW+1];	w = x->f->w;	if(w->deleted){		filsysrespond(x->fs, x, &fc, Edeleted);		return;	}	qid = FILE(x->f->qid);	cnt = x->count;	off = x->offset;	x->data[cnt] = 0;	switch(qid){	case Qcons:		nr = x->f->nrpart;		if(nr > 0){			memmove(x->data+nr, x->data, cnt);	/* there's room: see malloc in filsysproc */			memmove(x->data, x->f->rpart, nr);			cnt += nr;			x->f->nrpart = 0;		}		r = runemalloc(cnt);		cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);		/* approach end of buffer */		while(fullrune(x->data+nb, cnt-nb)){			c = nb;			nb += chartorune(&r[nr], x->data+c);			if(r[nr])				nr++;		}		if(nb < cnt){			memmove(x->f->rpart, x->data+nb, cnt-nb);			x->f->nrpart = cnt-nb;		}		x->flushtag = x->tag;		alts[CWdata].c = w->conswrite;		alts[CWdata].v = &cwm;		alts[CWdata].op = CHANRCV;		alts[CWflush].c = x->flushc;		alts[CWflush].v = nil;		alts[CWflush].op = CHANRCV;		alts[NCW].op = CHANEND;			switch(alt(alts)){		case CWdata:			break;		case CWflush:			filsyscancel(x);			return;		}		/* received data */		x->flushtag = -1;		if(x->flushing){			recv(x->flushc, nil);	/* wake up flushing xfid */			pair.s = runemalloc(1);			pair.ns = 0;			send(cwm.cw, &pair);		/* wake up window with empty data */			filsyscancel(x);			return;		}		qlock(&x->active);		pair.s = r;		pair.ns = nr;		send(cwm.cw, &pair);		fc.count = x->count;		filsysrespond(x->fs, x, &fc, nil);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -