elimore crap54e27ce9 years agoHistory
884 lines · 15.3 KB · C
RawDownload
#include <string.h>#include <stdio.h>#include <fcntl.h>#include <error.h>#include <errno.h>#include "draw.h" #define _drawdebug 1 Display	*display;Font	*font;Image	*screen;Screen	*_screen;Point	ZP; static int	screenid; staticintunitsperline(Rectangle r, int d, int bitsperunit){	ulong l, t; 	if(d <= 0 || d > 32)	/* being called wrong.  d is image depth. */		abort(); 	if(r.min.x >= 0){		l = (r.max.x*d+bitsperunit-1)/bitsperunit;		l -= (r.min.x*d)/bitsperunit;	}else{			/* make positive before divide */		t = (-r.min.x*d+bitsperunit-1)/bitsperunit;		l = t+(r.max.x*d+bitsperunit-1)/bitsperunit;	}	return l;} intwordsperline(Rectangle r, int d){	return unitsperline(r, d, 8*sizeof(ulong));} intrgb2cmap(int cr, int cg, int cb){	int i, r, g, b, sq;	ulong rgb;	int best, bestsq; 	best = 0;	bestsq = 0x7FFFFFFF;	for(i=0; i<256; i++){		rgb = cmap2rgb(i);		r = (rgb>>16) & 0xFF;		g = (rgb>>8) & 0xFF;		b = (rgb>>0) & 0xFF;		sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb);		if(sq < bestsq){			bestsq = sq;			best = i;		}	}	return best;} intcmap2rgb(int c){	int j, num, den, r, g, b, v, rgb; 	r = c>>6;	v = (c>>4)&3;	j = (c-v+r)&15;	g = j>>2;	b = j&3;	den=r;	if(g>den)		den=g;	if(b>den)		den=b;	if(den==0) {		v *= 17;		rgb = (v<<16)|(v<<8)|v;	}	else{		num=17*(4*den+v);		rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den);	}	return rgb;} intcmap2rgba(int c){	return (cmap2rgb(c)<<8)|0xFF;} Screen*allocscreen(Image *image, Image *fill, int public){	uchar *a;	Screen *s;	int id, try;	Display *d; 	d = image->display;	if(d != fill->display){		fprintf(stderr, "allocscreen: image and fill on different displays");		return nil;	}	s = malloc(sizeof(Screen));	if(s == nil)		return nil;	if(!screenid)		screenid = getpid();	for(try=0; try<25; try++){		/* loop until find a free id */		a = bufimage(d, 1+4+4+4+1);		if(a == nil)			break;		id = ++screenid & 0xffff;	/* old devdraw bug */		a[0] = 'A';		BPLONG(a+1, id);		BPLONG(a+5, image->id);		BPLONG(a+9, fill->id);		a[13] = public;		if(flushimage(d, 0) != -1)			goto Found;	}	free(s);	return nil;     Found:	s->display = d;	s->id = id;	s->image = image;	if(s->image != nil && s->image->chan != 0){		s->fill = fill;		return s;	}	exit(-1);} intfreescreen(Screen *s){	uchar *a;	Display *d; 	if(s == nil)		return 0;	d = s->display;	a = bufimage(d, 1+4);	if(a == nil){Error:		free(s);		return -1;	}	a[0] = 'F';	BPLONG(a+1, s->id);	/*	 * flush(1) because screen is likely holding last reference to	 * window, and want it to disappear visually.	 */	if(flushimage(d, 1) < 0)		goto Error;	free(s);	return 1;} Image*_allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong col){	Display *d; 	d = s->display;	i = _allocimage(i, d, r, d->screenimage->chan, 0, col, s->id, ref);	if(i == nil)		return nil;	i->screen = s;	i->next = s->display->windows;	s->display->windows = i;	return i;} Image*namedimage(Display *d, char *name){	uchar *a;	char *err, buf[12*12+1];	Image *i;	int id, n;	ulong chan; 	err = nil;	i = nil; 	n = strlen(name);	if(n >= 256){		err = "name too long";    Error:		if(err != nil)			fprintf(stderr,"namedimage: %s", err);		else			fprintf(stderr,"namedimage: %s", strerror(errno));		free(i);		return nil;	}	/* flush pending data so we don't get error allocating the image */	flushimage(d, 0);	a = bufimage(d, 1+4+1+n);	if(a == nil)		goto Error;	d->imageid++;	id = d->imageid;	a[0] = 'n';	BPLONG(a+1, id);	a[5] = n;	memmove(a+6, name, n);	if(flushimage(d, 0) < 0)		goto Error; 	if(pread(d->ctlfd, buf, 12*12, 0) < 12*12)		goto Error;	buf[12*12] = '\0'; 	i = malloc(sizeof(Image));	if(i == nil){	Error1:		a = bufimage(d, 1+4);		if(a != nil){			a[0] = 'f';			BPLONG(a+1, id);			flushimage(d, 0);		}		goto Error;	}	i->display = d;	i->id = id;	if((chan=strtochan(buf+2*12))==0){		fprintf(stderr, "bad channel '%.12s' from devdraw", buf+2*12);		goto Error1;	}	i->chan = chan;	i->depth = chantodepth(chan);	i->repl = atoi(buf+3*12);	i->r.min.x = atoi(buf+4*12);	i->r.min.y = atoi(buf+5*12);	i->r.max.x = atoi(buf+6*12);	i->r.max.y = atoi(buf+7*12);	i->clipr.min.x = atoi(buf+8*12);	i->clipr.min.y = atoi(buf+9*12);	i->clipr.max.x = atoi(buf+10*12);	i->clipr.max.y = atoi(buf+11*12);	i->screen = nil;	i->next = nil;	return i;} void_setdrawop(Display *d, Drawop op){	uchar *a; 	if(op != SoverD){		a = bufimage(d, 1+1);		if(a == nil)			return;		a[0] = 'O';		a[1] = op;	}}		static voiddraw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op){	uchar *a; 	_setdrawop(dst->display, op); 	a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4);	if(a == nil)		return;	if(src == nil)		src = dst->display->black;	if(mask == nil)		mask = dst->display->opaque;	a[0] = 'd';	BPLONG(a+1, dst->id);	BPLONG(a+5, src->id);	BPLONG(a+9, mask->id);	BPLONG(a+13, r->min.x);	BPLONG(a+17, r->min.y);	BPLONG(a+21, r->max.x);	BPLONG(a+25, r->max.y);	BPLONG(a+29, p0->x);	BPLONG(a+33, p0->y);	BPLONG(a+37, p1->x);	BPLONG(a+41, p1->y); } voiddraw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1){	draw1(dst, &r, src, &p1, mask, &p1, SoverD);} int_freeimage1(Image *i){	uchar *a;	Display *d;	Image *w; 	if(i == nil || i->display == nil)		return 0;	d = i->display;	if(i->screen != nil){		w = d->windows;		if(w == i)			d->windows = i->next;		else			while(w != nil){				if(w->next == i){					w->next = i->next;					break;				}				w = w->next;			}	}	a = bufimage(d, 1+4);	if(a == nil)		return -1;	a[0] = 'f';	BPLONG(a+1, i->id);	return 0;} intfreeimage(Image *i){	int ret; 	ret = _freeimage1(i);	free(i);	return ret;} static void_closedisplay(Display *disp, int isshutdown){	int fd;	char buf[128]; 	if(disp == nil)		return;	if(disp == display)		display = nil;	if(disp->oldlabel[0]){		snprintf(buf, sizeof buf, "%s/label", disp->windir);		fd = open(buf, O_WRONLY);		if(fd >= 0){			write(fd, disp->oldlabel, strlen(disp->oldlabel));			close(fd);		}	} 	/*	 * if we're shutting down, don't free all the resources.	 * if other procs are getting shot down by notes too,	 * one might get shot down while holding the malloc lock.	 * just let the kernel clean things up when we exit.	 */	if(isshutdown)		return; 	free(disp->devdir);	free(disp->windir);	freeimage(disp->white);	freeimage(disp->black);	close(disp->fd);	close(disp->ctlfd);	/* should cause refresh slave to shut down */	close(disp->reffd);	/* qunlock(&disp->qlock); TODO */	free(disp);} voidclosedisplay(Display *disp){	_closedisplay(disp, 0);} /* note handler */static voiddrawshutdown(void){	Display *d; 	d = display;	if(d != nil){		display = nil;		_closedisplay(d, 1);	}} PointPt(int x, int y){	Point p; 	p.x = x;	p.y = y;	return p;} RectangleRect(int x, int y, int bx, int by){	Rectangle r; 	r.min.x = x;	r.min.y = y;	r.max.x = bx;	r.max.y = by;	return r;} Rectangleinsetrect(Rectangle r, int n){	r.min.x += n;	r.min.y += n;	r.max.x -= n;	r.max.y -= n;	return r;} intbadrect(Rectangle r){	int x, y;	uint z; 	x = Dx(r);	y = Dy(r);	if(x > 0 && y > 0){		z = x*y;		if(z/x == y && z < 0x10000000)			return 0;	}	return 1;} static char channames[] = "rgbkamx"; intchantodepth(ulong c){	int n; 	for(n=0; c; c>>=8){		if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0)			return 0;		n += NBITS(c);	}	if(n==0 || (n>8 && n%8) || (n<8 && 8%n))		return 0;	return n;} ulongstrtochan(char *s){	char *p, *q;	ulong c;	int t, n, d; 	c = 0;	d = 0;	p=s;	while(*p && isspace(*p))		p++; 	while(*p && !isspace(*p)){		if((q = strchr(channames, p[0])) == nil) 			return 0;		t = q-channames;		if(p[1] < '0' || p[1] > '9')			return 0;		n = p[1]-'0';		d += n;		c = (c<<8) | __DC(t, n);		p += 2;	}	if(d==0 || (d>8 && d%8) || (d<8 && 8%d))		return 0;	return c;

Lines 1–500 of 884.