Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ss/devbit.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname ss/devbit.c 1990/1223
## diff -e /dev/null /n/bootesdump/1990/1223/sys/src/9/sparc/devbit.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"

#include	"devtab.h"

#include	<libg.h>
#include	<gnot.h>

extern GFont	*defont;

/*
 * Device (#b/bitblt) is exclusive use on open, so no locks are necessary
 * for i/o
 */

/*
 * Some fields in GBitmaps are overloaded:
 *	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. 
 */

struct
{
	Ref;
	GBitmap	*map;		/* arena */
	GBitmap	*free;		/* free list */
	ulong	*words;		/* storage */
	ulong	nwords;		/* total in arena */
	ulong	*wfree;		/* pointer to next free word */
	GFont	*font;		/* arena; looked up linearly BUG */
	int	lastid;		/* last allocated bitmap id */
	int	lastfid;	/* last allocated font id */
	int	init;		/* freshly opened; init message pending */
	int	rid;		/* read bitmap id */
	int	rminy;		/* read miny */
	int	rmaxy;		/* read maxy */
}bit;

#define	FREE	0x80000000
void	bitcompact(void);
void	bitfree(GBitmap*);
extern	GBitmap	gscreen;

struct{
	/*
	 * First three fields are known in l.s
	 */
	int	dx;		/* interrupt-time delta */
	int	dy;
	int	track;		/* update cursor on screen */
	Mouse;
	int	changed;	/* mouse structure changed since last read */
	int	newbuttons;	/* interrupt time access only */
	Rendez	r;
}mouse;

Cursor	arrow =
{
	{-1, -1},
	{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,
	}
};

struct{
	Cursor;
	Lock;
	int	visible;	/* on screen */
	Rectangle r;		/* location */
}cursor;

ulong setbits[16];
GBitmap	set =
{
	setbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

ulong clrbits[16];
GBitmap	clr =
{
	clrbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

ulong cursorbackbits[16];
GBitmap cursorback =
{
	cursorbackbits,
	0,
	1,
	0,
	{0, 0, 16, 16}
};

void	Cursortocursor(Cursor*);
void	cursoron(int);
void	cursoroff(int);
int	mousechanged(void*);

enum{
	Qdir,
	Qbitblt,
	Qmouse,
	Qscreen,
};

Dirtab bitdir[]={
	"bitblt",	{Qbitblt},	0,			0600,
	"mouse",	{Qmouse},	0,			0600,
	"screen",	{Qscreen},	0,			0400,
};

#define	NBIT	(sizeof bitdir/sizeof(Dirtab))
#define	NINFO	257

void
bitreset(void)
{
	int i;
	GBitmap *bp;

	bit.map = ialloc(conf.nbitmap * sizeof(GBitmap), 0);
	for(i=0,bp=bit.map; i<conf.nbitmap; i++,bp++){
		bp->ldepth = -1;
		bp->base = (ulong*)(bp+1);
	}
	bp--;
	bp->base = 0;
	bit.map[0] = gscreen;	/* bitmap 0 is screen */
	bit.free = bit.map+1;
	bit.lastid = -1;
	bit.lastfid = -1;
	bit.words = ialloc(conf.nbitbyte, 0);
	bit.nwords = conf.nbitbyte/sizeof(ulong);
	bit.wfree = bit.words;
	bit.font = ialloc(conf.nfont * sizeof(GFont), 0);
	bit.font[0] = *defont;
	for(i=1; i<conf.nfont; i++)
		bit.font[i].info = ialloc((NINFO+1)*sizeof(Fontchar), 0);
	Cursortocursor(&arrow);
}

void
bitinit(void)
{
	lock(&bit);
	unlock(&bit);
	if(gscreen.ldepth > 1)
		panic("bitinit ldepth>1");
	cursorback.ldepth = gscreen.ldepth;
	cursoron(1);
}

Chan*
bitattach(char *spec)
{
	return devattach('b', spec);
}

Chan*
bitclone(Chan *c, Chan *nc)
{
	nc = devclone(c, nc);
	if(c->qid.path != CHDIR)
		incref(&bit);
}

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)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	}else if(c->qid.path == Qbitblt){
		lock(&bit);
		if(bit.ref){
			unlock(&bit);
			error(Einuse);
		}
		bit.lastid = -1;
		bit.lastfid = -1;
		bit.rid = -1;
		bit.init = 0;
		bit.ref = 1;
		Cursortocursor(&arrow);
		unlock(&bit);
	}else
		incref(&bit);
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void
bitcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
bitremove(Chan *c)
{
	error(Eperm);
}

void
bitwstat(Chan *c, char *db)
{
	error(Eperm);
}

void
bitclose(Chan *c)
{
	int i;
	GBitmap *bp;
	GFont *fp;

	if(c->qid.path!=CHDIR && (c->flag&COPEN)){
		lock(&bit);
		if(--bit.ref == 0){
			for(i=1,bp=&bit.map[1]; i<conf.nbitmap; i++,bp++)
				if(bp->ldepth >= 0)
					bitfree(bp);
			for(i=1,fp=&bit.font[1]; i<conf.nfont; i++,fp++)
				fp->bits = 0;
		}
		unlock(&bit);
	}
}

#define	GSHORT(p)		(((p)[0]<<0) | ((p)[1]<<8))
#define	GLONG(p)		((GSHORT(p)<<0) | (GSHORT(p+2)<<16))
#define	PSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8))
#define	PLONG(p, v)		(PSHORT(p, (v)), PSHORT(p+2, (v)>>16))

/*
 * These macros turn user-level (high bit at left) into internal (whatever)
 * bit order.  On the gnot they're trivial.
 */
#define	U2K(x)	(x)
#define	K2U(x)	(x)

long
bitread(Chan *c, void *va, long n)
{
	uchar *p, *q;
	long miny, maxy, t, x, y;
	ulong l, nw, ws;
	int off, j;
	Fontchar *i;
	GBitmap *src;

	if(c->qid.path & CHDIR)
		return devdirread(c, va, n, bitdir, NBIT, devgen);

	switch(c->qid.path){
	case Qmouse:
		/*
		 * mouse:
		 *	'm'		1
		 *	buttons		1
		 * 	point		8
		 */
		if(n < 10)
			error(Ebadblt);
	    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;
		/*
		 * Fuss about and figure out what to say.
		 */
		if(bit.init){
			/*
			 * init:
			 *	'I'		1
			 *	ldepth		1
			 * 	rectangle	16
			 * if count great enough, also
			 *	font info	3*12
			 *	fontchars	6*(defont->n+1)
			 */
			if(n < 18)
				error(Ebadblt);
			p[0] = 'I';
			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);
			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;
			bit.init = 0;
			break;
		}
		if(bit.lastid > 0){
			/*
			 * allocate:
			 *	'A'		1
			 *	bitmap id	2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'A';
			PSHORT(p+1, bit.lastid);
			bit.lastid = -1;
			n = 3;
			break;
		}
		if(bit.lastfid > 0){
			/*
			 * allocate font:
			 *	'K'		1
			 *	font id		2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'K';
			PSHORT(p+1, bit.lastfid);
			bit.lastfid = -1;
			n = 3;
			break;
		}
		if(bit.rid >= 0){
			/*
			 * read
			 *	data		bytewidth*(maxy-miny)
			 */
			src = &bit.map[bit.rid];
			if(src->ldepth<0)
				error(Ebadbitmap);
			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)
				error(Ebadblt);
			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))
				error(Ebadblt);
			if(off)
				cursoroff(1);
			n = 0;
			p = va;
			for(y=miny; y<maxy; y++){
				q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
				q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
				for(x=0; x<l; x++)
					*p++ = K2U(*q++);
				n += l;
			}
			if(off)
				cursoron(1);
			bit.rid = -1;
			break;
		}
		error(Ebadblt);

	case Qscreen:
		if(c->offset==0){
			if(n < 5*12)
				error(Eio);
			sprint(va, "%11d %11d %11d %11d %11d ",
				gscreen.ldepth, gscreen.r.min.x,
				gscreen.r.min.y, gscreen.r.max.x,
				gscreen.r.max.y);
			n = 5*12;
			break;
		}
		ws = 1<<(3-gscreen.ldepth);	/* pixels per byte */
		l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;
		t = c->offset-5*12;
		miny = t/l;
		maxy = (t+n)/l;
		if(miny >= gscreen.r.max.y)
			return 0;
		if(maxy >= gscreen.r.max.y)
			maxy = gscreen.r.max.y;
		n = 0;
		p = va;
		for(y=miny; y<maxy; y++){
			q = (uchar*)gaddr(&gscreen, Pt(0, y));
			for(x=0; x<l; x++)
				*p++ = K2U(*q++);
			n += l;
		}
		break;

	default:
		error(Egreg);
	}

	return n;
}


long
bitwrite(Chan *c, void *va, long n)
{
	uchar *p, *q;
	long m, v, miny, maxy, minx, maxx, t, x, y, tw, th;
	ulong l, nw, ws;
	int off, isoff, i;
	Point pt, pt1, pt2;
	Rectangle rect;
	Cursor curs;
	Fontchar *fcp;
	GBitmap *bp, *src, *dst;
	GFont *f;

	if(c->qid.path == CHDIR)
		error(Eisdir);

	if(c->qid.path != Qbitblt)
		error(Egreg);

	isoff = 0;
	if(waserror()){
		if(isoff)
			cursoron(1);
		nexterror();
	}
	p = va;
	m = n;
	while(m > 0)
		switch(*p){
		default:
			pprint("bitblt request 0x%x\n", *p);
			error(Ebadblt);

		case 'a':
			/*
			 * allocate:
			 *	'a'		1
			 *	ldepth		1
			 *	Rectangle	16
			 * next read returns allocated bitmap id
			 */
			if(m < 18)
				error(Ebadblt);
			v = *(p+1);
			if(v!=0 && v!=1)	/* BUG */
				error(Ebadblt);
			ws = 1<<(5-v);	/* pixels per word */
			if(bit.free == 0)
				error(Enobitmap);
			rect.min.x = GLONG(p+2);
			rect.min.y = GLONG(p+6);
			rect.max.x = GLONG(p+10);
			rect.max.y = GLONG(p+14);
			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;
			}
			nw = l*Dy(rect);
			if(bit.wfree+2+nw > bit.words+bit.nwords){
				bitcompact();
				if(bit.wfree+2+nw > bit.words+bit.nwords)
					error(Enobitstore);
			}
			bp = bit.free;
			bit.free = (GBitmap*)(bp->base);
			*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;
			bp->r = rect;
			bp->cache = 0;
			bit.lastid = bp-bit.map;
			m -= 18;
			p += 18;
			break;

		case 'b':
			/*
			 * bitblt
			 *	'b'		1
			 *	dst id		2
			 *	dst Point	8
			 *	src id		2
			 *	src Rectangle	16
			 *	code		2
			 */
			if(m < 31)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth < 0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt.x = GLONG(p+3);
			pt.y = GLONG(p+7);
			v = GSHORT(p+11);
			src = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || src->ldepth < 0)
				error(Ebadbitmap);
			if(v == 0)
				off = 1;
			rect.min.x = GLONG(p+13);
			rect.min.y = GLONG(p+17);
			rect.max.x = GLONG(p+21);
			rect.max.y = GLONG(p+25);
			v = GSHORT(p+29);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			balubitblt(dst, pt, src, rect, v);
			m -= 31;
			p += 31;
			break;

		case 'c':
			/*
			 * cursorswitch
			 *	'c'		1
			 * nothing more: return to arrow; else
			 * 	Point		8
			 *	clr		32
			 *	set		32
			 */
			if(m == 1){
				if(!isoff){
					cursoroff(1);
					isoff = 1;
				}
				Cursortocursor(&arrow);
				m -= 1;
				p += 1;
				break;
			}
			if(m < 73)
				error(Ebadblt);
			curs.offset.x = GLONG(p+1);
			curs.offset.y = GLONG(p+5);
			memcpy(curs.clr, p+9, 2*16);
			memcpy(curs.set, p+41, 2*16);
			if(!isoff){
				cursoroff(1);
				isoff = 1;
			}
			Cursortocursor(&curs);
			m -= 73;
			p += 73;
			break;

		case 'f':
			/*
			 * free
			 *	'f'		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);
			bitfree(dst);
			m -= 3;
			p += 3;
			break;

		case 'g':
			/*
			 * free font (free bitmap separately)
			 *	'g'		1
			 *	id		2
			 */
			if(m < 3)
				error(Ebadblt);
			v = GSHORT(p+1);
			f = &bit.font[v];
			if(v<0 || v>=conf.nfont || f->bits==0)
				error(Ebadfont);
			f->bits = 0;
			m -= 3;
			p += 3;
			break;

		case 'i':
			/*
			 * init
			 *
			 *	'i'		1
			 */
			bit.init = 1;
			m -= 1;
			p += 1;
			break;

		case 'k':
			/*
			 * allocate font
			 *	'k'		1
			 *	n		2
			 *	height		1
			 *	ascent		1
			 *	bitmap id	2
			 *	fontchars	6*(n+1)
			 * next read returns allocated font id
			 */
			if(m < 7)
				error(Ebadblt);
			v = GSHORT(p+1);
			if(v<0 || v>NINFO || m<7+6*(v+1))	/* BUG */
				error(Ebadblt);
			for(i=1; i<conf.nfont; i++)
				if(bit.font[i].bits == 0)
					goto fontfound;
			error(Enofont);
		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)
				error(Ebadbitmap);
			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;

		case 'l':
			/*
			 * line segment
			 *
			 *	'l'		1
			 *	id		2
			 *	pt1		8
			 *	pt2		8
			 *	value		1
			 *	code		2
			 */
			if(m < 22)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt1.x = GLONG(p+3);
			pt1.y = GLONG(p+7);
			pt2.x = GLONG(p+11);
			pt2.y = GLONG(p+15);
			t = p[19];
			v = GSHORT(p+20);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gsegment(dst, pt1, pt2, t, v);
			m -= 22;
			p += 22;
			break;

		case 'p':
			/*
			 * point
			 *
			 *	'p'		1
			 *	id		2
			 *	pt		8
			 *	value		1
			 *	code		2
			 */
			if(m < 14)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt1.x = GLONG(p+3);
			pt1.y = GLONG(p+7);
			t = p[11];
			v = GSHORT(p+12);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gpoint(dst, pt1, t, v);
			m -= 14;
			p += 14;
			break;

		case 'r':
			/*
			 * read
			 *	'r'		1
			 *	src id		2
			 *	miny		4
			 *	maxy		4
			 */
			if(m < 11)
				error(Ebadblt);
			v = GSHORT(p+1);
			src = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || src->ldepth<0)
				error(Ebadbitmap);
			miny = GLONG(p+3);
			maxy = GLONG(p+7);
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
				error(Ebadblt);
			bit.rid = v;
			bit.rminy = miny;
			bit.rmaxy = maxy;
			p += 11;
			m -= 11;
			break;

		case 's':
			/*
			 * string
			 *	's'		1
			 *	id		2
			 *	pt		8
			 *	font id		2
			 *	code		2
			 * 	string		n (null terminated)
			 */
			if(m < 16)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			pt.x = GLONG(p+3);
			pt.y = GLONG(p+7);
			v = GSHORT(p+11);
			f = &bit.font[v];
			if(v<0 || v>=conf.nfont || f->bits==0 || f->bits->ldepth<0)
				error(Ebadblt);
			v = GSHORT(p+13);
			p += 15;
			m -= 15;
			q = memchr(p, 0, m);
			if(q == 0)
				error(Ebadblt);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gstring(dst, pt, f, (char*)p, v);
			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)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			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];
			if(v<0 || v>=conf.nbitmap || src->ldepth<0)
				error(Ebadbitmap);
			v = GSHORT(p+21);
			x = src->r.min.x;
			y = src->r.min.y;
			tw = src->r.max.x - x;
			th = src->r.max.y - y;
			if(x==0 && y==0 && 16%tw == 0 && 16%th == 0){
				GTexture t;

				if(tw==16 && th==16)
					for(y=0; y<16; y++)
						t.bits[y] = src->base[y]>>16;
				else
					for(y=0; y<16; y++){
						l = src->base[y%th] >> (32-tw);
						for(i=16/tw, ws=l; i > 1; i--)
							ws = (ws<<tw) | l;
						t.bits[y] = ws;
					}
				if(off && !isoff){
					cursoroff(1);
					isoff = 1;
				}
				gtexture(dst, rect, &t, v);
			}else{
				GBitmap d;

				d = *dst;
				rect = rcanon(rect);
				if(rectclip(&d.r, rect)==0)
					return;
				/*
				 * Find x, maxx such that
				 * x <= rect.min.x < x+tw,
				 * maxx-tw < rect.max.x <= maxx
				 * and x, maxx are integral multiples of tw
				 * away from src->r.min.x
				 * Similarly for y, maxy
				 */
				if(x > rect.min.x)
					x -= ((x-rect.min.x+tw-1)/tw)*tw;
				else if(x+tw <= rect.min.x)
					x += ((rect.min.x-x)/tw)*tw;
				if(y > rect.min.y)
					y -= ((y-rect.min.y+th-1)/th)*th;
				else if(y+tw <= rect.min.y)
					y += ((rect.min.y-y)/th)*th;
				maxx = x+tw;
				if(maxx < rect.max.x)
					maxx += ((rect.max.x-maxx+tw-1)/tw)*tw;
				maxy = y+th;
				if(maxy < rect.max.y)
					maxy += ((rect.max.y-maxy+th-1)/th)*th;
				minx = x;
				if(off && !isoff){
					cursoroff(1);
					isoff = 1;
				}
				for( ; y<maxy; y+=th)
					for(x=minx; x<maxx; x+=tw)
						gbitblt(&d, Pt(x,y), src, src->r, v);
			}
			m -= 23;
			p += 23;
			break;

		case 'w':
			/*
			 * write
			 *	'w'		1
			 *	dst id		2
			 *	miny		4
			 *	maxy		4
			 *	data		bytewidth*(maxy-miny)
			 */
			if(m < 11)
				error(Ebadblt);
			v = GSHORT(p+1);
			dst = &bit.map[v];
			if(v<0 || v>=conf.nbitmap || dst->ldepth<0)
				error(Ebadbitmap);
			off = 0;
			if(v == 0)
				off = 1;
			miny = GLONG(p+3);
			maxy = GLONG(p+7);
			if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y)
				error(Ebadblt);
			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))
				error(Ebadblt);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			for(y=miny; y<maxy; y++){
				q = (uchar*)gaddr(dst, Pt(dst->r.min.x, y));
				q += (dst->r.min.x&((sizeof(ulong))*ws-1))/ws;
				for(x=0; x<l; x++)
					*q++ = U2K(*p++);
				m -= l;
			}
			break;

		case 'x':
			/*
			 * cursorset
			 *
			 *	'x'		1
			 *	pt		8
			 */
			if(m < 9)
				error(Ebadblt);
			pt1.x = GLONG(p+1);
			pt1.y = GLONG(p+5);
			mouse.xy = pt1;
			mouse.track = 1;
			mouseclock();
			m -= 9;
			p += 9;
			break;
		}

	if(isoff)
		cursoron(1);
	return n;
}

void
bitfree(GBitmap *bp)
{
	bp->base[-1] = 0;
	bp->ldepth = -1;
	bp->base = (ulong*)bit.free;
	bit.free = bp;
}

QLock	bitlock;

GBitmap *
id2bit(int k)
{
	GBitmap *bp;
	bp = &bit.map[k];
	if(k<0 || k>=conf.nbitmap || bp->ldepth < 0)
		error(Ebadbitmap);
	return bp;
}

void
bitcompact(void)
{
	ulong *p1, *p2;

	qlock(&bitlock);
	p1 = p2 = bit.words;
	while(p2 < bit.wfree){
		if(p2[1] == 0){
			p2 += 2 + p2[0];
			continue;
		}
		if(p1 != p2){
			memcpy(p1, p2, (2+p2[0])*sizeof(ulong));
			((GBitmap*)p1[1])->base = p1+2;
		}
		p2 += 2 + p1[0];
		p1 += 2 + p1[0];
	}
	bit.wfree = p1;
	qunlock(&bitlock);
}

void
Cursortocursor(Cursor *c)
{
	int i;

	lock(&cursor);
	memcpy(&cursor, c, sizeof(Cursor));
	for(i=0; i<16; i++){
		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);
	}
	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);
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
		gbitblt(&gscreen, add(mouse.xy, cursor.offset),
			&clr, Rect(0, 0, 16, 16), D&~S);
		gbitblt(&gscreen, add(mouse.xy, cursor.offset),
			&set, Rect(0, 0, 16, 16), S|D);
	}
	if(dolock)
		unlock(&cursor);
}

void
cursoroff(int dolock)
{
	if(dolock)
		lock(&cursor);
	if(--cursor.visible == 0)
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
	if(dolock)
		unlock(&cursor);
}

void
mousebuttons(int b)	/* called spl5 */
{
	/*
	 * 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();
}

void
mouseclock(void)	/* called spl6 */
{
	int x, y;
	if(mouse.track && canlock(&cursor)){
		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.track = 0;
		mouse.buttons = mouse.newbuttons;
		mouse.changed = 1;
		unlock(&cursor);
		wakeup(&mouse.r);
	}
}

int
mousechanged(void *m)
{
	return mouse.changed;
}
.
## diffname ss/devbit.c 1990/1226
## diff -e /n/bootesdump/1990/1223/sys/src/9/sparc/devbit.c /n/bootesdump/1990/1226/sys/src/9/sparc/devbit.c
1086a
print("cursor.r %d %d %d %d\n", cursor.r.min.x, cursor.r.min.y, cursor.r.max.x, cursor.r.max.y);
.
1085a
print("cursor.r %d %d %d %d\n", cursor.r.min.x, cursor.r.min.y, cursor.r.max.x, cursor.r.max.y);
.
1084a
print("cursor.r %d %d\n", mouse.xy.x, mouse.xy.y);
.
1083a
print("mouse %d %d\n", mouse.xy.x, mouse.xy.y);
.
594c
			gbitblt(dst, pt, src, rect, v);
.
141a
print("warning: mouse set\n");
mouse.xy.x = 50;
mouse.xy.y = 50;
.
## diffname ss/devbit.c 1990/1231
## diff -e /n/bootesdump/1990/1226/sys/src/9/sparc/devbit.c /n/bootesdump/1990/1231/sys/src/9/sparc/devbit.c
1152a
	}
}

void
mousechar(int c)
{
	static short msg[5];
	static int nb;

	if((c&0xF0) == 0x80)
		nb=0;
	msg[nb] = c;
	if(c & 0x80)
		msg[nb] |= 0xFF00;	/* sign extend */
	if(++nb == 5){
		mouse.newbuttons = (msg[0]&7)^7;
		mouse.dx = msg[1]+msg[3];
		mouse.dy = -(msg[2]+msg[4]);
		mouse.track = 1;
		mouseclock();
		nb = 0;
.
1129c
mouseclock(void)	/* called splhi */
.
1093d
1091d
1089d
1087d
915c
					break;
.
188a
	return nc;
.
142,144d
60a
	int	newbuttons;	/* interrupt time access only */
.
59d
52c
	 * First four fields are known in screen.c
.
## diffname ss/devbit.c 1991/0109
## diff -e /n/bootesdump/1990/1231/sys/src/9/sparc/devbit.c /n/bootesdump/1991/0109/sys/src/9/sparc/devbit.c
1162c
		mouse.newbuttons = b[(msg[0]&7)^7];
.
1154a
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7};
.
## diffname ss/devbit.c 1991/0201 # deleted
## diff -e /n/bootesdump/1991/0109/sys/src/9/sparc/devbit.c /n/bootesdump/1991/0201/sys/src/9/sparc/devbit.c
1,1176d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.