plan 9 kernel history: overview | file list | diff list

1991/0708/port/devbit.c (diff list | history)

1991/0708/sys/src/9/port/devbit.c:1,12591991/0710/sys/src/9/port/devbit.c:1,1259 (short | long | prev | next)
1990/0324    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"errno.h" 
 
#include	"devtab.h" 
 
1990/0912    
#include	<libg.h> 
1990/0902    
#include	<gnot.h> 
1991/0708    
#include	"screen.h" 
1990/0324    
 
1990/0902    
extern GFont	*defont; 
1990/0329    
 
1990/0327    
/* 
1991/0706    
 * Some monochrome screens are reversed from what we like: 
 * We want 0's bright and 1s dark. 
 * Indexed by an Fcode, these compensate for the source bitmap being wrong 
 * (exchange S rows) and destination (exchange D columns and invert result) 
 */ 
int flipS[] = { 
	0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 
	0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF 
}; 
 
int flipD[] = { 
	0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4, 
	0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0,  
}; 
 
int flipping;	/* are flip tables being used to transform Fcodes? */ 
int hwcursor;	/* is there a hardware cursor? */ 
 
/* 
1990/0329    
 * Device (#b/bitblt) is exclusive use on open, so no locks are necessary 
 * for i/o 
 */ 
 
/* 
1990/0902    
 * Some fields in GBitmaps are overloaded: 
1990/0327    
 *	ldepth = -1 means free. 
 *	base is next pointer when free. 
 * Arena is a word containing N, followed by a pointer to its bitmap, 
 * followed by N blocks.  The bitmap pointer is zero if block is free.  
 */ 
1990/0324    
 
1990/05313    
struct 
{ 
1990/0324    
	Ref; 
1990/0902    
	GBitmap	*map;		/* arena */ 
	GBitmap	*free;		/* free list */ 
1990/0327    
	ulong	*words;		/* storage */ 
	ulong	nwords;		/* total in arena */ 
	ulong	*wfree;		/* pointer to next free word */ 
1990/0902    
	GFont	*font;		/* arena; looked up linearly BUG */ 
1990/0327    
	int	lastid;		/* last allocated bitmap id */ 
1990/0623    
	int	lastfid;	/* last allocated font id */ 
1990/0329    
	int	init;		/* freshly opened; init message pending */ 
1990/0613    
	int	rid;		/* read bitmap id */ 
	int	rminy;		/* read miny */ 
	int	rmaxy;		/* read maxy */ 
1991/0706    
	int	mid;		/* colormap read bitmap id */ 
1990/0324    
}bit; 
 
1990/0327    
#define	FREE	0x80000000 
void	bitcompact(void); 
1990/0902    
void	bitfree(GBitmap*); 
1990/0912    
extern	GBitmap	gscreen; 
1990/0327    
 
1991/0707    
Mouseinfo	mouse; 
Cursorinfo	cursor; 
1990/0504    
 
1990/05313    
Cursor	arrow = 
{ 
1990/0730    
	{-1, -1}, 
1990/05313    
	{0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00, 
	 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0, 
	 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE, 
	 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 
	}, 
	{0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, 
	 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, 
	 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 
	 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, 
	} 
}; 
 
1990/0504    
ulong setbits[16]; 
1990/0902    
GBitmap	set = 
1990/0504    
{ 
	setbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16} 
}; 
 
ulong clrbits[16]; 
1990/0902    
GBitmap	clr = 
1990/0504    
{ 
	clrbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16} 
}; 
 
1991/0706    
ulong cursorbackbits[16*4]; 
1990/0902    
GBitmap cursorback = 
1990/0504    
{ 
	cursorbackbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16} 
}; 
 
1990/05313    
void	Cursortocursor(Cursor*); 
1990/0504    
void	cursoron(int); 
void	cursoroff(int); 
1990/0505    
int	mousechanged(void*); 
1990/0504    
 
1990/0324    
enum{ 
	Qdir, 
	Qbitblt, 
1990/0329    
	Qmouse, 
1990/0709    
	Qscreen, 
1990/0324    
}; 
 
Dirtab bitdir[]={ 
1990/11211    
	"bitblt",	{Qbitblt},	0,			0600, 
	"mouse",	{Qmouse},	0,			0600, 
	"screen",	{Qscreen},	0,			0400, 
1990/0324    
}; 
 
#define	NBIT	(sizeof bitdir/sizeof(Dirtab)) 
1990/0629    
#define	NINFO	257 
1990/0324    
 
void 
bitreset(void) 
{ 
1990/0327    
	int i; 
1990/0902    
	GBitmap *bp; 
1991/0706    
	ulong r; 
1990/0327    
 
1990/0902    
	bit.map = ialloc(conf.nbitmap * sizeof(GBitmap), 0); 
1990/0327    
	for(i=0,bp=bit.map; i<conf.nbitmap; i++,bp++){ 
		bp->ldepth = -1; 
		bp->base = (ulong*)(bp+1); 
	} 
	bp--; 
	bp->base = 0; 
1990/0912    
	bit.map[0] = gscreen;	/* bitmap 0 is screen */ 
1991/0706    
	getcolor(0, &r, &r, &r); 
	if(r == 0) 
		flipping = 1; 
1990/0327    
	bit.free = bit.map+1; 
	bit.lastid = -1; 
1990/0623    
	bit.lastfid = -1; 
1990/0327    
	bit.words = ialloc(conf.nbitbyte, 0); 
	bit.nwords = conf.nbitbyte/sizeof(ulong); 
	bit.wfree = bit.words; 
1990/0902    
	bit.font = ialloc(conf.nfont * sizeof(GFont), 0); 
1990/0623    
	bit.font[0] = *defont; 
	for(i=1; i<conf.nfont; i++) 
		bit.font[i].info = ialloc((NINFO+1)*sizeof(Fontchar), 0); 
1990/05313    
	Cursortocursor(&arrow); 
1990/0324    
} 
 
void 
bitinit(void) 
{ 
	lock(&bit); 
	unlock(&bit); 
1991/0706    
	if(gscreen.ldepth > 3) 
		cursorback.ldepth = 0; 
	else { 
		cursorback.ldepth = gscreen.ldepth; 
		cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5; 
	} 
1990/0504    
	cursoron(1); 
1990/0324    
} 
 
Chan* 
bitattach(char *spec) 
{ 
	return devattach('b', spec); 
} 
 
Chan* 
bitclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
1990/11211    
	if(c->qid.path != CHDIR) 
1990/0324    
		incref(&bit); 
1991/0706    
	return nc; 
1990/0324    
} 
 
int 
bitwalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, bitdir, NBIT, devgen); 
} 
 
void 
bitstat(Chan *c, char *db) 
{ 
	devstat(c, db, bitdir, NBIT, devgen); 
} 
 
Chan * 
bitopen(Chan *c, int omode) 
{ 
1990/11211    
	if(c->qid.path == CHDIR){ 
1990/0324    
		if(omode != OREAD) 
1990/11211    
			error(Eperm); 
	}else if(c->qid.path == Qbitblt){ 
1990/0324    
		lock(&bit); 
1990/0515    
		if(bit.ref){ 
1990/0324    
			unlock(&bit); 
1990/11211    
			error(Einuse); 
1990/0324    
		} 
1990/0327    
		bit.lastid = -1; 
1990/0623    
		bit.lastfid = -1; 
1990/0613    
		bit.rid = -1; 
1991/0706    
		bit.mid = -1; 
1990/0604    
		bit.init = 0; 
1990/05151    
		bit.ref = 1; 
1990/05313    
		Cursortocursor(&arrow); 
1990/0324    
		unlock(&bit); 
1990/05151    
	}else 
1990/0324    
		incref(&bit); 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void 
bitcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitremove(Chan *c) 
{ 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitwstat(Chan *c, char *db) 
{ 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitclose(Chan *c) 
{ 
1990/0327    
	int i; 
1990/0902    
	GBitmap *bp; 
	GFont *fp; 
1990/0327    
 
1990/11211    
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){ 
1990/0329    
		lock(&bit); 
1990/0327    
		if(--bit.ref == 0){ 
			for(i=1,bp=&bit.map[1]; i<conf.nbitmap; i++,bp++) 
				if(bp->ldepth >= 0) 
					bitfree(bp); 
1990/0623    
			for(i=1,fp=&bit.font[1]; i<conf.nfont; i++,fp++) 
				fp->bits = 0; 
1990/0327    
		} 
1990/0324    
		unlock(&bit); 
	} 
} 
 
1990/0327    
#define	GSHORT(p)		(((p)[0]<<0) | ((p)[1]<<8)) 
#define	GLONG(p)		((GSHORT(p)<<0) | (GSHORT(p+2)<<16)) 
1990/0329    
#define	PSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8)) 
#define	PLONG(p, v)		(PSHORT(p, (v)), PSHORT(p+2, (v)>>16)) 
1990/0327    
 
1990/0329    
/* 
 * These macros turn user-level (high bit at left) into internal (whatever) 
1991/0706    
 * bit order. So far all machines have the same (good) order; when 
 * that changes, these should switch on a variable set at init time. 
1990/0329    
 */ 
#define	U2K(x)	(x) 
#define	K2U(x)	(x) 
 
1990/0324    
long 
1991/0411    
bitread(Chan *c, void *va, long n, ulong offset) 
1990/0324    
{ 
1990/0613    
	uchar *p, *q; 
	long miny, maxy, t, x, y; 
1991/0706    
	ulong l, nw, ws, rv, gv, bv; 
1990/06231    
	int off, j; 
	Fontchar *i; 
1990/0902    
	GBitmap *src; 
1990/0327    
 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0324    
		return devdirread(c, va, n, bitdir, NBIT, devgen); 
 
1990/11211    
	switch(c->qid.path){ 
1990/0505    
	case Qmouse: 
1990/0329    
		/* 
1990/0505    
		 * mouse: 
		 *	'm'		1 
		 *	buttons		1 
		 * 	point		8 
1990/0329    
		 */ 
1990/0505    
		if(n < 10) 
1990/11211    
			error(Ebadblt); 
1990/0505    
	    Again: 
		while(mouse.changed == 0) 
			sleep(&mouse.r, mousechanged, 0); 
		lock(&cursor); 
		if(mouse.changed == 0){ 
			unlock(&cursor); 
			goto Again; 
		} 
		p = va; 
		p[0] = 'm'; 
		p[1] = mouse.buttons; 
		PLONG(p+2, mouse.xy.x); 
		PLONG(p+6, mouse.xy.y); 
		mouse.changed = 0; 
		unlock(&cursor); 
		n = 10; 
		break; 
 
	case Qbitblt: 
		p = va; 
1990/0329    
		/* 
1990/0505    
		 * Fuss about and figure out what to say. 
1990/0329    
		 */ 
1990/0505    
		if(bit.init){ 
			/* 
			 * init: 
			 *	'I'		1 
			 *	ldepth		1 
			 * 	rectangle	16 
1990/06231    
			 * if count great enough, also 
			 *	font info	3*12 
			 *	fontchars	6*(defont->n+1) 
1990/0505    
			 */ 
			if(n < 18) 
1990/11211    
				error(Ebadblt); 
1990/0505    
			p[0] = 'I'; 
1990/0912    
			p[1] = gscreen.ldepth; 
			PLONG(p+2, gscreen.r.min.x); 
			PLONG(p+6, gscreen.r.min.y); 
			PLONG(p+10, gscreen.r.max.x); 
			PLONG(p+14, gscreen.r.max.y); 
1990/06231    
			if(n >= 18+3*12+6*(defont->n+1)){ 
				p += 18; 
				sprint((char*)p, "%11d %11d %11d ", defont->n, 
					defont->height, defont->ascent); 
				p += 3*12; 
				for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){ 
					PSHORT(p, i->x); 
					p[2] = i->top; 
					p[3] = i->bottom; 
					p[4] = i->left; 
					p[5] = i->width; 
				} 
				n = 18+3*12+6*(defont->n+1); 
			}else 
				n = 18; 
1990/0505    
			bit.init = 0; 
			break; 
		} 
		if(bit.lastid > 0){ 
			/* 
			 * allocate: 
			 *	'A'		1 
			 *	bitmap id	2 
			 */ 
			if(n < 3) 
1990/11211    
				error(Ebadblt); 
1990/0505    
			p[0] = 'A'; 
			PSHORT(p+1, bit.lastid); 
			bit.lastid = -1; 
			n = 3; 
			break; 
		} 
1990/0623    
		if(bit.lastfid > 0){ 
			/* 
			 * allocate font: 
			 *	'K'		1 
			 *	font id		2 
			 */ 
			if(n < 3) 
1990/11211    
				error(Ebadblt); 
1990/0623    
			p[0] = 'K'; 
			PSHORT(p+1, bit.lastfid); 
			bit.lastfid = -1; 
			n = 3; 
			break; 
		} 
1991/0706    
		if(bit.mid >= 0){ 
			/* 
			 * read colormap: 
			 *	data		12*(2**bitmapdepth) 
			 */ 
			l = (1<<bit.map[bit.mid].ldepth); 
			nw = 1 << l; 
			if(n < 12*nw) 
				error(Ebadblt); 
			for(j = 0; j < nw; j++){ 
				if(bit.mid == 0){ 
					getcolor(flipping? ~j : j, &rv, &gv, &bv); 
				}else{ 
					rv = j; 
					for(off = 32-l; off > 0; off -= l) 
						rv = (rv << l) | j; 
					gv = bv = rv; 
				} 
				PLONG(p, rv); 
				PLONG(p+4, gv); 
				PLONG(p+8, bv); 
				p += 12; 
			} 
			bit.mid = -1; 
			n = 12*nw; 
			break; 
		} 
1990/0613    
		if(bit.rid >= 0){ 
			/* 
1991/0706    
			 * read bitmap: 
1990/0613    
			 *	data		bytewidth*(maxy-miny) 
			 */ 
			src = &bit.map[bit.rid]; 
			if(src->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0613    
			off = 0; 
			if(bit.rid == 0) 
				off = 1; 
			miny = bit.rminy; 
			maxy = bit.rmaxy; 
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y) 
1990/11211    
				error(Ebadblt); 
1990/0613    
			ws = 1<<(3-src->ldepth);	/* pixels per byte */ 
			/* set l to number of bytes of incoming data per scan line */ 
			if(src->r.min.x >= 0) 
				l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws; 
			else{	/* make positive before divide */ 
				t = (-src->r.min.x)+ws-1; 
				t = (t/ws)*ws; 
				l = (t+src->r.max.x+ws-1)/ws; 
			} 
			if(n < l*(maxy-miny)) 
1990/11211    
				error(Ebadblt); 
1990/0613    
			if(off) 
				cursoroff(1); 
			n = 0; 
			p = va; 
			for(y=miny; y<maxy; y++){ 
1990/0912    
				q = (uchar*)gaddr(src, Pt(src->r.min.x, y)); 
1990/0911    
				q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws; 
1991/0706    
				if(bit.rid == 0 && flipping)	/* flip bits */ 
					for(x=0; x<l; x++) 
						*p++ = ~K2U(*q++); 
				else 
					for(x=0; x<l; x++) 
						*p++ = K2U(*q++); 
1990/0613    
				n += l; 
			} 
			if(off) 
				cursoron(1); 
			bit.rid = -1; 
			break; 
		} 
1990/11211    
		error(Ebadblt); 
1990/0709    
 
	case Qscreen: 
1991/0411    
		if(offset==0){ 
1990/0709    
			if(n < 5*12) 
1990/11211    
				error(Eio); 
1990/0709    
			sprint(va, "%11d %11d %11d %11d %11d ", 
1990/0912    
				gscreen.ldepth, gscreen.r.min.x, 
				gscreen.r.min.y, gscreen.r.max.x, 
				gscreen.r.max.y); 
1990/0709    
			n = 5*12; 
			break; 
		} 
1990/0912    
		ws = 1<<(3-gscreen.ldepth);	/* pixels per byte */ 
		l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws; 
1991/0411    
		t = offset-5*12; 
1990/0709    
		miny = t/l; 
		maxy = (t+n)/l; 
1990/0912    
		if(miny >= gscreen.r.max.y) 
1990/0709    
			return 0; 
1990/0912    
		if(maxy >= gscreen.r.max.y) 
			maxy = gscreen.r.max.y; 
1990/0709    
		n = 0; 
		p = va; 
		for(y=miny; y<maxy; y++){ 
1990/0912    
			q = (uchar*)gaddr(&gscreen, Pt(0, y)); 
1990/0709    
			for(x=0; x<l; x++) 
				*p++ = K2U(*q++); 
			n += l; 
		} 
		break; 
1990/0505    
 
	default: 
1990/11211    
		error(Egreg); 
1990/0327    
	} 
 
	return n; 
1990/0324    
} 
 
 
long 
1991/0411    
bitwrite(Chan *c, void *va, long n, ulong offset) 
1990/0324    
{ 
1990/0329    
	uchar *p, *q; 
1991/0706    
	long m, v, miny, maxy, minx, maxx, t, x, y; 
	ulong l, nw, ws, rv; 
	int off, isoff, i, ok; 
1990/06111    
	Point pt, pt1, pt2; 
1990/0324    
	Rectangle rect; 
1990/05313    
	Cursor curs; 
1991/0706    
	Fcode fc; 
1990/0623    
	Fontchar *fcp; 
1990/0902    
	GBitmap *bp, *src, *dst; 
	GFont *f; 
1990/0324    
 
1990/11211    
	if(c->qid.path == CHDIR) 
		error(Eisdir); 
1990/0324    
 
1990/11211    
	if(c->qid.path != Qbitblt) 
		error(Egreg); 
1990/0327    
 
1990/0721    
	isoff = 0; 
	if(waserror()){ 
		if(isoff) 
			cursoron(1); 
		nexterror(); 
	} 
1990/0324    
	p = va; 
	m = n; 
1990/0327    
	while(m > 0) 
		switch(*p){ 
1990/0329    
		default: 
			pprint("bitblt request 0x%x\n", *p); 
1990/11211    
			error(Ebadblt); 
1990/0329    
 
1990/0327    
		case 'a': 
			/* 
			 * allocate: 
			 *	'a'		1 
			 *	ldepth		1 
			 *	Rectangle	16 
			 * next read returns allocated bitmap id 
			 */ 
			if(m < 18) 
1990/11211    
				error(Ebadblt); 
1990/0327    
			v = *(p+1); 
1991/0706    
			if(v>3)	/* BUG */ 
1990/11211    
				error(Ebadblt); 
1990/0327    
			ws = 1<<(5-v);	/* pixels per word */ 
			if(bit.free == 0) 
1990/11211    
				error(Enobitmap); 
1990/0327    
			rect.min.x = GLONG(p+2); 
			rect.min.y = GLONG(p+6); 
			rect.max.x = GLONG(p+10); 
			rect.max.y = GLONG(p+14); 
1991/0423    
			if(Dx(rect) < 0 || Dy(rect) < 0) 
				error(Ebadblt); 
1990/0327    
			if(rect.min.x >= 0) 
				l = (rect.max.x+ws-1)/ws - rect.min.x/ws; 
			else{	/* make positive before divide */ 
				t = (-rect.min.x)+ws-1; 
				t = (t/ws)*ws; 
				l = (t+rect.max.x+ws-1)/ws; 
1990/0324    
			} 
1990/0327    
			nw = l*Dy(rect); 
1990/05313    
			if(bit.wfree+2+nw > bit.words+bit.nwords){ 
1990/0327    
				bitcompact(); 
1990/05313    
				if(bit.wfree+2+nw > bit.words+bit.nwords) 
1990/11211    
					error(Enobitstore); 
1990/0327    
			} 
			bp = bit.free; 
1990/0902    
			bit.free = (GBitmap*)(bp->base); 
1990/0327    
			*bit.wfree++ = nw; 
			*bit.wfree++ = (ulong)bp; 
			bp->base = bit.wfree; 
			memset(bp->base, 0, nw*sizeof(ulong)); 
			bit.wfree += nw; 
			bp->zero = l*rect.min.y; 
			if(rect.min.x >= 0) 
				bp->zero += rect.min.x/ws; 
			else 
				bp->zero -= (-rect.min.x+ws-1)/ws; 
			bp->zero = -bp->zero; 
			bp->width = l; 
			bp->ldepth = v; 
1990/0329    
			bp->r = rect; 
1990/0327    
			bp->cache = 0; 
			bit.lastid = bp-bit.map; 
			m -= 18; 
			p += 18; 
			break; 
1990/0324    
 
1990/0327    
		case 'b': 
			/* 
			 * bitblt 
			 *	'b'		1 
			 *	dst id		2 
			 *	dst Point	8 
			 *	src id		2 
			 *	src Rectangle	16 
			 *	code		2 
			 */ 
			if(m < 31) 
1990/11211    
				error(Ebadblt); 
1991/0706    
			fc = GSHORT(p+29) & 0xF; 
			v = GSHORT(p+11); 
			src = &bit.map[v]; 
			if(v<0 || v>=conf.nbitmap || src->ldepth < 0) 
				error(Ebadbitmap); 
			off = 0; 
			if(v == 0){ 
				if(flipping) 
					fc = flipS[fc]; 
				off = 1; 
			} 
1990/0327    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
			if(v<0 || v>=conf.nbitmap || dst->ldepth < 0) 
1990/11211    
				error(Ebadbitmap); 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0504    
				off = 1; 
1991/0706    
			} 
1990/0327    
			pt.x = GLONG(p+3); 
			pt.y = GLONG(p+7); 
			rect.min.x = GLONG(p+13); 
			rect.min.y = GLONG(p+17); 
			rect.max.x = GLONG(p+21); 
			rect.max.y = GLONG(p+25); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/0706    
			gbitblt(dst, pt, src, rect, fc); 
1991/0710    
			ubitblt(dst, pt, src, rect, fc); 
1990/0327    
			m -= 31; 
			p += 31; 
			break; 
 
1990/05313    
		case 'c': 
			/* 
			 * cursorswitch 
			 *	'c'		1 
			 * nothing more: return to arrow; else 
			 * 	Point		8 
			 *	clr		32 
			 *	set		32 
			 */ 
			if(m == 1){ 
1990/0721    
				if(!isoff){ 
					cursoroff(1); 
					isoff = 1; 
				} 
1990/05313    
				Cursortocursor(&arrow); 
				m -= 1; 
				p += 1; 
				break; 
			} 
			if(m < 73) 
1990/11211    
				error(Ebadblt); 
1990/05313    
			curs.offset.x = GLONG(p+1); 
			curs.offset.y = GLONG(p+5); 
1991/0318    
			memmove(curs.clr, p+9, 2*16); 
			memmove(curs.set, p+41, 2*16); 
1990/0721    
			if(!isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
1990/05313    
			Cursortocursor(&curs); 
			m -= 73; 
			p += 73; 
			break; 
 
1990/0327    
		case 'f': 
			/* 
			 * free 
			 *	'f'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
1990/11211    
				error(Ebadblt); 
1990/0327    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0327    
			bitfree(dst); 
			m -= 3; 
			p += 3; 
1990/0604    
			break; 
 
1990/0623    
		case 'g': 
			/* 
			 * free font (free bitmap separately) 
			 *	'g'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
1990/11211    
				error(Ebadblt); 
1990/0623    
			v = GSHORT(p+1); 
			f = &bit.font[v]; 
			if(v<0 || v>=conf.nfont || f->bits==0) 
1990/11211    
				error(Ebadfont); 
1990/0623    
			f->bits = 0; 
			m -= 3; 
			p += 3; 
			break; 
 
1990/0604    
		case 'i': 
			/* 
			 * init 
			 * 
			 *	'i'		1 
			 */ 
			bit.init = 1; 
			m -= 1; 
			p += 1; 
1990/0327    
			break; 
1990/0329    
 
1990/0623    
		case 'k': 
			/* 
			 * allocate font 
			 *	'k'		1 
			 *	n		2 
			 *	height		1 
			 *	ascent		1 
			 *	bitmap id	2 
1990/0707    
			 *	fontchars	6*(n+1) 
1990/0623    
			 * next read returns allocated font id 
			 */ 
			if(m < 7) 
1990/11211    
				error(Ebadblt); 
1990/0623    
			v = GSHORT(p+1); 
			if(v<0 || v>NINFO || m<7+6*(v+1))	/* BUG */ 
1990/11211    
				error(Ebadblt); 
1990/0623    
			for(i=1; i<conf.nfont; i++) 
				if(bit.font[i].bits == 0) 
					goto fontfound; 
1990/11211    
			error(Enofont); 
1990/0623    
		fontfound: 
			f = &bit.font[i]; 
			f->n = v; 
			f->height = p[3]; 
			f->ascent = p[4]; 
			v = GSHORT(p+5); 
			dst = &bit.map[v]; 
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0623    
			m -= 7; 
			p += 7; 
			fcp = f->info; 
			for(i=0; i<=f->n; i++,fcp++){ 
				fcp->x = GSHORT(p); 
				fcp->top = p[2]; 
				fcp->bottom = p[3]; 
				fcp->left = p[4]; 
				fcp->width = p[5]; 
				fcp->top = p[2]; 
				p += 6; 
				m -= 6; 
			} 
			bit.lastfid = f - bit.font; 
			f->bits = dst; 
			break; 
 
1990/06111    
		case 'l': 
			/* 
			 * line segment 
			 * 
			 *	'l'		1 
			 *	id		2 
			 *	pt1		8 
			 *	pt2		8 
			 *	value		1 
			 *	code		2 
			 */ 
			if(m < 22) 
1990/11211    
				error(Ebadblt); 
1990/06111    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/06111    
			off = 0; 
1991/0706    
			fc = GSHORT(p+20) & 0xF; 
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/06111    
				off = 1; 
1991/0706    
			} 
1990/06111    
			pt1.x = GLONG(p+3); 
			pt1.y = GLONG(p+7); 
			pt2.x = GLONG(p+11); 
			pt2.y = GLONG(p+15); 
			t = p[19]; 
1990/0721    
			if(off && !isoff){ 
1990/06111    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/0706    
			gsegment(dst, pt1, pt2, t, fc); 
1990/06111    
			m -= 22; 
			p += 22; 
1990/0613    
			break; 
 
1991/0706    
		case 'm': 
			/* 
			 * read colormap 
			 * 
			 *	'm'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
				error(Ebadbitmap); 
			bit.mid = v; 
			m -= 3; 
			p += 3; 
			break; 
 
1990/0722    
		case 'p': 
			/* 
			 * point 
			 * 
			 *	'p'		1 
			 *	id		2 
			 *	pt		8 
			 *	value		1 
			 *	code		2 
			 */ 
			if(m < 14) 
1990/11211    
				error(Ebadblt); 
1990/0722    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0722    
			off = 0; 
1991/0706    
			fc = GSHORT(p+12) & 0xF; 
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0722    
				off = 1; 
1991/0706    
			} 
1990/0722    
			pt1.x = GLONG(p+3); 
			pt1.y = GLONG(p+7); 
			t = p[11]; 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
1991/0706    
			gpoint(dst, pt1, t, fc); 
1990/0722    
			m -= 14; 
			p += 14; 
			break; 
 
1990/0613    
		case 'r': 
			/* 
			 * read 
			 *	'r'		1 
			 *	src id		2 
			 *	miny		4 
			 *	maxy		4 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1990/0613    
			v = GSHORT(p+1); 
			src = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || src->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0613    
			miny = GLONG(p+3); 
			maxy = GLONG(p+7); 
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y) 
1990/11211    
				error(Ebadblt); 
1990/0613    
			bit.rid = v; 
			bit.rminy = miny; 
			bit.rmaxy = maxy; 
			p += 11; 
			m -= 11; 
1990/06111    
			break; 
 
1990/0329    
		case 's': 
			/* 
			 * string 
			 *	's'		1 
			 *	id		2 
			 *	pt		8 
			 *	font id		2 
1990/06111    
			 *	code		2 
1990/0329    
			 * 	string		n (null terminated) 
			 */ 
			if(m < 16) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0504    
			off = 0; 
1991/0706    
			fc = GSHORT(p+13) & 0xF; 
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0504    
				off = 1; 
1991/0706    
			} 
1990/0329    
			pt.x = GLONG(p+3); 
			pt.y = GLONG(p+7); 
			v = GSHORT(p+11); 
1990/0623    
			f = &bit.font[v]; 
			if(v<0 || v>=conf.nfont || f->bits==0 || f->bits->ldepth<0) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			p += 15; 
			m -= 15; 
			q = memchr(p, 0, m); 
			if(q == 0) 
1990/11211    
				error(Ebadblt); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/0706    
			gstring(dst, pt, f, (char*)p, fc); 
1990/0329    
			q++; 
			m -= q-p; 
			p = q; 
			break; 
 
		case 't': 
			/* 
			 * texture 
			 *	't'		1 
			 *	dst id		2 
			 *	Rectangle	16 
			 *	src id		2 
			 *	fcode		2 
			 */ 
			if(m < 23) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0504    
			off = 0; 
1991/0706    
			fc = GSHORT(p+21) & 0xF; 
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0504    
				off = 1; 
1991/0706    
			} 
1990/0329    
			rect.min.x = GLONG(p+3); 
			rect.min.y = GLONG(p+7); 
			rect.max.x = GLONG(p+11); 
			rect.max.y = GLONG(p+15); 
			v = GSHORT(p+19); 
			src = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || src->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1991/0701    
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
1990/0329    
			} 
1991/0706    
			gtexture(dst, rect, src, fc); 
1990/0329    
			m -= 23; 
			p += 23; 
			break; 
 
		case 'w': 
			/* 
			 * write 
			 *	'w'		1 
			 *	dst id		2 
			 *	miny		4 
			 *	maxy		4 
			 *	data		bytewidth*(maxy-miny) 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			v = GSHORT(p+1); 
			dst = &bit.map[v]; 
1990/0623    
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0) 
1990/11211    
				error(Ebadbitmap); 
1990/0504    
			off = 0; 
			if(v == 0) 
				off = 1; 
1990/0329    
			miny = GLONG(p+3); 
			maxy = GLONG(p+7); 
1990/03291    
			if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y) 
1990/11211    
				error(Ebadblt); 
1990/0329    
			ws = 1<<(3-dst->ldepth);	/* pixels per byte */ 
			/* set l to number of bytes of incoming data per scan line */ 
			if(dst->r.min.x >= 0) 
				l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws; 
			else{	/* make positive before divide */ 
				t = (-dst->r.min.x)+ws-1; 
				t = (t/ws)*ws; 
				l = (t+dst->r.max.x+ws-1)/ws; 
			} 
			p += 11; 
			m -= 11; 
			if(m < l*(maxy-miny)) 
1990/11211    
				error(Ebadblt); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1990/0329    
			for(y=miny; y<maxy; y++){ 
1990/0912    
				q = (uchar*)gaddr(dst, Pt(dst->r.min.x, y)); 
1990/0911    
				q += (dst->r.min.x&((sizeof(ulong))*ws-1))/ws; 
1991/0706    
				if(v == 0 && flipping)	/* flip bits */ 
					for(x=0; x<l; x++) 
						*q++ = ~U2K(*p++); 
				else 
					for(x=0; x<l; x++) 
						*q++ = U2K(*p++); 
1990/0329    
				m -= l; 
			} 
			break; 
1990/0826    
 
		case 'x': 
			/* 
			 * cursorset 
			 * 
			 *	'x'		1 
			 *	pt		8 
			 */ 
			if(m < 9) 
1990/11211    
				error(Ebadblt); 
1990/0826    
			pt1.x = GLONG(p+1); 
			pt1.y = GLONG(p+5); 
1991/0706    
/*			if(!eqpt(mouse.xy, pt1))*/{ 
1991/0619    
				mouse.xy = pt1; 
				mouse.track = 1; 
				mouseclock(); 
			} 
1990/0826    
			m -= 9; 
			p += 9; 
			break; 
1991/0706    
 
		case 'z': 
			/* 
			 * write the colormap 
			 * 
			 *	'z'		1 
			 *	id		2 
			 *	map		12*(2**bitmapdepth) 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
			v = GSHORT(p+1); 
			if(v != 0) 
				error(Ebadbitmap); 
			m -= 3; 
			p += 3; 
			nw = 1 << (1 << bit.map[v].ldepth); 
			if(m < 12*nw) 
				error(Ebadblt); 
			ok = 1; 
			for(i = 0; i < nw; i++){ 
				ok &= setcolor(i, GLONG(p), GLONG(p+4), GLONG(p+8)); 
				p += 12; 
				m -= 12; 
			} 
			if(!ok){ 
				/* assume monochrome: possibly change flipping */ 
				l = GLONG(p-12); 
				getcolor(nw-1, &rv, &rv, &rv); 
				flipping = (l != rv); 
			} 
			break; 
1990/0327    
		} 
 
1991/0614    
	poperror(); 
1990/0721    
	if(isoff) 
		cursoron(1); 
1990/0324    
	return n; 
} 
 
void 
1990/0902    
bitfree(GBitmap *bp) 
1990/0327    
{ 
1990/05313    
	bp->base[-1] = 0; 
1990/0327    
	bp->ldepth = -1; 
	bp->base = (ulong*)bit.free; 
	bit.free = bp; 
} 
 
1990/08101    
QLock	bitlock; 
 
1990/0902    
GBitmap * 
1990/08101    
id2bit(int k) 
{ 
1990/0902    
	GBitmap *bp; 
1990/08101    
	bp = &bit.map[k]; 
	if(k<0 || k>=conf.nbitmap || bp->ldepth < 0) 
1990/11211    
		error(Ebadbitmap); 
1990/08101    
	return bp; 
} 
 
1990/0327    
void 
bitcompact(void) 
{ 
	ulong *p1, *p2; 
 
1990/08101    
	qlock(&bitlock); 
1990/0327    
	p1 = p2 = bit.words; 
	while(p2 < bit.wfree){ 
		if(p2[1] == 0){ 
			p2 += 2 + p2[0]; 
			continue; 
		} 
		if(p1 != p2){ 
1991/0318    
			memmove(p1, p2, (2+p2[0])*sizeof(ulong)); 
1990/0902    
			((GBitmap*)p1[1])->base = p1+2; 
1990/0327    
		} 
		p2 += 2 + p1[0]; 
		p1 += 2 + p1[0]; 
	} 
	bit.wfree = p1; 
1990/08101    
	qunlock(&bitlock); 
1990/0329    
} 
 
void 
1990/05313    
Cursortocursor(Cursor *c) 
1990/0329    
{ 
1990/0504    
	int i; 
 
	lock(&cursor); 
1991/0318    
	memmove(&cursor, c, sizeof(Cursor)); 
1990/0504    
	for(i=0; i<16; i++){ 
1990/05313    
		setbits[i] = (c->set[2*i]<<24) + (c->set[2*i+1]<<16); 
		clrbits[i] = (c->clr[2*i]<<24) + (c->clr[2*i+1]<<16); 
1990/0504    
	} 
	unlock(&cursor); 
} 
 
void 
cursoron(int dolock) 
{ 
	if(dolock) 
		lock(&cursor); 
	if(cursor.visible++ == 0){ 
		cursor.r.min = mouse.xy; 
		cursor.r.max = add(mouse.xy, Pt(16, 16)); 
		cursor.r = raddp(cursor.r, cursor.offset); 
1990/0912    
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S); 
		gbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0710    
		kbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S); 
		kbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0706    
			&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S); 
1990/0912    
		gbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0710    
		kbitblt(&gscreen, add(mouse.xy, cursor.offset), 
1991/0706    
			&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D); 
1990/0504    
	} 
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
cursoroff(int dolock) 
{ 
	if(dolock) 
		lock(&cursor); 
	if(--cursor.visible == 0) 
1990/0912    
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S); 
1991/0710    
		kbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S); 
1990/0504    
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
1991/0706    
mousedelta(int b, int dx, int dy)	/* called at higher priority */ 
1990/0504    
{ 
1991/0706    
	mouse.dx += dx; 
	mouse.dy += dy; 
	mouse.newbuttons = b; 
	mouse.track = 1; 
} 
 
void 
mousebuttons(int b)	/* called at higher priority */ 
{ 
1990/0505    
	/* 
	 * It is possible if you click very fast and get bad luck 
	 * you could miss a button click (down up).  Doesn't seem 
	 * likely or important enough to worry about. 
	 */ 
	mouse.newbuttons = b; 
	mouse.track = 1;		/* aggressive but o.k. */ 
	mouseclock(); 
1990/0504    
} 
 
1991/0707    
 
1990/0504    
void 
1991/0707    
mouseupdate(int dolock) 
1990/0504    
{ 
1991/0706    
	int x, y; 
1991/0707    
 
	if(!mouse.track || (dolock && !canlock(&cursor))) 
		return; 
 
	x = mouse.xy.x + mouse.dx; 
	if(x < gscreen.r.min.x) 
		x = gscreen.r.min.x; 
	if(x >= gscreen.r.max.x) 
		x = gscreen.r.max.x; 
	y = mouse.xy.y + mouse.dy; 
	if(y < gscreen.r.min.y) 
		y = gscreen.r.min.y; 
	if(y >= gscreen.r.max.y) 
		y = gscreen.r.max.y; 
	cursoroff(0); 
	mouse.xy = Pt(x, y); 
	cursoron(0); 
	mouse.dx = 0; 
	mouse.dy = 0; 
	mouse.clock = 0; 
	mouse.track = 0; 
	mouse.buttons = mouse.newbuttons; 
	mouse.changed = 1; 
 
	if(dolock){ 
1991/0423    
		unlock(&cursor); 
		wakeup(&mouse.r); 
	} 
} 
 
1991/0605    
int 
mouseputc(IOQ *q, int c) 
{ 
1991/0706    
	static short msg[5]; 
	static int nb; 
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7}; 
1991/0605    
 
1991/0706    
	if((c&0xF0) == 0x80) 
		nb=0; 
	msg[nb] = c; 
	if(c & 0x80) 
		msg[nb] |= 0xFF00;	/* sign extend */ 
	if(++nb == 5){ 
		mouse.newbuttons = b[(msg[0]&7)^7]; 
		mouse.dx = msg[1]+msg[3]; 
		mouse.dy = -(msg[2]+msg[4]); 
		mouse.track = 1; 
		mouseclock(); 
		nb = 0; 
1990/0329    
	} 
1990/0505    
} 
 
int 
mousechanged(void *m) 
{ 
	return mouse.changed; 
1990/0324    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)