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

📄 devdraw.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
{	DImage *d, *next;	d = client->dimage[id&HASHMASK];	if(d == 0)		error(Enodrawimage);	if(d->id == id){		client->dimage[id&HASHMASK] = d->next;		drawfreedimage(d);		return;	}	while((next = d->next)){	/* assign = */		if(next->id == id){			d->next = next->next;			drawfreedimage(next);			return;		}		d = next;	}	error(Enodrawimage);}voiddrawaddname(Client *client, DImage *di, int n, char *str){	DName *name, *ename, *new, *t;	name = sdraw.name;	ename = &name[sdraw.nname];	for(; name<ename; name++)		if(drawcmp(name->name, str, n) == 0)			error(Enameused);	t = smalloc((sdraw.nname+1)*sizeof(DName));	memmove(t, sdraw.name, sdraw.nname*sizeof(DName));	free(sdraw.name);	sdraw.name = t;	new = &sdraw.name[sdraw.nname++];	new->name = smalloc(n+1);	memmove(new->name, str, n);	new->name[n] = 0;	new->dimage = di;	new->client = client;	new->vers = ++sdraw.vers;}Client*drawnewclient(void){	Client *cl, **cp;	int i;	for(i=0; i<sdraw.nclient; i++){		cl = sdraw.client[i];		if(cl == 0)			break;	}	if(i == sdraw.nclient){		cp = malloc((sdraw.nclient+1)*sizeof(Client*));		if(cp == 0)			return 0;		memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));		free(sdraw.client);		sdraw.client = cp;		sdraw.nclient++;		cp[i] = 0;	}	cl = malloc(sizeof(Client));	if(cl == 0)		return 0;	memset(cl, 0, sizeof(Client));	cl->slot = i;	cl->clientid = ++sdraw.clientid;	cl->op = SoverD;	sdraw.client[i] = cl;	return cl;}static intdrawclientop(Client *cl){	int op;	op = cl->op;	cl->op = SoverD;	return op;}intdrawhasclients(void){	/*	 * if draw has ever been used, we can't resize the frame buffer,	 * even if all clients have exited (nclients is cumulative); it's too	 * hard to make work.	 */	return sdraw.nclient != 0;}Client*drawclientofpath(ulong path){	Client *cl;	int slot;	slot = CLIENTPATH(path);	if(slot == 0)		return nil;	cl = sdraw.client[slot-1];	if(cl==0 || cl->clientid==0)		return nil;	return cl;}Client*drawclient(Chan *c){	Client *client;	client = drawclientofpath(c->qid.path);	if(client == nil)		error(Enoclient);	return client;}Memimage*drawimage(Client *client, uchar *a){	DImage *d;	d = drawlookup(client, BGLONG(a), 1);	if(d == nil)		error(Enodrawimage);	return d->image;}voiddrawrectangle(Rectangle *r, uchar *a){	r->min.x = BGLONG(a+0*4);	r->min.y = BGLONG(a+1*4);	r->max.x = BGLONG(a+2*4);	r->max.y = BGLONG(a+3*4);}voiddrawpoint(Point *p, uchar *a){	p->x = BGLONG(a+0*4);	p->y = BGLONG(a+1*4);}#define isvgascreen(dst) 1Pointdrawchar(Memimage *dst, Memimage *rdst, Point p, 	Memimage *src, Point *sp, DImage *font, int index, int op){	FChar *fc;	Rectangle r;	Point sp1;	static Memimage *tmp;	fc = &font->fchar[index];	r.min.x = p.x+fc->left;	r.min.y = p.y-(font->ascent-fc->miny);	r.max.x = r.min.x+(fc->maxx-fc->minx);	r.max.y = r.min.y+(fc->maxy-fc->miny);	sp1.x = sp->x+fc->left;	sp1.y = sp->y+fc->miny;		/*	 * If we're drawing greyscale fonts onto a VGA screen,	 * it's very costly to read the screen memory to do the	 * alpha blending inside memdraw.  If this is really a stringbg,	 * then rdst is the bg image (in main memory) which we can	 * refer to for the underlying dst pixels instead of reading dst	 * directly.	 */	if(1 || (isvgascreen(dst) && !isvgascreen(rdst) /*&& font->image->depth > 1*/)){		if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){			if(tmp)				freememimage(tmp);			tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan);			if(tmp == nil)				goto fallback;		}		memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S);		memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op);		memdraw(dst, r, tmp, ZP, memopaque, ZP, S);	}else{	fallback:		memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);	}	p.x += fc->width;	sp->x += fc->width;	return p;}static intinitscreenimage(void){	int width, depth;	ulong chan;	void *X;	Rectangle r;	if(screenimage != nil)		return 1;	screendata.base = nil;	screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);	if(screendata.bdata == nil && X == nil)		return 0;	screendata.ref = 1;	screenimage = allocmemimaged(r, chan, &screendata, X);	if(screenimage == nil){		/* RSC: BUG: detach screen */		return 0;	}	screenimage->width = width;	screenimage->clipr = r;	return 1;}voiddeletescreenimage(void){	qlock(&sdraw.lk);	/* RSC: BUG: detach screen */	if(screenimage)		freememimage(screenimage);	screenimage = nil;	qunlock(&sdraw.lk);}static Chan*drawattach(char *spec){	qlock(&sdraw.lk);	if(!initscreenimage()){		qunlock(&sdraw.lk);		error("no frame buffer");	}	qunlock(&sdraw.lk);	return devattach('i', spec);}static Walkqid*drawwalk(Chan *c, Chan *nc, char **name, int nname){	if(screendata.bdata == nil)		error("no frame buffer");	return devwalk(c, nc, name, nname, 0, 0, drawgen);}static intdrawstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, drawgen);}static Chan*drawopen(Chan *c, int omode){	Client *cl;	if(c->qid.type & QTDIR){		c = devopen(c, omode, 0, 0, drawgen);		c->iounit = IOUNIT;	}	qlock(&sdraw.lk);	if(waserror()){		qunlock(&sdraw.lk);		nexterror();	}	if(QID(c->qid) == Qnew){		cl = drawnewclient();		if(cl == 0)			error(Enodev);		c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);	}	switch(QID(c->qid)){	case Qnew:		break;	case Qctl:		cl = drawclient(c);		if(cl->busy)			error(Einuse);		cl->busy = 1;		flushrect = Rect(10000, 10000, -10000, -10000);		drawinstall(cl, 0, screenimage, 0);		incref(&cl->r);		break;	case Qcolormap:	case Qdata:	case Qrefresh:		cl = drawclient(c);		incref(&cl->r);		break;	}	qunlock(&sdraw.lk);	poperror();	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	c->iounit = IOUNIT;	return c;}static voiddrawclose(Chan *c){	int i;	DImage *d, **dp;	Client *cl;	Refresh *r;	if(QID(c->qid) < Qcolormap)	/* Qtopdir, Qnew, Q3rd, Q2nd have no client */		return;	qlock(&sdraw.lk);	if(waserror()){		qunlock(&sdraw.lk);		nexterror();	}	cl = drawclient(c);	if(QID(c->qid) == Qctl)		cl->busy = 0;	if((c->flag&COPEN) && (decref(&cl->r)==0)){		while((r = cl->refresh)){	/* assign = */			cl->refresh = r->next;			free(r);		}		/* free names */		for(i=0; i<sdraw.nname; )			if(sdraw.name[i].client == cl)				drawdelname(sdraw.name+i);			else				i++;		while(cl->cscreen)			drawuninstallscreen(cl, cl->cscreen);		/* all screens are freed, so now we can free images */		dp = cl->dimage;		for(i=0; i<NHASH; i++){			while((d = *dp) != nil){				*dp = d->next;				drawfreedimage(d);			}			dp++;		}		sdraw.client[cl->slot] = 0;		drawflush();	/* to erase visible, now dead windows */		free(cl);	}	qunlock(&sdraw.lk);	poperror();}longdrawread(Chan *c, void *a, long n, vlong off){	int index, m;	ulong red, green, blue;	Client *cl;	uchar *p;	Refresh *r;	DImage *di;	Memimage *i;	ulong offset = off;	char buf[16];	if(c->qid.type & QTDIR)		return devdirread(c, a, n, 0, 0, drawgen);	cl = drawclient(c);	qlock(&sdraw.lk);	if(waserror()){		qunlock(&sdraw.lk);		nexterror();	}	switch(QID(c->qid)){	case Qctl:		if(n < 12*12)			error(Eshortread);		if(cl->infoid < 0)			error(Enodrawimage);		if(cl->infoid == 0){			i = screenimage;			if(i == nil)				error(Enodrawimage);		}else{			di = drawlookup(cl, cl->infoid, 1);			if(di == nil)				error(Enodrawimage);			i = di->image;		}		n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",			cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,			i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,			i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);		cl->infoid = -1;		break;	case Qcolormap:		drawactive(1);	/* to restore map from backup */		p = malloc(4*12*256+1);		if(p == 0)			error(Enomem);		m = 0;		for(index = 0; index < 256; index++){			getcolor(index, &red, &green, &blue);			m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);		}		n = readstr(offset, a, n, (char*)p);		free(p);		break;	case Qdata:		if(cl->readdata == nil)			error("no draw data");		if(n < cl->nreaddata)			error(Eshortread);		n = cl->nreaddata;		memmove(a, cl->readdata, cl->nreaddata);		free(cl->readdata);		cl->readdata = nil;		break;	case Qrefresh:		if(n < 5*4)			error(Ebadarg);		for(;;){			if(cl->refreshme || cl->refresh)				break;			qunlock(&sdraw.lk);			if(waserror()){				qlock(&sdraw.lk);	/* restore lock for waserror() above */				nexterror();			}			sleep(&cl->refrend, drawrefactive, cl);			poperror();			qlock(&sdraw.lk);		}		p = a;		while(cl->refresh && n>=5*4){			r = cl->refresh;			BPLONG(p+0*4, r->dimage->id);			BPLONG(p+1*4, r->r.min.x);			BPLONG(p+2*4, r->r.min.y);			BPLONG(p+3*4, r->r.max.x);			BPLONG(p+4*4, r->r.max.y);			cl->refresh = r->next;			free(r);			p += 5*4;			n -= 5*4;		}		cl->refreshme = 0;		n = p-(uchar*)a;	}	qunlock(&sdraw.lk);	poperror();	return n;}voiddrawwakeall(void){	Client *cl;	int i;	for(i=0; i<sdraw.nclient; i++){		cl = sdraw.client[i];		if(cl && (cl->refreshme || cl->refresh))			wakeup(&cl->refrend);	}}static longdrawwrite(Chan *c, void *a, long n, vlong offset){	char buf[128], *fields[4], *q;	Client *cl;	int i, m, red, green, blue, x;	USED(offset);	if(c->qid.type & QTDIR)		error(Eisdir);	cl = drawclient(c);	qlock(&sdraw.lk);	if(waserror()){		drawwakeall();		qunlock(&sdraw.lk);		nexterror();	}	switch(QID(c->qid)){	case Qctl:		if(n != 4)			error("unknown draw control request");		cl->infoid = BGLONG((uchar*)a);		break;	case Qcolormap:		drawactive(1);	/* to restore map from backup */		m = n;		n = 0;		while(m > 0){			x = m;			if(x > sizeof(buf)-1)				x = sizeof(buf)-1;			q = memccpy(buf, a, '\n', x);			if(q == 0)				break;			i = q-buf;			n += i;			a = (char*)a + i;			m -= i;			*q = 0;			if(tokenize(buf, fields, nelem(fields)) != 4)				error(Ebadarg);			i = strtoul(fields[0], 0, 0);			red = strtoul(fields[1], 0, 0);			green = strtoul(fields[2], 0, 0);			blue = strtoul(fields[3], &q, 0);			if(fields[3] == q)				error(Ebadarg);			if(red>255 || green>255 || blue>255 || i<0 || i>255)				error(Ebadarg);			red |= red<<8;			red |= red<<16;			green |= green<<8;			green |= green<<16;			blue |= blue<<8;			blue |= blue<<16;			setcolor(i, red, green, blue);		}		break;	case Qdata:		drawmesg(cl, a, n);		drawwakeall();		break;	default:		error(Ebadusefd);	}	qunlock(&sdraw.lk);	poperror();	return n;}uchar*drawcoord(uchar *p, uchar *maxp, int oldx, int *newx){	int b, x;	if(p >= maxp)		error(Eshortdraw);	b = *p++;	x = b & 0x7F;	if(b & 0x80){		if(p+1 >= maxp)			error(Eshortdraw);		x |= *p++ << 7;		x |= *p++ << 15;		if(x & (1<<22))			x |= ~0<<23;	}else{		if(b & 0x40)			x |= ~0<<7;		x += oldx;	}	*newx = x;	return p;}static voidprintmesg(char *fmt, uchar *a, int plsprnt){	char buf[256];	char *p, *q;	int s;	if(1|| plsprnt==0){		SET(s);		SET(q);		SET(p);		USED(fmt);		USED(a);		USED(buf);		USED(p);		USED(q);		USED(s);		return;	}	q = buf;	*q++ = *a++;	for(p=fmt; *p; p++){		switch(*p){		case 'l':			q += sprint(q, " %ld", (long)BGLONG(a));			a += 4;			break;		case 'L':			q += sprint(q, " %.8lux", (ulong)BGLONG(a));			a += 4;			break;		case 'R':			q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));			a += 16;			break;		case 'P':			q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));			a += 8;			break;		case 'b':			q += sprint(q, " %d", *a++);			break;		case 's':			q += sprint(q, " %d", BGSHORT(a));			a += 2;			break;		case 'S':			q += sprint(q, " %.4ux", BGSHORT(a));			a += 2;			break;		}	}	*q++ = '\n';	*q = 0;	iprint("%.*s", (int)(q-buf), buf);}voiddrawmesg(Client *client, void *av, int n){	int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;	uchar *u, *a, refresh;	char *fmt;	ulong value, chan;	Rectangle r, clipr;	Point p, q, *pp, sp;	Memimage *i, *dst, *src, *mask;	Memimage *l, **lp;	Memscreen *scrn;	DImage *font, *ll, *di, *ddst, *dsrc;	DName *dn;	DScreen *dscrn;	FChar *fc;	Refx *refx;	CScreen *cs;	Refreshfn reffn;	a = av;	m = 0;	fmt = nil;	if(waserror()){		if(fmt) printmesg(fmt, a, 1);	/*	iprint("error: %s\n", up->errstr);	*/		nexterror();	}	while((n-=m) > 0){		USED(fmt);		a += m;		switch(*a){		default:			error("bad draw command");		/* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */		case 'b':			printmesg(fmt="LLbLbRRL", a, 0);			m = 1+4+4+1+4+1+4*4+4*4+4;			if(n < m)				error(Eshortdraw);			dstid = BGLONG(a+1);			scrnid = BGSHORT(a+5);			refresh = a[9];			chan = BGLONG(a+10);			repl = a[14];			drawrectangle(&r, a+15);			drawrectangle(&clipr, a+31);			value = BGLONG(a+47);			if(drawlookup(client, dstid, 0))				error(Eimageexists);			if(scrnid){				dscrn = drawlookupscreen(client, scrnid, &cs);				scrn = dscrn->screen;				if(repl || chan!=scrn->image->chan)					error("image parameters incompatible with screen");				reffn = 0;				switch(refresh){				case Refbackup:					break;				case Refnone:					reffn = memlnorefresh;					break;				case Refmesg:					reffn = drawrefresh;					break;				default:					error("unknown refresh method");				}				l = memlalloc(scrn, r, reffn, 0, value);				if(l == 0)					error(Edrawmem);				addflush(l->layer->screenr);				l->clipr = clipr;				rectclip(&l->clipr, r);				if(drawinstall(client, dstid, l, dscrn) == 0){					memldelete(l);

⌨️ 快捷键说明

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