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

1992/1108/port/devbit.c (diff list | history)

port/devbit.c on 1990/0324
1990/0324    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1992/1030    
#include	<libg.h> 
#include	<gnot.h> 
1990/0324    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0324    
 
#include	"devtab.h" 
 
1991/0708    
#include	"screen.h" 
1990/0324    
 
1990/0327    
/* 
1991/0706    
 * Some monochrome screens are reversed from what we like: 
1992/0209    
 * We want 0's bright and 1's dark. 
1991/0706    
 * 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? */ 
 
/* 
1990/0329    
 * Device (#b/bitblt) is exclusive use on open, so no locks are necessary 
 * for i/o 
 */ 
 
/* 
1992/0622    
 * Arena is a word containing N, followed by a pointer to the Arena, 
 * followed by a pointer to the Bitmap, followed by N words. 
 * The bitmap pointer is zero if block is free. 
1992/0621    
 * bit.map is an array of pointers to GBitmaps.  The GBitmaps are 
 * freed individually and their corresponding entries in bit.map are zeroed. 
 * The index into bit.map is the Bitmap id as seen in libg.  Subfonts and 
 * fonts are handled similarly. 
1990/0327    
 */ 
1990/0324    
 
1992/0622    
typedef struct	Arena	Arena; 
struct Arena 
{ 
	ulong	*words;		/* storage */ 
	ulong	*wfree;		/* pointer to next free word */ 
	ulong	nwords;		/* total in arena */ 
	int	nbusy;		/* number of busy blocks */ 
}; 
 
1992/06271    
typedef struct	BSubfont BSubfont; 
struct BSubfont 
{ 
	GSubfont; 
	int	ref;		/* number of times this subfont is open */ 
	ulong	qid[2];		/* unique id used as a cache tag */ 
}; 
 
1992/0912    
extern GSubfont	*defont; 
       BSubfont	*bdefont; 
       BSubfont bdefont0; 
 
 
1990/05313    
struct 
{ 
1990/0324    
	Ref; 
1992/0622    
	QLock; 
1992/0621    
	GBitmap	**map;		/* indexed array */ 
	int	nmap;		/* number allocated */ 
	GFont	**font;		/* indexed array */ 
	int	nfont;		/* number allocated */ 
1992/06271    
	BSubfont**subfont;	/* indexed array */ 
1992/0621    
	int	nsubfont;	/* number allocated */ 
1992/0622    
	Arena	*arena;		/* array */ 
	int	narena;		/* number allocated */ 
1992/0720    
	int	mouseopen;	/* flag: mouse open */ 
1992/0913    
	int	bitbltopen;	/* flag: bitblt open */ 
1992/0630    
	int	bid;		/* last allocated bitmap id */ 
	int	subfid;		/* last allocated subfont id */ 
	int	cacheid;	/* last cached subfont id */ 
	int	fid;		/* 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; 
 
1992/0622    
#define	DMAP	16		/* delta increase in size of arrays */ 
1990/0327    
#define	FREE	0x80000000 
1992/0622    
 
1990/0327    
void	bitcompact(void); 
1992/0621    
int	bitalloc(Rectangle, int); 
1990/0902    
void	bitfree(GBitmap*); 
1992/0621    
void	fontfree(GFont*); 
1992/0702    
void	subfontfree(BSubfont*, int); 
1992/0622    
void	arenafree(Arena*); 
1992/0209    
void	bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode); 
void	bitloadchar(GFont*, int, GSubfont*, int); 
1990/0912    
extern	GBitmap	gscreen; 
1990/0327    
 
1991/0707    
Mouseinfo	mouse; 
Cursorinfo	cursor; 
1992/1020    
int		mouseshifted; 
1992/1021    
int		mousetype; 
1992/1106    
int		islittle; 
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, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{0, 0, 16, 16} 
}; 
 
ulong clrbits[16]; 
1990/0902    
GBitmap	clr = 
1990/0504    
{ 
	clrbits, 
	0, 
	1, 
	0, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{0, 0, 16, 16} 
}; 
 
1991/0706    
ulong cursorbackbits[16*4]; 
1990/0902    
GBitmap cursorback = 
1990/0504    
{ 
	cursorbackbits, 
	0, 
	1, 
	0, 
1992/0604    
	{0, 0, 16, 16}, 
1990/0504    
	{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, 
1992/1020    
	Qmousectl, 
1990/0709    
	Qscreen, 
1990/0324    
}; 
 
Dirtab bitdir[]={ 
1991/1112    
	"bitblt",	{Qbitblt},	0,			0666, 
	"mouse",	{Qmouse},	0,			0666, 
1992/1020    
	"mousectl",	{Qmousectl},	0,			0220, 
1991/1112    
	"screen",	{Qscreen},	0,			0444, 
1990/0324    
}; 
 
#define	NBIT	(sizeof bitdir/sizeof(Dirtab)) 
1992/06271    
#define	NINFO	8192	/* max chars per subfont; sanity check only */ 
1992/0622    
#define	HDR	3 
1990/0324    
 
void 
1992/1104    
lockedupdate(void) 
{ 
	qlock(&bit); 
	if(waserror()){ 
		qunlock(&bit); 
		return; 
	} 
	screenupdate(); 
	qunlock(&bit); 
	poperror(); 
} 
 
void 
1992/0706    
bitfreeup(void) 
{ 
	int i; 
	BSubfont *s; 
 
	/* free unused subfonts and compact */ 
	for(i=0; i<bit.nsubfont; i++){ 
		s = bit.subfont[i]; 
1992/0912    
		if(s && s!=bdefont && s->ref==0){ 
1992/0706    
			s->ref = 1; 
			s->qid[0] = ~0;	/* force cleanup */ 
			subfontfree(s, i); 
		} 
	} 
	bitcompact(); 
} 
 
void* 
bitmalloc(ulong n) 
{ 
	void *p; 
 
	p = malloc(n); 
	if(p) 
		return p; 
	bitfreeup(); 
	return malloc(n); 
} 
 
void 
1992/0704    
bitdebug(void) 
{ 
	int i; 
	long l; 
	Arena *a; 
 
	l = 0; 
	for(i=0; i<bit.narena; i++){ 
		a = &bit.arena[i]; 
		if(a->words){ 
			l += a->nwords; 
1992/0820    
			print("%d: %ld bytes used; %ld total\n", i, 
1992/0704    
				(a->wfree-a->words)*sizeof(ulong), 
				a->nwords*sizeof(ulong)); 
		} 
	} 
1992/0820    
	print("arena: %ld bytes\n", l*sizeof(ulong)); 
1992/0704    
	l = 0; 
	for(i=0; i<bit.nmap; i++) 
		if(bit.map[i]) 
			l++; 
	print("%d bitmaps ", l); 
	l = 0; 
	for(i=0; i<bit.nfont; i++) 
		if(bit.font[i]) 
			l++; 
	print("%d fonts ", l); 
	l = 0; 
	for(i=0; i<bit.nsubfont; i++) 
		if(bit.subfont[i]){ 
			print("%d: %lux %lux ", i, bit.subfont[i]->qid[0], bit.subfont[i]->qid[1]); 
			l++; 
		} 
	print("%d subfonts\n", l); 
} 
 
void 
1990/0324    
bitreset(void) 
{ 
1992/0711    
	int ws; 
1991/0706    
	ulong r; 
1992/0622    
	Arena *a; 
1990/0327    
 
1992/0807    
	if(!conf.monitor) 
		return; 
1992/0914    
	memmove(&bdefont0, defont, sizeof(*defont)); 
	bdefont = &bdefont0; 
1992/0621    
	bit.map = smalloc(DMAP*sizeof(GBitmap*)); 
	bit.nmap = DMAP; 
1991/0706    
	getcolor(0, &r, &r, &r); 
	if(r == 0) 
		flipping = 1; 
1992/0630    
	bit.bid = -1; 
	bit.subfid = -1; 
	bit.fid = -1; 
	bit.cacheid = -1; 
1992/0621    
	bit.font = smalloc(DMAP*sizeof(GFont*)); 
	bit.nfont = DMAP; 
1992/06271    
	bit.subfont = smalloc(DMAP*sizeof(BSubfont*)); 
1992/0621    
	bit.nsubfont = DMAP; 
1992/0622    
	bit.arena = smalloc(DMAP*sizeof(Arena)); 
	bit.narena = DMAP; 
	a = &bit.arena[0]; 
	/* 
	 * Somewhat of a heuristic: start with three screensful and 
	 * allocate single screensful dynamically if needed. 
	 */ 
1992/0706    
	ws = BI2WD>>gscreen.ldepth;	/* pixels per word */ 
	a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws); 
1992/0622    
	a->words = xalloc(a->nwords*sizeof(ulong)); 
1992/0706    
	if(a->words == 0){ 
		/* try again */ 
		print("bitreset: allocating only 1 screenful\n"); 
		a->nwords /= 3; 
		a->words = a->words = xalloc(a->nwords*sizeof(ulong)); 
		if(a->words == 0) 
			panic("bitreset"); 
	} 
1992/0622    
	a->wfree = a->words; 
	a->nbusy = 1;	/* keep 0th arena from being freed */ 
1990/05313    
	Cursortocursor(&arrow); 
1990/0324    
} 
 
void 
bitinit(void) 
{ 
1992/0807    
	if(!conf.monitor) 
		return; 
1991/0706    
	if(gscreen.ldepth > 3) 
		cursorback.ldepth = 0; 
1992/0621    
	else{ 
1991/0706    
		cursorback.ldepth = gscreen.ldepth; 
		cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5; 
	} 
1990/0504    
	cursoron(1); 
1990/0324    
} 
 
Chan* 
bitattach(char *spec) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/0324    
	return devattach('b', spec); 
} 
 
Chan* 
bitclone(Chan *c, Chan *nc) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/0324    
	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) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/0324    
	return devwalk(c, name, bitdir, NBIT, devgen); 
} 
 
void 
bitstat(Chan *c, char *db) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/0324    
	devstat(c, db, bitdir, NBIT, devgen); 
} 
 
1992/0621    
Chan* 
1990/0324    
bitopen(Chan *c, int omode) 
{ 
1992/0621    
	GBitmap *b; 
 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1992/0720    
	switch(c->qid.path){ 
	case CHDIR: 
1990/0324    
		if(omode != OREAD) 
1990/11211    
			error(Eperm); 
1992/0720    
		break; 
	case Qmouse: 
1990/0324    
		lock(&bit); 
1992/0720    
		if(bit.mouseopen){ 
			unlock(&bit); 
			error(Einuse); 
		} 
		bit.mouseopen = 1; 
		bit.ref++; 
		unlock(&bit); 
		break; 
	case Qbitblt: 
		lock(&bit); 
1992/0913    
		if(bit.bitbltopen || bit.mouseopen){ 
1990/0324    
			unlock(&bit); 
1990/11211    
			error(Einuse); 
1990/0324    
		} 
1992/0621    
		b = smalloc(sizeof(GBitmap)); 
		*b = gscreen; 
		bit.map[0] = b;			/* bitmap 0 is screen */ 
1992/0912    
		bit.subfont[0] = bdefont;	/* subfont 0 is default */ 
1992/06271    
		bit.subfont[0]->ref = 1; 
		bit.subfont[0]->qid[0] = 0; 
		bit.subfont[0]->qid[1] = 0; 
1992/0630    
		bit.bid = -1; 
		bit.fid = -1; 
		bit.subfid = -1; 
		bit.cacheid = -1; 
1990/0613    
		bit.rid = -1; 
1991/0706    
		bit.mid = -1; 
1990/0604    
		bit.init = 0; 
1992/0913    
		bit.bitbltopen = 1; 
1990/05313    
		Cursortocursor(&arrow); 
1990/0324    
		unlock(&bit); 
1992/0720    
		break; 
	default: 
1990/0324    
		incref(&bit); 
1992/0720    
	} 
1990/0324    
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
void 
bitcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1991/1115    
	USED(c, name, omode, perm); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitremove(Chan *c) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1991/1115    
	USED(c); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitwstat(Chan *c, char *db) 
{ 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1991/1115    
	USED(c, db); 
1990/11211    
	error(Eperm); 
1990/0324    
} 
 
void 
bitclose(Chan *c) 
{ 
1992/0621    
	GBitmap *b, **bp, **ebp; 
1992/06271    
	BSubfont *s, **sp, **esp; 
1992/0621    
	GFont *f, **fp, **efp; 
1990/0327    
 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/11211    
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){ 
1990/0329    
		lock(&bit); 
1992/0720    
		if(c->qid.path == Qmouse) 
			bit.mouseopen = 0; 
1992/0913    
		if(c->qid.path == Qbitblt) 
			bit.bitbltopen = 0; 
1990/0327    
		if(--bit.ref == 0){ 
1992/0621    
			ebp = &bit.map[bit.nmap]; 
1992/0630    
			for(bp = bit.map; bp<ebp; bp++){ 
1992/0621    
				b = *bp; 
				if(b){ 
					bitfree(b); 
					*bp = 0; 
				} 
1992/0209    
			} 
1992/0621    
			esp = &bit.subfont[bit.nsubfont]; 
1992/0630    
			for(sp=bit.subfont; sp<esp; sp++){ 
1992/0621    
				s = *sp; 
1992/0628    
				if(s) 
1992/0702    
					subfontfree(s, sp-bit.subfont); 
1992/0630    
				/* don't clear *sp: cached */ 
1992/0621    
			} 
			efp = &bit.font[bit.nfont]; 
			for(fp=bit.font; fp<efp; fp++){ 
				f = *fp; 
				if(f){ 
					fontfree(f); 
					*fp = 0; 
				} 
			} 
1990/0327    
		} 
1990/0324    
		unlock(&bit); 
	} 
} 
 
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; 
1992/0816    
	ulong l, nw, ws, rv, gv, bv; 
1992/0627    
	int off, j; 
1990/06231    
	Fontchar *i; 
1990/0902    
	GBitmap *src; 
1992/0628    
	BSubfont *s; 
1990/0327    
 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1990/11211    
	if(c->qid.path & CHDIR) 
1990/0324    
		return devdirread(c, va, n, bitdir, NBIT, devgen); 
 
1992/0622    
	if(c->qid.path == Qmouse){ 
1990/0329    
		/* 
1990/0505    
		 * mouse: 
		 *	'm'		1 
		 *	buttons		1 
		 * 	point		8 
1992/06271    
		 * 	msec		4 
1990/0329    
		 */ 
1992/06271    
		if(n < 14) 
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; 
1992/0630    
		BPLONG(p+2, mouse.xy.x); 
		BPLONG(p+6, mouse.xy.y); 
		BPLONG(p+10, TK2MS(MACHP(0)->ticks)); 
1990/0505    
		mouse.changed = 0; 
		unlock(&cursor); 
1992/06271    
		return 14; 
1992/0622    
	} 
	if(c->qid.path == 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); 
1992/0622    
			return 5*12; 
1990/0709    
		} 
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; 
1991/1023    
		miny = t/l;	/* unsigned computation */ 
1990/0709    
		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)); 
1992/0816    
			memmove(p, q, l); 
			if(flipping) 
				/* is screen, so must be word aligned */ 
				for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong)) 
					*(ulong*)p ^= ~0; 
			else 
				p += l; 
1990/0709    
			n += l; 
		} 
1992/0622    
		return n; 
	} 
	if(c->qid.path != Qbitblt) 
1990/11211    
		error(Egreg); 
1992/0622    
 
	qlock(&bit); 
	if(waserror()){ 
		qunlock(&bit); 
		nexterror(); 
1990/0327    
	} 
1992/0622    
	p = va; 
	/* 
	 * Fuss about and figure out what to say. 
	 */ 
	if(bit.init){ 
		/* 
		 * init: 
		 *	'I'		1 
		 *	ldepth		1 
		 * 	rectangle	16 
1992/0627    
		 * 	clip rectangle	16 
1992/0622    
		 *	font info	3*12 
1992/0912    
		 *	fontchars	6*(bdefont->n+1) 
1992/0622    
		 */ 
1992/0627    
		if(n < 34) 
1992/0622    
			error(Ebadblt); 
		p[0] = 'I'; 
		p[1] = gscreen.ldepth; 
1992/0630    
		BPLONG(p+2, gscreen.r.min.x); 
		BPLONG(p+6, gscreen.r.min.y); 
		BPLONG(p+10, gscreen.r.max.x); 
		BPLONG(p+14, gscreen.r.max.y); 
		BPLONG(p+18, gscreen.clipr.min.x); 
		BPLONG(p+22, gscreen.clipr.min.y); 
		BPLONG(p+26, gscreen.clipr.max.x); 
		BPLONG(p+30, gscreen.clipr.max.y); 
1992/0912    
		if(n >= 34+3*12+6*(bdefont->n+1)){ 
1992/0627    
			p += 34; 
1992/0912    
			sprint((char*)p, "%11d %11d %11d ", bdefont->n, 
				bdefont->height, bdefont->ascent); 
1992/0622    
			p += 3*12; 
1992/0912    
			for(i=bdefont->info,j=0; j<=bdefont->n; j++,i++,p+=6){ 
1992/0630    
				BPSHORT(p, i->x); 
1992/0622    
				p[2] = i->top; 
				p[3] = i->bottom; 
				p[4] = i->left; 
				p[5] = i->width; 
			} 
1992/0912    
			n = 34+3*12+6*(bdefont->n+1); 
1992/0622    
		}else 
1992/0627    
			n = 34; 
1992/0622    
		bit.init = 0; 
1992/0630    
	}else if(bit.bid > 0){ 
1992/0622    
		/* 
		 * allocate: 
		 *	'A'		1 
		 *	bitmap id	2 
		 */ 
		if(n < 3) 
			error(Ebadblt); 
1992/0630    
		if(bit.bid<0 || bit.map[bit.bid]==0) 
			error(Ebadbitmap); 
1992/0622    
		p[0] = 'A'; 
1992/0630    
		BPSHORT(p+1, bit.bid); 
		bit.bid = -1; 
1992/0622    
		n = 3; 
1992/0630    
	}else if(bit.subfid > 0){ 
1992/0622    
		/* 
		 * allocate subfont: 
		 *	'K'		1 
		 *	subfont id	2 
		 */ 
1992/0630    
		if(n<3 || bit.subfid<0) 
1992/0622    
			error(Ebadblt); 
1992/0630    
		s = bit.subfont[bit.subfid]; 
		if(s==0 || s->ref==0) 
			error(Ebadfont); 
1992/0622    
		p[0] = 'K'; 
1992/0630    
		BPSHORT(p+1, bit.subfid); 
		bit.subfid = -1; 
1992/0622    
		n = 3; 
1992/0630    
	}else if(bit.cacheid >= 0){ 
1992/0628    
		/* 
1992/0811    
		 * check cache for subfont: 
1992/0628    
		 *	'J'		1 
		 *	subfont id	2 
		 *	font info	3*12 
		 *	fontchars	6*(subfont->n+1) 
		 */ 
		p[0] = 'J'; 
1992/0702    
		if(bit.cacheid < 0) 
1992/0630    
			error(Ebadfont); 
		s = bit.subfont[bit.cacheid]; 
		if(s==0 || s->ref==0) 
			error(Ebadfont); 
		if(n < 3+3*12+6*(s->n+1)) 
1992/0628    
			error(Ebadblt); 
1992/0630    
		BPSHORT(p+1, bit.cacheid); 
1992/0628    
		p += 3; 
1992/0630    
		sprint((char*)p, "%11d %11d %11d ", s->n, s->height, s->ascent); 
1992/0628    
		p += 3*12; 
		for(i=s->info,j=0; j<=s->n; j++,i++,p+=6){ 
1992/0630    
			BPSHORT(p, i->x); 
1992/0628    
			p[2] = i->top; 
			p[3] = i->bottom; 
			p[4] = i->left; 
			p[5] = i->width; 
		} 
		n = 3+3*12+6*(s->n+1); 
1992/0630    
		bit.cacheid = -1; 
	}else if(bit.fid >= 0){ 
1992/0622    
		/* 
		 * allocate font: 
		 *	'N'		1 
		 *	font id		2 
		 */ 
		if(n < 3) 
			error(Ebadblt); 
1992/0630    
		if(bit.fid<0 || bit.font[bit.fid]==0) 
			error(Ebadfont); 
1992/0622    
		p[0] = 'N'; 
1992/0630    
		BPSHORT(p+1, bit.fid); 
		bit.fid = -1; 
1992/0622    
		n = 3; 
	}else if(bit.mid >= 0){ 
		/* 
		 * read colormap: 
		 *	data		12*(2**bitmapdepth) 
		 */ 
		src = bit.map[bit.mid]; 
		if(src == 0) 
			error(Ebadbitmap); 
		l = (1<<src->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; 
			} 
1992/0630    
			BPLONG(p, rv); 
			BPLONG(p+4, gv); 
			BPLONG(p+8, bv); 
1992/0622    
			p += 12; 
		} 
		bit.mid = -1; 
		n = 12*nw; 
	}else if(bit.rid >= 0){ 
		/* 
		 * read bitmap: 
		 *	data		bytewidth*(maxy-miny) 
		 */ 
		src = bit.map[bit.rid]; 
		if(src == 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; 
1992/0816    
			memmove(p, q, l); 
1992/1106    
			if(islittle) 
				bitreverse(p, l); 
1992/0816    
			if(bit.rid==0 && flipping) 
				/* is screen, so must be word aligned */ 
				for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong)) 
					*(ulong*)p ^= ~0; 
1992/0622    
			else 
1992/0816    
				p += l; 
1992/0622    
			n += l; 
		} 
		if(off) 
			cursoron(1); 
		bit.rid = -1; 
	} 
1990/0327    
 
1992/0622    
	poperror(); 
	qunlock(&bit); 
1990/0327    
	return n; 
1990/0324    
} 
 
1992/1013    
Point 
bitstrsize(GFont *f, uchar *p, int l) 
{ 
	ushort r; 
	Point s = {0,0}; 
	GCacheinfo *c; 
 
	while(l > 0){ 
		r = BGSHORT(p); 
		p += 2; 
		l -= 2; 
		if(r >= f->ncache) 
			continue; 
		c = &f->cache[r]; 
		if(c->bottom > s.y) 
			s.y = c->bottom; 
		s.x += c->width; 
	} 
	return s; 
} 
 
1990/0324    
long 
1991/0411    
bitwrite(Chan *c, void *va, long n, ulong offset) 
1990/0324    
{ 
1992/0816    
	uchar *p, *q, *oq; 
1992/0711    
	long m, v, miny, maxy, t, x, y; 
1992/0628    
	ulong l, nw, ws, rv, q0, q1; 
1992/0816    
	ulong *lp; 
1992/0621    
	int off, isoff, i, j, ok; 
1992/1107    
 	ulong *endscreen = gaddr(&gscreen, Pt(0, gscreen.r.max.y)); 
1990/06111    
	Point pt, pt1, pt2; 
1990/0324    
	Rectangle rect; 
1990/05313    
	Cursor curs; 
1991/0706    
	Fcode fc; 
1990/0623    
	Fontchar *fcp; 
1992/0711    
	GBitmap *src, *dst; 
1992/0702    
	BSubfont *f, *tf, **fp; 
1992/0621    
	GFont *ff, **ffp; 
1992/0706    
	GCacheinfo *gc; 
1992/1020    
	char buf[64]; 
1990/0324    
 
1992/0807    
	if(!conf.monitor) 
		error(Egreg); 
1992/0711    
	USED(offset); 
 
1990/11211    
	if(c->qid.path == CHDIR) 
		error(Eisdir); 
1990/0324    
 
1992/1020    
	if(c->qid.path == Qmousectl){ 
		if(n >= sizeof(buf)) 
			n = sizeof(buf)-1; 
		strncpy(buf, va, n); 
		buf[n] = 0; 
		mousectl(buf); 
		return n; 
	} 
 
1990/11211    
	if(c->qid.path != Qbitblt) 
		error(Egreg); 
1990/0327    
 
1990/0721    
	isoff = 0; 
1992/0622    
	qlock(&bit); 
1990/0721    
	if(waserror()){ 
1992/0622    
		qunlock(&bit); 
1990/0721    
		if(isoff) 
			cursoron(1); 
		nexterror(); 
	} 
1990/0324    
	p = va; 
	m = n; 
1992/0621    
	SET(src, dst, f, ff); 
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); 
1992/0209    
			if(v > 3)	/* BUG */ 
1990/11211    
				error(Ebadblt); 
1992/0630    
			rect.min.x = BGLONG(p+2); 
			rect.min.y = BGLONG(p+6); 
			rect.max.x = BGLONG(p+10); 
			rect.max.y = BGLONG(p+14); 
1991/0423    
			if(Dx(rect) < 0 || Dy(rect) < 0) 
				error(Ebadblt); 
1992/0630    
			bit.bid = bitalloc(rect, v); 
1990/0327    
			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); 
1992/0630    
			fc = BGSHORT(p+29) & 0xF; 
			v = BGSHORT(p+11); 
1992/0621    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
1991/0706    
				error(Ebadbitmap); 
			off = 0; 
			if(v == 0){ 
				if(flipping) 
					fc = flipS[fc]; 
				off = 1; 
			} 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0504    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt.x = BGLONG(p+3); 
			pt.y = BGLONG(p+7); 
			rect.min.x = BGLONG(p+13); 
			rect.min.y = BGLONG(p+17); 
			rect.max.x = BGLONG(p+21); 
			rect.max.y = BGLONG(p+25); 
1990/0721    
			if(off && !isoff){ 
1990/0504    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/1225    
			gbitblt(dst, pt, src, rect, fc); 
1992/1104    
			if(dst->base < endscreen) 
1992/1013    
				mbbrect(Rpt(pt, add(pt, sub(rect.max, rect.min)))); 
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; 
			} 
1992/1107    
			if(m == 2){ 
				if(p[1]){	/* make damn sure */ 
					cursor.disable = 0; 
					isoff = 1; 
				}else{ 
					cursoroff(1); 
					cursor.disable = 1; 
				} 
				m -= 2; 
				p += 2; 
				break; 
			} 
1990/05313    
			if(m < 73) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			curs.offset.x = BGLONG(p+1); 
			curs.offset.y = BGLONG(p+5); 
1991/0318    
			memmove(curs.clr, p+9, 2*16); 
			memmove(curs.set, p+41, 2*16); 
1992/1106    
			if(islittle){ 
				bitreverse(curs.clr, 2*16); 
				bitreverse(curs.set, 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); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0327    
			bitfree(dst); 
1992/0621    
			bit.map[v] = 0; 
1990/0327    
			m -= 3; 
			p += 3; 
1990/0604    
			break; 
 
1990/0623    
		case 'g': 
			/* 
1992/0628    
			 * free subfont 
1990/0623    
			 *	'g'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0628    
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0) 
1990/11211    
				error(Ebadfont); 
1992/0702    
			subfontfree(f, v); 
1990/0623    
			m -= 3; 
			p += 3; 
			break; 
 
1992/0209    
		case 'h': 
			/* 
			 * free font 
			 *	'h'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadfont); 
1992/0621    
			fontfree(ff); 
			bit.font[v] = 0; 
1992/0209    
			m -= 3; 
			p += 3; 
			break; 
 
1990/0604    
		case 'i': 
			/* 
			 * init 
			 * 
1992/0627    
			 *	'i'		1 
1990/0604    
			 */ 
1992/0627    
			bit.init = 1; 
1990/0604    
			m -= 1; 
			p += 1; 
1990/0327    
			break; 
1990/0329    
 
1992/06271    
		case 'j': 
			/* 
1992/0628    
			 * subfont cache check 
1992/06271    
			 * 
			 *	'j'		1 
1992/0702    
			 *	qid		8 
1992/06271    
			 */ 
1992/0628    
			if(m < 9) 
				error(Ebadblt); 
1992/0630    
			q0 = BGLONG(p+1); 
			q1 = BGLONG(p+5); 
1992/0629    
			i = 0; 
			if(q0 != ~0) 
				for(; i<bit.nsubfont; i++){ 
					f = bit.subfont[i]; 
					if(f && f->qid[0]==q0 && f->qid[1]==q1) 
						goto sfcachefound; 
				} 
1992/0628    
			error(Esfnotcached); 
 
		sfcachefound: 
			f->ref++; 
1992/0630    
			bit.cacheid = i; 
1992/06271    
			m -= 9; 
			p += 9; 
			break; 
 
1990/0623    
		case 'k': 
			/* 
1992/0209    
			 * allocate subfont 
1990/0623    
			 *	'k'		1 
			 *	n		2 
			 *	height		1 
			 *	ascent		1 
			 *	bitmap id	2 
1992/06271    
			 *	qid		8 
1990/0707    
			 *	fontchars	6*(n+1) 
1990/0623    
			 * next read returns allocated font id 
			 */ 
1992/06271    
			if(m < 15) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/06271    
			if(v<0 || v>NINFO || m<15+6*(v+1)) 
1990/11211    
				error(Ebadblt); 
1992/0621    
			for(i=1; i<bit.nsubfont; i++) 
				if(bit.subfont[i] == 0) 
1992/0209    
					goto subfontfound; 
1992/0706    
			fp = bitmalloc((bit.nsubfont+DMAP)*sizeof(BSubfont*)); 
			if(fp == 0) 
				error(Enomem); 
			memmove(fp, bit.subfont, bit.nsubfont*sizeof(BSubfont*)); 
			free(bit.subfont); 
			bit.subfont = fp; 
1992/0621    
			bit.nsubfont += DMAP; 
1992/0209    
		subfontfound: 
1992/0706    
			f = bitmalloc(sizeof(BSubfont)); 
			if(f == 0) 
				error(Enomem); 
			f->info = bitmalloc((v+1)*sizeof(Fontchar)); 
			if(f->info == 0){ 
				free(f); 
				error(Enomem); 
			} 
1992/1026    
			bit.subfont[i] = f; 
1990/0623    
			f->n = v; 
			f->height = p[3]; 
			f->ascent = p[4]; 
1992/0630    
			f->qid[0] = BGLONG(p+7); 
			f->qid[1] = BGLONG(p+11); 
1992/0702    
			/* check to see if already there, uncache if so */ 
			for(j=0; j<bit.nsubfont; j++){ 
				if(j == i) 
					continue; 
				tf = bit.subfont[j]; 
1992/0704    
				if(tf && tf->qid[0]==f->qid[0] && tf->qid[1]==f->qid[1]){ 
1992/0702    
					f->qid[0] = ~0;	/* uncached */ 
1992/0704    
					break; 
				} 
1992/0702    
			} 
1992/0628    
			f->ref = 1; 
1992/0630    
			v = BGSHORT(p+5); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1992/06271    
			f->bits = dst; 
			bit.map[v] = 0;	/* subfont now owns bitmap */ 
			m -= 15; 
			p += 15; 
1990/0623    
			fcp = f->info; 
1992/0621    
			for(j=0; j<=f->n; j++,fcp++){ 
1992/0630    
				fcp->x = BGSHORT(p); 
1990/0623    
				fcp->top = p[2]; 
				fcp->bottom = p[3]; 
				fcp->left = p[4]; 
				fcp->width = p[5]; 
				fcp->top = p[2]; 
				p += 6; 
				m -= 6; 
			} 
1992/0630    
			bit.subfid = i; 
1990/0623    
			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); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/06111    
			off = 0; 
1992/0630    
			fc = BGSHORT(p+20) & 0xF; 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/06111    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt1.x = BGLONG(p+3); 
			pt1.y = BGLONG(p+7); 
			pt2.x = BGLONG(p+11); 
			pt2.y = BGLONG(p+15); 
1990/06111    
			t = p[19]; 
1990/0721    
			if(off && !isoff){ 
1990/06111    
				cursoroff(1); 
1990/0721    
				isoff = 1; 
			} 
1991/0706    
			gsegment(dst, pt1, pt2, t, fc); 
1992/1107    
			if(dst->base < endscreen){ 
1992/1013    
				mbbpt(pt1); 
				mbbpt(pt2); 
			} 
1990/06111    
			m -= 22; 
			p += 22; 
1990/0613    
			break; 
 
1991/0706    
		case 'm': 
			/* 
			 * read colormap 
			 * 
			 *	'm'		1 
			 *	id		2 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1991/0706    
				error(Ebadbitmap); 
			bit.mid = v; 
			m -= 3; 
			p += 3; 
			break; 
 
1992/0209    
		case 'n': 
			/* 
			 * allocate font 
			 *	'n'		1 
			 *	height		1 
			 *	ascent		1 
			 *	ldepth		2 
1992/0627    
			 *	ncache		2 
1992/0209    
			 * next read returns allocated font id 
			 */ 
1992/0627    
			if(m < 7) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+3); 
			t = BGSHORT(p+5); 
1992/0627    
			if(v<0 || t<0) 
1992/0209    
				error(Ebadblt); 
1992/0621    
			for(i=0; i<bit.nfont; i++) 
				if(bit.font[i] == 0) 
1992/0209    
					goto fontfound; 
1992/0706    
			ffp = bitmalloc((bit.nfont+DMAP)*sizeof(GFont*)); 
			if(ffp == 0) 
				error(Enomem); 
			memmove(ffp, bit.font, bit.nfont*sizeof(GFont*)); 
			free(bit.font); 
			bit.font = ffp; 
1992/0621    
			bit.nfont += DMAP; 
1992/0209    
		fontfound: 
1992/0706    
			ff = bitmalloc(sizeof(GFont)); 
			if(ff == 0) 
				error(Enomem); 
1992/0627    
			ff->ncache = t; 
1992/0706    
			ff->cache = bitmalloc(t*sizeof(GCacheinfo)); 
			if(ff->cache == 0){ 
				free(ff); 
				error(Enomem); 
			} 
1992/0621    
			bit.font[i] = ff; 
			ff = bit.font[i]; 
1992/0209    
			ff->height = p[1]; 
			ff->ascent = p[2]; 
			ff->ldepth = v; 
			ff->width = 0; 
			ff->b = 0; 
1992/0627    
			m -= 7; 
			p += 7; 
1992/0630    
			bit.fid = i; 
1992/0209    
			break; 
 
1990/0722    
		case 'p': 
			/* 
			 * point 
			 * 
			 *	'p'		1 
			 *	id		2 
			 *	pt		8 
			 *	value		1 
			 *	code		2 
			 */ 
			if(m < 14) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0722    
			off = 0; 
1992/0630    
			fc = BGSHORT(p+12) & 0xF; 
1991/0706    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
1990/0722    
				off = 1; 
1991/0706    
			} 
1992/0630    
			pt1.x = BGLONG(p+3); 
			pt1.y = BGLONG(p+7); 
1990/0722    
			t = p[11]; 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
1991/0706    
			gpoint(dst, pt1, t, fc); 
1992/1104    
			if(dst->base < endscreen) 
1992/1013    
				mbbpt(pt1); 
1990/0722    
			m -= 14; 
			p += 14; 
			break; 
 
1992/0604    
		case 'q': 
			/* 
			 * clip rectangle 
			 *	'q'		1 
			 *	id		2 
			 *	rect		16 
			 */ 
			if(m < 19) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1992/0604    
				error(Ebadbitmap); 
1992/0630    
			rect.min.x = BGLONG(p+3); 
			rect.min.y = BGLONG(p+7); 
			rect.max.x = BGLONG(p+11); 
			rect.max.y = BGLONG(p+15); 
1992/0604    
			if(rectclip(&rect, dst->r)) 
				dst->clipr = rect; 
			else 
				dst->clipr = dst->r; 
			m -= 19; 
			p += 19; 
			break; 
 
1990/0613    
		case 'r': 
			/* 
			 * read 
			 *	'r'		1 
			 *	src id		2 
			 *	miny		4 
			 *	maxy		4 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1992/0630    
			miny = BGLONG(p+3); 
			maxy = BGLONG(p+7); 
1990/0613    
			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; 
 
1992/0627    
		case 's': 
1990/0329    
			/* 
1992/0209    
			 * string 
1992/0627    
			 *	's'		1 
1992/0209    
			 *	id		2 
			 *	pt		8 
			 *	font id		2 
			 *	code		2 
			 *	n		2 
1992/0627    
			 * 	cache indices	2*n (not null terminated) 
1992/0209    
			 */ 
			if(m < 17) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1992/0209    
				error(Ebadbitmap); 
			off = 0; 
1992/0630    
			fc = BGSHORT(p+13) & 0xF; 
1992/0209    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
				off = 1; 
			} 
1992/0630    
			pt.x = BGLONG(p+3); 
			pt.y = BGLONG(p+7); 
			v = BGSHORT(p+11); 
1992/0621    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0912    
				error(Ebadfont); 
1992/0630    
			l = BGSHORT(p+15)*2; 
1992/0209    
			p += 17; 
			m -= 17; 
			if(l > m) 
				error(Ebadblt); 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
			bitstring(dst, pt, ff, p, l, fc); 
1992/1104    
			if(dst->base < endscreen) 
1992/1013    
				mbbrect(Rpt(pt, add(pt, bitstrsize(ff, p, l)))); 
1992/0209    
			m -= l; 
			p += l; 
			break; 
 
1992/0627    
		case 't': 
			/* 
			 * texture 
			 *	't'		1 
			 *	dst id		2 
			 *	rect		16 
			 *	src id		2 
			 *	fcode		2 
			 */ 
			if(m < 23) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0627    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
				error(Ebadbitmap); 
			off = 0; 
1992/0630    
			fc = BGSHORT(p+21) & 0xF; 
1992/0627    
			if(v == 0){ 
				if(flipping) 
					fc = flipD[fc]; 
				off = 1; 
			} 
1992/0630    
			rect.min.x = BGLONG(p+3); 
			rect.min.y = BGLONG(p+7); 
			rect.max.x = BGLONG(p+11); 
			rect.max.y = BGLONG(p+15); 
			v = BGSHORT(p+19); 
1992/0627    
			if(v<0 || v>=bit.nmap || (src=bit.map[v])==0) 
				error(Ebadbitmap); 
			if(off && !isoff){ 
				cursoroff(1); 
				isoff = 1; 
			} 
			gtexture(dst, rect, src, fc); 
1992/1104    
			if(dst->base < endscreen) 
1992/1013    
				mbbrect(rect); 
1992/0627    
			m -= 23; 
			p += 23; 
			break; 
 
1992/0209    
		case 'v': 
			/* 
1992/0704    
			 * clear font cache and bitmap. 
			 * if error, font is unchanged. 
1992/0209    
			 *	'v'		1 
			 *	id		2 
1992/06271    
			 *	ncache		2 
1992/0209    
			 *	width		2 
			 */ 
1992/06271    
			if(m < 7) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
			t = BGSHORT(p+3); 
1992/06271    
			if(t<0 || v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadblt); 
1992/0704    
			x = BGSHORT(p+5); 
			i = bitalloc(Rect(0, 0, t*x, ff->height), ff->ldepth); 
1992/0706    
			if(t != ff->ncache){ 
				gc = bitmalloc(t*sizeof(ff->cache[0])); 
				if(gc == 0){ 
					bitfree(bit.map[i]); 
					bit.map[i] = 0; 
					error(Enomem); 
				} 
				free(ff->cache); 
				ff->cache = gc; 
				ff->ncache = t; 
			}else{ 
				/* 
				 * memset not necessary but helps avoid 
				 * confusion if the cache is mishandled by the 
				 * user. 
				 */ 
				memset(ff->cache, 0, t*sizeof(ff->cache[0])); 
			} 
1992/0704    
			if(ff->b) 
				bitfree(ff->b); 
			ff->b = bit.map[i]; 
			bit.map[i] = 0;	/* disconnect it from GBitmap space */ 
			ff->width = x; 
1992/06271    
			p += 7; 
			m -= 7; 
1992/0209    
			break; 
 
1990/0329    
		case 'w': 
			/* 
			 * write 
			 *	'w'		1 
			 *	dst id		2 
			 *	miny		4 
			 *	maxy		4 
			 *	data		bytewidth*(maxy-miny) 
			 */ 
			if(m < 11) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0621    
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0) 
1990/11211    
				error(Ebadbitmap); 
1990/0504    
			off = 0; 
			if(v == 0) 
				off = 1; 
1992/0630    
			miny = BGLONG(p+3); 
			maxy = BGLONG(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; 
			} 
1992/1104    
			if(dst->base < endscreen) 
1992/1013    
				mbbrect(Rect(dst->r.min.x, miny, dst->r.max.x, maxy)); 
1990/0329    
			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++){ 
1992/0816    
				oq = (uchar*)gaddr(dst, Pt(dst->r.min.x, y)); 
				q = oq + (dst->r.min.x&((sizeof(ulong))*ws-1))/ws; 
				memmove(q, p, l); 
1992/1106    
				if(islittle) 
					bitreverse(q, l); 
1992/0816    
				if(v==0 && flipping){	/* flip bits */ 
					/* we know it's all word aligned */ 
					lp = (ulong*)oq; 
					for(x=0; x<l; x+=sizeof(ulong)) 
						*lp++ ^= ~0; 
				} 
				p += l; 
1990/0329    
				m -= l; 
			} 
1992/1010    
			if(v == 0) 
				hwscreenwrite(miny, maxy); 
1990/0329    
			break; 
1990/0826    
 
		case 'x': 
			/* 
			 * cursorset 
			 * 
			 *	'x'		1 
			 *	pt		8 
			 */ 
			if(m < 9) 
1990/11211    
				error(Ebadblt); 
1992/0630    
			pt1.x = BGLONG(p+1); 
			pt1.y = BGLONG(p+5); 
1992/0816    
			if(ptinrect(pt1, gscreen.r)){ 
1991/0619    
				mouse.xy = pt1; 
				mouse.track = 1; 
				mouseclock(); 
			} 
1990/0826    
			m -= 9; 
			p += 9; 
			break; 
1991/0706    
 
1992/0209    
		case 'y': 
			/* 
			 * load font from subfont 
			 *	'y'		1 
			 *	id		2 
1992/0212    
			 *	cache index	2 
1992/0209    
			 *	subfont id	2 
			 *	subfont index	2 
			 */ 
			if(m < 9) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1992/0622    
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0) 
1992/0209    
				error(Ebadblt); 
1992/0729    
			if(ff->b == 0) 
				error(Ebadbitmap); 
1992/0630    
			l = BGSHORT(p+3); 
			if(l >= ff->ncache) 
1992/0209    
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+5); 
1992/0628    
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0) 
				error(Ebadfont); 
1992/0630    
			nw = BGSHORT(p+7); 
1992/0209    
			if(nw >= f->n) 
				error(Ebadblt); 
			bitloadchar(ff, l, f, nw); 
			p += 9; 
			m -= 9; 
			break; 
 
1991/0706    
		case 'z': 
			/* 
			 * write the colormap 
			 * 
			 *	'z'		1 
			 *	id		2 
			 *	map		12*(2**bitmapdepth) 
			 */ 
			if(m < 3) 
				error(Ebadblt); 
1992/0630    
			v = BGSHORT(p+1); 
1991/0706    
			if(v != 0) 
				error(Ebadbitmap); 
			m -= 3; 
			p += 3; 
1992/0621    
			nw = 1 << (1 << gscreen.ldepth); 
1991/0706    
			if(m < 12*nw) 
				error(Ebadblt); 
			ok = 1; 
			for(i = 0; i < nw; i++){ 
1992/1030    
				ok &= setcolor(flipping ? ~i : i, BGLONG(p), BGLONG(p+4), BGLONG(p+8)); 
1991/0706    
				p += 12; 
				m -= 12; 
			} 
			if(!ok){ 
				/* assume monochrome: possibly change flipping */ 
1992/0630    
				l = BGLONG(p-12); 
1991/0706    
				getcolor(nw-1, &rv, &rv, &rv); 
				flipping = (l != rv); 
			} 
			break; 
1990/0327    
		} 
 
1991/0614    
	poperror(); 
1992/1107    
	screenupdate(); 
1990/0721    
	if(isoff) 
		cursoron(1); 
1992/0622    
	qunlock(&bit); 
1990/0324    
	return n; 
} 
 
1992/0621    
int 
1992/0209    
bitalloc(Rectangle rect, int ld) 
{ 
1992/0711    
	Arena *a, *ea, *aa; 
1992/0621    
	GBitmap *b, **bp, **ep; 
1992/0209    
	ulong l, ws, nw; 
	long t; 
 
1992/0706    
	ws = BI2WD>>ld;	/* pixels per word */ 
1992/0621    
	if(rect.min.x >= 0){ 
1992/0519    
		l = (rect.max.x+ws-1)/ws; 
		l -= rect.min.x/ws; 
1992/0621    
	}else{	/* make positive before divide */ 
1992/0209    
		t = (-rect.min.x)+ws-1; 
		t = (t/ws)*ws; 
		l = (t+rect.max.x+ws-1)/ws; 
	} 
	nw = l*Dy(rect); 
1992/0622    
	ea = &bit.arena[bit.narena]; 
 
	/* first try easy fit */ 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
			continue; 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
1992/0209    
	} 
1992/0622    
 
	/* compact and try again */ 
	bitcompact(); 
	aa = 0; 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0){ 
			if(aa == 0) 
				aa = a; 
			continue; 
		} 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
	} 
 
	/* need new arena */ 
1992/0630    
	if(aa){ 
1992/0622    
		a = aa; 
1992/0706    
		a->nwords = HDR + (gscreen.r.max.y*gscreen.r.max.x)/ws; 
1992/0630    
		if(a->nwords < HDR+nw) 
			a->nwords = HDR+nw; 
		a->words = xalloc(a->nwords*sizeof(ulong)); 
		if(a->words){ 
			a->wfree = a->words; 
			a->nbusy = 0; 
			goto found; 
		} 
1992/0622    
	} 
1992/0630    
	/* else can't grow list: bitmaps have backpointers */ 
1992/0628    
 
1992/0706    
	bitfreeup(); 
 
1992/0628    
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
			continue; 
		if(a->wfree+HDR+nw <= a->words+a->nwords) 
			goto found; 
	} 
	if(a == ea) 
1992/0622    
		error(Enobitstore); 
	 
    found: 
1992/0706    
	b = bitmalloc(sizeof(GBitmap)); 
	if(b == 0) 
		error(Enomem); 
1992/0622    
	*a->wfree++ = nw; 
	*a->wfree++ = (ulong)a; 
	*a->wfree++ = (ulong)b; 
1992/0706    
	memset(a->wfree, 0, nw*sizeof(ulong)); 
1992/0622    
	b->base = a->wfree; 
	a->wfree += nw; 
	a->nbusy++; 
1992/0621    
	b->zero = l*rect.min.y; 
1992/0209    
	if(rect.min.x >= 0) 
1992/0621    
		b->zero += rect.min.x/ws; 
1992/0209    
	else 
1992/0621    
		b->zero -= (-rect.min.x+ws-1)/ws; 
	b->zero = -b->zero; 
	b->width = l; 
	b->ldepth = ld; 
	b->r = rect; 
	b->clipr = rect; 
	b->cache = 0; 
	/* worth doing better than linear lookup? */ 
	ep = bit.map+bit.nmap; 
	for(bp=bit.map; bp<ep; bp++) 
		if(*bp == 0) 
			break; 
	if(bp == ep){ 
1992/0706    
		bp = bitmalloc((bit.nmap+DMAP)*sizeof(GBitmap*)); 
		if(bp == 0){ 
			bitfree(b); 
			error(Enomem); 
		} 
		memmove(bp, bit.map, bit.nmap*sizeof(GBitmap*)); 
		free(bit.map); 
		bit.map = bp; 
		bp += bit.nmap; 
1992/0621    
		bit.nmap += DMAP; 
	} 
	*bp = b; 
	return bp-bit.map; 
1992/0209    
} 
 
1990/0324    
void 
1992/0621    
bitfree(GBitmap *b) 
1990/0327    
{ 
1992/0622    
	Arena *a; 
 
1992/0630    
	if(b->base != gscreen.base){	/* can't free screen memory */ 
		a = (Arena*)(b->base[-2]); 
		a->nbusy--; 
		if(a->nbusy == 0) 
			arenafree(a); 
		b->base[-1] = 0; 
	} 
1992/0621    
	free(b); 
1990/0327    
} 
 
1992/0209    
void 
1992/0621    
fontfree(GFont *f) 
{ 
	if(f->b) 
		bitfree(f->b); 
1992/0627    
	free(f->cache); 
1992/0621    
	free(f); 
} 
 
void 
1992/0702    
subfontfree(BSubfont *s, int i) 
1992/0621    
{ 
1992/0912    
	if(s!=bdefont && s->ref>0){	/* don't free subfont 0, bdefont */ 
1992/0630    
		s->ref--; 
1992/0702    
		if(s->ref==0 && s->qid[0]==~0){	/* uncached */ 
			bitfree(s->bits); 
			free(s->info); 
			free(s); 
			bit.subfont[i] = 0; 
		} 
	} 
1992/0628    
	return; 
1992/0621    
} 
 
void 
1992/0622    
arenafree(Arena *a) 
{ 
	xfree(a->words); 
	a->words = 0; 
} 
 
void 
1992/0209    
bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc) 
{ 
	int full; 
	Rectangle rect; 
	ushort r; 
	GCacheinfo *c; 
1992/0903    
	int x; 
	Fcode clr; 
1992/0209    
 
1992/0903    
	clr = 0; 
	full = (fc&~S)^(D&~S);	/* result involves source */ 
1992/0209    
	if(full){ 
		rect.min.y = 0; 
		rect.max.y = f->height; 
1992/0903    
		/* set clr to result under fc if source pixel is zero */ 
		/* hard to do without knowing layout of bits, so we cheat */ 
		clr = (fc&3);	/* fc&3 is result if source is zero */ 
		clr |= clr<<2;	/* fc&(3<<2) is result if source is one */ 
1992/0209    
	} 
 
	while(l > 0){ 
1992/0630    
		r = BGSHORT(p); 
1992/0209    
		p += 2; 
		l -= 2; 
1992/0630    
		if(r >= f->ncache) 
1992/0211    
			continue; 
1992/0209    
		c = &f->cache[r]; 
		if(!full){ 
			rect.min.y = c->top; 
			rect.max.y = c->bottom; 
1992/0903    
		}else{ 
			if(c->left > 0) 
				gbitblt(bp, pt, bp, 
					Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height), 
					clr); 
			x = c->left+(c->xright-c->x); 
			if(x < c->width) 
				gbitblt(bp, Pt(pt.x+x, pt.y), bp, 
					Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height), 
					clr); 
		} 
1992/0209    
		rect.min.x = c->x; 
		rect.max.x = c->xright; 
		gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc); 
		pt.x += c->width; 
	} 
} 
 
void 
bitloadchar(GFont *f, int ci, GSubfont *subf, int si) 
{ 
	GCacheinfo *c; 
	Rectangle rect; 
	Fontchar *fi; 
1992/0219    
	int y; 
1992/0209    
 
	c = &f->cache[ci]; 
	fi = &subf->info[si]; 
1992/0219    
	/* careful about sign extension: top and bottom are uchars */ 
	y = fi->top + (f->ascent-subf->ascent); 
	if(y < 0) 
		y = 0; 
	c->top = y; 
	y = fi->bottom + (f->ascent-subf->ascent); 
	if(y < 0) 
		y = 0; 
	c->bottom = y; 
1992/0209    
	c->width = fi->width; 
	c->left = fi->left; 
	c->x = ci*f->width; 
	c->xright = c->x + ((fi+1)->x - fi->x); 
	rect.min.y = 0; 
	rect.max.y = f->height; 
	rect.min.x = c->x; 
1992/0214    
	rect.max.x = c->x+f->width; 
	gbitblt(f->b, rect.min, f->b, rect, 0); 
1992/0209    
	rect.min.x = fi->x; 
	rect.max.x = (fi+1)->x; 
1992/0219    
	rect.max.y = subf->height; 
1992/0209    
	gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S); 
} 
 
1992/0818    
QLock	bitlock; 
 
GBitmap* 
id2bit(int v) 
{ 
	GBitmap *bp=0; 
 
	if(v<0 || v>=bit.nmap || (bp=bit.map[v])==0) 
		error(Ebadbitmap); 
	return bp; 
} 
 
1990/0327    
void 
bitcompact(void) 
{ 
1992/0711    
	Arena *a, *ea, *na; 
1992/0622    
	ulong *p1, *p2, n; 
1990/0327    
 
1992/0818    
	qlock(&bitlock); 
1992/0622    
	ea = &bit.arena[bit.narena]; 
	for(a=bit.arena; a<ea; a++){ 
		if(a->words == 0) 
1990/0327    
			continue; 
1992/0622    
		/* first compact what's here */ 
		p1 = p2 = a->words; 
		while(p2 < a->wfree){ 
			n = HDR+p2[0]; 
			if(p2[2] == 0){ 
				p2 += n; 
				continue; 
			} 
			if(p1 != p2){ 
				memmove(p1, p2, n*sizeof(ulong)); 
				((GBitmap*)p1[2])->base = p1+HDR; 
			} 
			p2 += n; 
			p1 += n; 
1990/0327    
		} 
1992/0622    
		/* now pull stuff from later arena to fill this one */ 
		na = a+1; 
		while(na<ea && p1<a->words+a->nwords){ 
			p2 = na->words; 
			if(p2 == 0){ 
				na++; 
				continue; 
			} 
			while(p2 < na->wfree){ 
				n = HDR+p2[0]; 
				if(p2[2] == 0){ 
					p2 += n; 
					continue; 
				} 
				if(p1+n < a->words+a->nwords){ 
					memmove(p1, p2, n*sizeof(ulong)); 
					((GBitmap*)p1[2])->base = p1+HDR; 
					/* block now in new arena... */ 
					p1[1] = (ulong)a; 
					a->nbusy++; 
					/* ... not in old arena */ 
					na->nbusy--; 
					p2[2] = 0; 
					p1 += n; 
				} 
				p2 += n; 
			} 
			na++; 
1990/0327    
		} 
1992/0622    
		a->wfree = p1; 
1990/0327    
	} 
1992/0630    
	for(a=bit.arena; a<ea; a++) 
		if(a->words && a->nbusy==0) 
1992/0622    
			arenafree(a); 
1992/0818    
	qunlock(&bitlock); 
1990/0329    
} 
 
void 
1990/05313    
Cursortocursor(Cursor *c) 
1990/0329    
{ 
1990/0504    
	int i; 
1991/0731    
	uchar *p; 
1990/0504    
 
	lock(&cursor); 
1991/0318    
	memmove(&cursor, c, sizeof(Cursor)); 
1990/0504    
	for(i=0; i<16; i++){ 
1991/0731    
		p = (uchar*)&setbits[i]; 
		*p = c->set[2*i]; 
		*(p+1) = c->set[2*i+1]; 
		p = (uchar*)&clrbits[i]; 
		*p = c->clr[2*i]; 
		*(p+1) = c->clr[2*i+1]; 
1990/0504    
	} 
	unlock(&cursor); 
} 
 
void 
cursoron(int dolock) 
{ 
1992/1107    
	if(cursor.disable) 
		return; 
1990/0504    
	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); 
1991/1225    
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S); 
1992/1013    
		gbitblt(&gscreen, cursor.r.min, 
1991/0706    
			&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S); 
1992/1013    
		gbitblt(&gscreen, cursor.r.min, 
1991/0706    
			&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D); 
1992/1104    
		mbbrect(cursor.r); 
1992/1107    
		screenupdate(); 
1990/0504    
	} 
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
cursoroff(int dolock) 
{ 
1992/1107    
	if(cursor.disable) 
		return; 
1990/0504    
	if(dolock) 
		lock(&cursor); 
1992/1013    
	if(--cursor.visible == 0) { 
1991/1225    
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S); 
1992/1104    
		mbbrect(cursor.r); 
1992/1107    
		screenupdate(); 
1992/1013    
	} 
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    
} 
 
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); 
1992/1104    
	mousescreenupdate(); 
1991/0707    
	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); 
	} 
} 
 
1992/1020    
/* 
 *  microsoft 3 button, 7 bit bytes 
 * 
 *	byte 0 -	1  L  R Y7 Y6 X7 X6 
 *	byte 1 -	0 X5 X4 X3 X2 X1 X0 
 *	byte 2 -	0 Y5 Y4 Y3 Y2 Y1 Y0 
 *	byte 3 -	0  M  x  x  x  x  x	(optional) 
 * 
1992/1021    
 *  shift & right button is the same as middle button (for 2 button mice) 
1992/1020    
 */ 
int 
m3mouseputc(IOQ *q, int c) 
{ 
	static uchar msg[3]; 
	static int nb; 
1992/1021    
	static int middle; 
	static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 }; 
1992/1020    
	short x; 
 
	USED(q); 
	/*  
	 *  check bit 6 for consistency 
	 */ 
	if(nb==0){ 
		if((c&0x40) == 0){ 
			/* an extra byte gets sent for the middle button */ 
1992/1021    
			middle = (c&0x20) ? 2 : 0; 
			mousebuttons((mouse.buttons & ~2) | middle); 
1992/1020    
			return 0; 
		} 
	} 
	msg[nb] = c; 
	if(++nb == 3){ 
		nb = 0; 
1992/1021    
		mouse.newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)]; 
1992/1020    
		x = (msg[0]&0x3)<<14; 
		mouse.dx = (x>>8) | msg[1]; 
		x = (msg[0]&0xc)<<12; 
		mouse.dy = (x>>8) | msg[2]; 
		mouse.track = 1; 
		mouseclock(); 
	} 
	return 0; 
} 
 
/* 
 *  Logitech 5 byte packed binary mouse format, 8 bit bytes 
1992/1021    
 * 
 *  shift & right button is the same as middle button (for 2 button mice) 
1992/1020    
 */ 
1991/0605    
int 
mouseputc(IOQ *q, int c) 
{ 
1991/0706    
	static short msg[5]; 
	static int nb; 
1992/1021    
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7}; 
1991/0605    
 
1991/1115    
	USED(q); 
1991/0706    
	if((c&0xF0) == 0x80) 
		nb=0; 
	msg[nb] = c; 
	if(c & 0x80) 
1992/0630    
		msg[nb] |= ~0xFF;	/* sign extend */ 
1991/0706    
	if(++nb == 5){ 
1992/1107    
		mouse.newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)]; 
1991/0706    
		mouse.dx = msg[1]+msg[3]; 
		mouse.dy = -(msg[2]+msg[4]); 
		mouse.track = 1; 
		mouseclock(); 
		nb = 0; 
1990/0329    
	} 
1992/0522    
	return 0; 
1990/0505    
} 
 
int 
mousechanged(void *m) 
{ 
1991/1115    
	USED(m); 
1990/0505    
	return mouse.changed; 
1992/1106    
} 
 
/* 
1992/1108    
 *  reverse the bits in a bitmap (converting between little & big endian) 
1992/1106    
 */ 
1992/1108    
uchar bitrevtab[] = { 
1992/1106    
	0x00,	0x80,	0x40,	0xc0,	0x20,	0xa0,	0x60,	0xe0, 
	0x10,	0x90,	0x50,	0xd0,	0x30,	0xb0,	0x70,	0xf0, 
	0x08,	0x88,	0x48,	0xc8,	0x28,	0xa8,	0x68,	0xe8, 
	0x18,	0x98,	0x58,	0xd8,	0x38,	0xb8,	0x78,	0xf8, 
	0x04,	0x84,	0x44,	0xc4,	0x24,	0xa4,	0x64,	0xe4, 
	0x14,	0x94,	0x54,	0xd4,	0x34,	0xb4,	0x74,	0xf4, 
	0x0c,	0x8c,	0x4c,	0xcc,	0x2c,	0xac,	0x6c,	0xec, 
	0x1c,	0x9c,	0x5c,	0xdc,	0x3c,	0xbc,	0x7c,	0xfc, 
	0x02,	0x82,	0x42,	0xc2,	0x22,	0xa2,	0x62,	0xe2, 
	0x12,	0x92,	0x52,	0xd2,	0x32,	0xb2,	0x72,	0xf2, 
	0x0a,	0x8a,	0x4a,	0xca,	0x2a,	0xaa,	0x6a,	0xea, 
	0x1a,	0x9a,	0x5a,	0xda,	0x3a,	0xba,	0x7a,	0xfa, 
	0x06,	0x86,	0x46,	0xc6,	0x26,	0xa6,	0x66,	0xe6, 
	0x16,	0x96,	0x56,	0xd6,	0x36,	0xb6,	0x76,	0xf6, 
	0x0e,	0x8e,	0x4e,	0xce,	0x2e,	0xae,	0x6e,	0xee, 
	0x1e,	0x9e,	0x5e,	0xde,	0x3e,	0xbe,	0x7e,	0xfe, 
	0x01,	0x81,	0x41,	0xc1,	0x21,	0xa1,	0x61,	0xe1, 
	0x11,	0x91,	0x51,	0xd1,	0x31,	0xb1,	0x71,	0xf1, 
	0x09,	0x89,	0x49,	0xc9,	0x29,	0xa9,	0x69,	0xe9, 
	0x19,	0x99,	0x59,	0xd9,	0x39,	0xb9,	0x79,	0xf9, 
	0x05,	0x85,	0x45,	0xc5,	0x25,	0xa5,	0x65,	0xe5, 
	0x15,	0x95,	0x55,	0xd5,	0x35,	0xb5,	0x75,	0xf5, 
	0x0d,	0x8d,	0x4d,	0xcd,	0x2d,	0xad,	0x6d,	0xed, 
	0x1d,	0x9d,	0x5d,	0xdd,	0x3d,	0xbd,	0x7d,	0xfd, 
	0x03,	0x83,	0x43,	0xc3,	0x23,	0xa3,	0x63,	0xe3, 
	0x13,	0x93,	0x53,	0xd3,	0x33,	0xb3,	0x73,	0xf3, 
	0x0b,	0x8b,	0x4b,	0xcb,	0x2b,	0xab,	0x6b,	0xeb, 
	0x1b,	0x9b,	0x5b,	0xdb,	0x3b,	0xbb,	0x7b,	0xfb, 
	0x07,	0x87,	0x47,	0xc7,	0x27,	0xa7,	0x67,	0xe7, 
	0x17,	0x97,	0x57,	0xd7,	0x37,	0xb7,	0x77,	0xf7, 
	0x0f,	0x8f,	0x4f,	0xcf,	0x2f,	0xaf,	0x6f,	0xef, 
	0x1f,	0x9f,	0x5f,	0xdf,	0x3f,	0xbf,	0x7f,	0xff 
}; 
 
void 
bitreverse(uchar *p, int l) 
{ 
	uchar *e; 
 
	e = p + l; 
	for(; p < e; p++) 
1992/1108    
		*p = bitrevtab[*p]; 
1990/0324    
} 


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