Charles.Forsyth20060303a828770d19 years agoHistory
2345 lines · 39.9 KB · C
RawDownload
#include <lib9.h>#include <kernel.h>#include "interp.h"#include "isa.h"#include "runt.h"#include "raise.h"#include "drawmod.h"#include "draw.h"#include "drawif.h"#include "memdraw.h"#include "memlayer.h" /* * When a Display is remote, it must be locked to synchronize the * outgoing message buffer with the refresh demon, which runs as a * different process.  When it is local, the refresh demon does nothing * and it is sufficient to use the interpreter's own acquire/release protection * to lock the buffer. * * Most action to the buffer is caused by calls from Limbo, so locking at * the top before going into the library is good enough.  However, the * garbage collector can call the free routines at other times, so they * need to protect themselves whether called through the Draw module * or not; hence the need for check against recursive locking in lockdisplay(). * This also means that we needn't lock around calls to destroy if it's * extra work to do so. */ typedef struct Cache Cache;typedef struct DRef DRef;typedef struct DDisplay DDisplay;typedef struct DImage DImage;typedef struct DScreen DScreen;typedef struct DFont DFont; struct Cache{	int	ref;	char*	name;	Display*display;	union{		Subfont*	sf;		Font*		f;		void*		ptr;	}u;	Cache*	next;}; /* not visible to Limbo; used only for internal reference counting */struct DRef{	int		ref;	Display*	display;}; struct DDisplay{	Draw_Display	drawdisplay;	Display*	display;	DRef*		dref;}; struct DImage{	Draw_Image	drawimage;	Image*		image;	void*		refreshptr;	DRef*		dref;	int		flush;}; struct DScreen{	Draw_Screen	drawscreen;	Screen*		screen;	DRef*		dref;}; struct DFont{	Draw_Font	drawfont;	Font*		font;	DRef*		dref;}; Cache*	sfcache[BIHASH];Cache*	fcache[BIHASH];void*	cacheqlock; static	Cache	*cachelookup(Cache**, Display*, char*); uchar fontmap[] = Draw_Font_map;uchar imagemap[] = Draw_Image_map;uchar screenmap[] = Draw_Screen_map;uchar displaymap[] = Draw_Display_map; Type*	TFont;Type*	TImage;Type*	TScreen;Type*	TDisplay; Draw_Image*	allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int);Draw_Image*	color(DDisplay*, ulong);Draw_Screen	*mkdrawscreen(Screen*, Draw_Display*); char		deffontname[] = "*default*";void		refreshslave(Display*);void		subfont_close(Subfont*);void		freeallsubfonts(Display*); voiddrawmodinit(void){	TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap));	TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap));	TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap));	TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap));	builtinmod("$Draw", Drawmodtab, Drawmodlen);} static intdrawhash(char *s){	int h; 	h = 0;	while(*s){		h += *s++;		h <<= 1;		if(h & (1<<8))			h |= 1;	}	return (h&0xFFFF)%BIHASH;} static Cache*cachelookup(Cache *cache[], Display *d, char *name){	Cache *c; 	libqlock(cacheqlock);	c = cache[drawhash(name)];	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0))		c = c->next;	libqunlock(cacheqlock);	return c;} Cache*cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type){	Cache *c;	int hash; 	USED(type);	c = cachelookup(cache, d, name);	if(c){/*		print("%s %s already in cache\n", type, name); /**/		return nil;	}	c = malloc(sizeof(Cache));	if(c == nil)		return nil;	hash = drawhash(name);	c->ref = 0;	/* will be incremented by caller */	c->display = d;	c->name = strdup(name);	c->u.ptr = ptr;	libqlock(cacheqlock);	c->next = cache[hash];	cache[hash] = c;	libqunlock(cacheqlock);	return c;} voidcacheuninstall(Cache **cache, Display *d, char *name, char *type){	Cache *c, *prev;	int hash; 	hash = drawhash(name);	libqlock(cacheqlock);	c = cache[hash];	if(c == nil){   Notfound:		libqunlock(cacheqlock);		print("%s not in %s cache\n", name, type);		return;	}	prev = nil;	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){		prev = c;		c = c->next;	}	if(c == nil)		goto Notfound;	if(prev == 0)		cache[hash] = c->next;	else		prev->next = c->next;	libqunlock(cacheqlock);	free(c->name);	free(c);} Image*lookupimage(Draw_Image *di){	Display *disp;	Image *i;	int locked; 	if(di == H || D2H(di)->t != TImage)		return nil;	i = ((DImage*)di)->image;	if(i == nil)		return nil;	if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){		disp = i->display;		locked = lockdisplay(disp);		replclipr(i, di->repl, IRECT(di->clipr));		if(locked)			unlockdisplay(disp);	}	return i;} Screen*lookupscreen(Draw_Screen *ds){	if(ds == H || D2H(ds)->t != TScreen)		return nil;	return ((DScreen*)ds)->screen;} Font*lookupfont(Draw_Font *df){	if(df == H || D2H(df)->t != TFont)		return nil;	return ((DFont*)df)->font;} Display*lookupdisplay(Draw_Display *dd){	if(dd == H || D2H(dd)->t != TDisplay)		return nil;	return ((DDisplay*)dd)->display;} Image*checkimage(Draw_Image *di){	Image *i; 	if(di == H)		error("nil Image");	i = lookupimage(di);	if(i == nil)		error(exType);	return i;} Screen*checkscreen(Draw_Screen *ds){	Screen *s; 	if(ds == H)		error("nil Screen");	s = lookupscreen(ds);	if(s == nil)		error(exType);	return s;} Font*checkfont(Draw_Font *df){	Font *f; 	if(df == H)		error("nil Font");	f = lookupfont(df);	if(f == nil)		error(exType);	return f;} Display*checkdisplay(Draw_Display *dd){	Display *d; 	if(dd == H)		error("nil Display");	d = lookupdisplay(dd);	if(d == nil)		error(exType);	return d;} voidDisplay_allocate(void *fp){	F_Display_allocate *f;	char buf[128], *dev;	Subfont *df;	Display *display;	DDisplay *dd;	Heap *h;	Draw_Rect r;	DRef *dr;	Cache *c; 	f = fp;	destroy(*f->ret);	*f->ret = H;	if(cacheqlock == nil){		cacheqlock = libqlalloc();		if(cacheqlock == nil)			return;	}	dev = string2c(f->dev);	if(dev[0] == 0)		dev = 0;	display = initdisplay(dev, dev, nil);	/* TO DO: win, error */	if(display == 0)		return; 	dr = malloc(sizeof(DRef));	if(dr == nil)		return;	h = heap(TDisplay);	if(h == H){		closedisplay(display);		return;	}	dd = H2D(DDisplay*, h);	dd->display = display;	*f->ret = &dd->drawdisplay;	dd->dref = dr;	display->limbo = dr;	dr->display = display;	dr->ref = 1;	df = getdefont(display);	if(df){		display->defaultsubfont = df;		sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,			df->n-1, deffontname);		display->defaultfont = buildfont(display, buf, deffontname);		if(display->defaultfont){			c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font");			if(c)				c->ref++;			/* else BUG? */		}	} 	R2R(r, display->image->r);	dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0);	R2R(r, display->white->r);	dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0);	dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0);	dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0);	dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0); 	/* don't call unlockdisplay because the qlock was left up by initdisplay */	libqunlock(display->qlock);} voidDisplay_getwindow(void *fp){	F_Display_getwindow *f;	Display *disp;	int locked;	Image *image;	Screen *screen;	char *wn;	void *r; 	f = fp;	r = f->ret->t0;	f->ret->t0 = H;	destroy(r);	r = f->ret->t1;	f->ret->t1 = H;	destroy(r);	disp = checkdisplay(f->d);	if(f->winname == H)		wn = "/dev/winname";	else		wn = string2c(f->winname);	if(f->image == H)		image = nil;	else		image = checkimage(f->image);	if(f->screen == H)		screen = nil;	else		screen = checkscreen(f->screen);	locked = lockdisplay(disp);	if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){		/* TO DO: eliminate f->image and f->screen's references to Image and Screen */		goto Return;	}	if(screen != nil){		if(f->screen != H){			f->ret->t0 = f->screen;			D2H(f->screen)->ref++;		}else			f->ret->t0 = mkdrawscreen(screen, f->d);	}	if(image != nil){		if(f->image != H){			f->ret->t1 = f->image;			D2H(f->image)->ref++;		}else			f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil);	} Return:	if(locked)		unlockdisplay(disp);} voidDisplay_startrefresh(void *fp){	F_Display_startrefresh *f;	Display *disp; 	f = fp;	disp = checkdisplay(f->d);	refreshslave(disp);} voiddisplay_dec(void *v){	DRef *dr;	Display *d;	int locked; 	dr = v;	if(dr->ref-- != 1)		return; 	d = dr->display;	locked = lockdisplay(d);	font_close(d->defaultfont);	subfont_close(d->defaultsubfont);	if(locked)		unlockdisplay(d);	freeallsubfonts(d);	closedisplay(d);	free(dr);} voidfreedrawdisplay(Heap *h, int swept){	DDisplay *dd;	Display *d; 	dd = H2D(DDisplay*, h); 	if(!swept) {		destroy(dd->drawdisplay.image);		destroy(dd->drawdisplay.black);		destroy(dd->drawdisplay.white);		destroy(dd->drawdisplay.opaque);		destroy(dd->drawdisplay.transparent);	}	/* we've now released dd->image etc.; make sure they're not freed again */	d = dd->display;	d->image = nil;	d->white = nil;	d->black = nil;	d->opaque = nil;	d->transparent = nil;	display_dec(dd->dref);	/* Draw_Display header will be freed by caller */} voidDisplay_color(void *fp){	F_Display_color *f;	Display *d;	int locked; 	f = fp;	destroy(*f->ret);	*f->ret = H;	d = checkdisplay(f->d);	locked = lockdisplay(d);

Lines 1–500 of 2345.