xref: /inferno-os/libinterp/draw.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include <lib9.h>
2 #include <kernel.h>
3 #include "interp.h"
4 #include "isa.h"
5 #include "runt.h"
6 #include "raise.h"
7 #include "drawmod.h"
8 #include "draw.h"
9 #include "drawif.h"
10 #include "memdraw.h"
11 #include "memlayer.h"
12 
13 /*
14  * When a Display is remote, it must be locked to synchronize the
15  * outgoing message buffer with the refresh demon, which runs as a
16  * different process.  When it is local, the refresh demon does nothing
17  * and it is sufficient to use the interpreter's own acquire/release protection
18  * to lock the buffer.
19  *
20  * Most action to the buffer is caused by calls from Limbo, so locking at
21  * the top before going into the library is good enough.  However, the
22  * garbage collector can call the free routines at other times, so they
23  * need to protect themselves whether called through the Draw module
24  * or not; hence the need for check against recursive locking in lockdisplay().
25  * This also means that we needn't lock around calls to destroy if it's
26  * extra work to do so.
27  */
28 
29 typedef struct Cache Cache;
30 typedef struct DRef DRef;
31 typedef struct DDisplay DDisplay;
32 typedef struct DImage DImage;
33 typedef struct DScreen DScreen;
34 typedef struct DFont DFont;
35 
36 struct Cache
37 {
38 	int	ref;
39 	char*	name;
40 	Display*display;
41 	union{
42 		Subfont*	sf;
43 		Font*		f;
44 		void*		ptr;
45 	}u;
46 	Cache*	next;
47 };
48 
49 /* not visible to Limbo; used only for internal reference counting */
50 struct DRef
51 {
52 	int		ref;
53 	Display*	display;
54 };
55 
56 struct DDisplay
57 {
58 	Draw_Display	drawdisplay;
59 	Display*	display;
60 	DRef*		dref;
61 };
62 
63 struct DImage
64 {
65 	Draw_Image	drawimage;
66 	Image*		image;
67 	void*		refreshptr;
68 	DRef*		dref;
69 	int		flush;
70 };
71 
72 struct DScreen
73 {
74 	Draw_Screen	drawscreen;
75 	Screen*		screen;
76 	DRef*		dref;
77 };
78 
79 struct DFont
80 {
81 	Draw_Font	drawfont;
82 	Font*		font;
83 	DRef*		dref;
84 };
85 
86 Cache*	sfcache[BIHASH];
87 Cache*	fcache[BIHASH];
88 void*	cacheqlock;
89 
90 static	Cache	*cachelookup(Cache**, Display*, char*);
91 
92 uchar fontmap[] = Draw_Font_map;
93 uchar imagemap[] = Draw_Image_map;
94 uchar screenmap[] = Draw_Screen_map;
95 uchar displaymap[] = Draw_Display_map;
96 
97 Type*	TFont;
98 Type*	TImage;
99 Type*	TScreen;
100 Type*	TDisplay;
101 
102 Draw_Image*	allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int);
103 Draw_Image*	color(DDisplay*, ulong);
104 Draw_Screen	*mkdrawscreen(Screen*, Draw_Display*);
105 
106 char		deffontname[] = "*default*";
107 void		refreshslave(Display*);
108 void		subfont_close(Subfont*);
109 void		freeallsubfonts(Display*);
110 
111 void
112 drawmodinit(void)
113 {
114 	TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap));
115 	TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap));
116 	TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap));
117 	TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap));
118 	builtinmod("$Draw", Drawmodtab, Drawmodlen);
119 }
120 
121 static int
122 drawhash(char *s)
123 {
124 	int h;
125 
126 	h = 0;
127 	while(*s){
128 		h += *s++;
129 		h <<= 1;
130 		if(h & (1<<8))
131 			h |= 1;
132 	}
133 	return (h&0xFFFF)%BIHASH;
134 }
135 
136 static Cache*
137 cachelookup(Cache *cache[], Display *d, char *name)
138 {
139 	Cache *c;
140 
141 	libqlock(cacheqlock);
142 	c = cache[drawhash(name)];
143 	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0))
144 		c = c->next;
145 	libqunlock(cacheqlock);
146 	return c;
147 }
148 
149 Cache*
150 cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type)
151 {
152 	Cache *c;
153 	int hash;
154 
155 	USED(type);
156 	c = cachelookup(cache, d, name);
157 	if(c){
158 /*		print("%s %s already in cache\n", type, name); /**/
159 		return nil;
160 	}
161 	c = malloc(sizeof(Cache));
162 	if(c == nil)
163 		return nil;
164 	hash = drawhash(name);
165 	c->ref = 0;	/* will be incremented by caller */
166 	c->display = d;
167 	c->name = strdup(name);
168 	c->u.ptr = ptr;
169 	libqlock(cacheqlock);
170 	c->next = cache[hash];
171 	cache[hash] = c;
172 	libqunlock(cacheqlock);
173 	return c;
174 }
175 
176 void
177 cacheuninstall(Cache **cache, Display *d, char *name, char *type)
178 {
179 	Cache *c, *prev;
180 	int hash;
181 
182 	hash = drawhash(name);
183 	libqlock(cacheqlock);
184 	c = cache[hash];
185 	if(c == nil){
186    Notfound:
187 		libqunlock(cacheqlock);
188 		print("%s not in %s cache\n", name, type);
189 		return;
190 	}
191 	prev = nil;
192 	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){
193 		prev = c;
194 		c = c->next;
195 	}
196 	if(c == nil)
197 		goto Notfound;
198 	if(prev == 0)
199 		cache[hash] = c->next;
200 	else
201 		prev->next = c->next;
202 	libqunlock(cacheqlock);
203 	free(c->name);
204 	free(c);
205 }
206 
207 Image*
208 lookupimage(Draw_Image *di)
209 {
210 	Display *disp;
211 	Image *i;
212 	int locked;
213 
214 	if(di == H || D2H(di)->t != TImage)
215 		return nil;
216 	i = ((DImage*)di)->image;
217 	if(i == nil)
218 		return nil;
219 	if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){
220 		disp = i->display;
221 		locked = lockdisplay(disp);
222 		replclipr(i, di->repl, IRECT(di->clipr));
223 		if(locked)
224 			unlockdisplay(disp);
225 	}
226 	return i;
227 }
228 
229 Screen*
230 lookupscreen(Draw_Screen *ds)
231 {
232 	if(ds == H || D2H(ds)->t != TScreen)
233 		return nil;
234 	return ((DScreen*)ds)->screen;
235 }
236 
237 Font*
238 lookupfont(Draw_Font *df)
239 {
240 	if(df == H || D2H(df)->t != TFont)
241 		return nil;
242 	return ((DFont*)df)->font;
243 }
244 
245 Display*
246 lookupdisplay(Draw_Display *dd)
247 {
248 	if(dd == H || D2H(dd)->t != TDisplay)
249 		return nil;
250 	return ((DDisplay*)dd)->display;
251 }
252 
253 Image*
254 checkimage(Draw_Image *di)
255 {
256 	Image *i;
257 
258 	if(di == H)
259 		error("nil Image");
260 	i = lookupimage(di);
261 	if(i == nil)
262 		error(exType);
263 	return i;
264 }
265 
266 Screen*
267 checkscreen(Draw_Screen *ds)
268 {
269 	Screen *s;
270 
271 	if(ds == H)
272 		error("nil Screen");
273 	s = lookupscreen(ds);
274 	if(s == nil)
275 		error(exType);
276 	return s;
277 }
278 
279 Font*
280 checkfont(Draw_Font *df)
281 {
282 	Font *f;
283 
284 	if(df == H)
285 		error("nil Font");
286 	f = lookupfont(df);
287 	if(f == nil)
288 		error(exType);
289 	return f;
290 }
291 
292 Display*
293 checkdisplay(Draw_Display *dd)
294 {
295 	Display *d;
296 
297 	if(dd == H)
298 		error("nil Display");
299 	d = lookupdisplay(dd);
300 	if(d == nil)
301 		error(exType);
302 	return d;
303 }
304 
305 void
306 Display_allocate(void *fp)
307 {
308 	F_Display_allocate *f;
309 	char buf[128], *dev;
310 	Subfont *df;
311 	Display *display;
312 	DDisplay *dd;
313 	Heap *h;
314 	Draw_Rect r;
315 	DRef *dr;
316 	Cache *c;
317 
318 	f = fp;
319 	destroy(*f->ret);
320 	*f->ret = H;
321 	if(cacheqlock == nil){
322 		cacheqlock = libqlalloc();
323 		if(cacheqlock == nil)
324 			return;
325 	}
326 	dev = string2c(f->dev);
327 	if(dev[0] == 0)
328 		dev = 0;
329 	display = initdisplay(dev, dev, nil);	/* TO DO: win, error */
330 	if(display == 0)
331 		return;
332 
333 	dr = malloc(sizeof(DRef));
334 	if(dr == nil)
335 		return;
336 	h = heap(TDisplay);
337 	if(h == H){
338 		closedisplay(display);
339 		return;
340 	}
341 	dd = H2D(DDisplay*, h);
342 	dd->display = display;
343 	*f->ret = &dd->drawdisplay;
344 	dd->dref = dr;
345 	display->limbo = dr;
346 	dr->display = display;
347 	dr->ref = 1;
348 	df = getdefont(display);
349 	if(df){
350 		display->defaultsubfont = df;
351 		sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
352 			df->n-1, deffontname);
353 		display->defaultfont = buildfont(display, buf, deffontname);
354 		if(display->defaultfont){
355 			c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font");
356 			if(c)
357 				c->ref++;
358 			/* else BUG? */
359 		}
360 	}
361 
362 	R2R(r, display->image->r);
363 	dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0);
364 	R2R(r, display->white->r);
365 	dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0);
366 	dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0);
367 	dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0);
368 	dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0);
369 
370 	/* don't call unlockdisplay because the qlock was left up by initdisplay */
371 	libqunlock(display->qlock);
372 }
373 
374 void
375 Display_getwindow(void *fp)
376 {
377 	F_Display_getwindow *f;
378 	Display *disp;
379 	int locked;
380 	Image *image;
381 	Screen *screen;
382 	char *wn;
383 	void *r;
384 
385 	f = fp;
386 	r = f->ret->t0;
387 	f->ret->t0 = H;
388 	destroy(r);
389 	r = f->ret->t1;
390 	f->ret->t1 = H;
391 	destroy(r);
392 	disp = checkdisplay(f->d);
393 	if(f->winname == H)
394 		wn = "/dev/winname";
395 	else
396 		wn = string2c(f->winname);
397 	if(f->image == H)
398 		image = nil;
399 	else
400 		image = checkimage(f->image);
401 	if(f->screen == H)
402 		screen = nil;
403 	else
404 		screen = checkscreen(f->screen);
405 	locked = lockdisplay(disp);
406 	if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){
407 		/* TO DO: eliminate f->image and f->screen's references to Image and Screen */
408 		goto Return;
409 	}
410 	if(screen != nil){
411 		if(f->screen != H){
412 			f->ret->t0 = f->screen;
413 			D2H(f->screen)->ref++;
414 		}else
415 			f->ret->t0 = mkdrawscreen(screen, f->d);
416 	}
417 	if(image != nil){
418 		if(f->image != H){
419 			f->ret->t1 = f->image;
420 			D2H(f->image)->ref++;
421 		}else
422 			f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil);
423 	}
424 
425 Return:
426 	if(locked)
427 		unlockdisplay(disp);
428 }
429 
430 void
431 Display_startrefresh(void *fp)
432 {
433 	F_Display_startrefresh *f;
434 	Display *disp;
435 
436 	f = fp;
437 	disp = checkdisplay(f->d);
438 	refreshslave(disp);
439 }
440 
441 void
442 display_dec(void *v)
443 {
444 	DRef *dr;
445 	Display *d;
446 	int locked;
447 
448 	dr = v;
449 	if(dr->ref-- != 1)
450 		return;
451 
452 	d = dr->display;
453 	locked = lockdisplay(d);
454 	font_close(d->defaultfont);
455 	subfont_close(d->defaultsubfont);
456 	if(locked)
457 		unlockdisplay(d);
458 	freeallsubfonts(d);
459 	closedisplay(d);
460 	free(dr);
461 }
462 
463 void
464 freedrawdisplay(Heap *h, int swept)
465 {
466 	DDisplay *dd;
467 	Display *d;
468 
469 	dd = H2D(DDisplay*, h);
470 
471 	if(!swept) {
472 		destroy(dd->drawdisplay.image);
473 		destroy(dd->drawdisplay.black);
474 		destroy(dd->drawdisplay.white);
475 		destroy(dd->drawdisplay.opaque);
476 		destroy(dd->drawdisplay.transparent);
477 	}
478 	/* we've now released dd->image etc.; make sure they're not freed again */
479 	d = dd->display;
480 	d->image = nil;
481 	d->white = nil;
482 	d->black = nil;
483 	d->opaque = nil;
484 	d->transparent = nil;
485 	display_dec(dd->dref);
486 	/* Draw_Display header will be freed by caller */
487 }
488 
489 void
490 Display_color(void *fp)
491 {
492 	F_Display_color *f;
493 	Display *d;
494 	int locked;
495 
496 	f = fp;
497 	destroy(*f->ret);
498 	*f->ret = H;
499 	d = checkdisplay(f->d);
500 	locked = lockdisplay(d);
501 	*f->ret = color((DDisplay*)f->d, f->color);
502 	if(locked)
503 		unlockdisplay(d);
504 }
505 
506 void
507 Image_flush(void *fp)
508 {
509 	F_Image_flush *f;
510 	Image *d;
511 	DImage *di;
512 	int locked;
513 
514 	f = fp;
515 	d = checkimage(f->win);
516 	di = (DImage*)f->win;
517 	switch(f->func){
518 	case 0:	/* Draw->Flushoff */
519 		di->flush = 0;
520 		break;
521 	case 1:	/* Draw->Flushon */
522 		di->flush = 1;
523 		/* fall through */
524 	case 2:	/* Draw->Flushnow */
525 		locked = lockdisplay(d->display);
526 		if(d->id==0 || d->screen!=0)
527 			flushimage(d->display, 1);
528 		if(locked)
529 			unlockdisplay(d->display);
530 		break;
531 	default:
532 		error(exInval);
533 	}
534 }
535 
536 void
537 checkflush(Draw_Image *dst)
538 {
539 	DImage  *di;
540 
541 	di = (DImage*)dst;
542 	if(di->flush && (di->image->id==0 || di->image->screen!=nil))
543 		flushimage(di->image->display, 1);
544 }
545 
546 static void
547 imagedraw(void *fp, int op)
548 {
549 	F_Image_draw *f;
550 	Image *d, *s, *m;
551 	int locked;
552 
553 	f = fp;
554 	d = checkimage(f->dst);
555 	if(f->src == H)
556 		s = d->display->black;
557 	else
558 		s = checkimage(f->src);
559 	if(f->matte == H)
560 		m = d->display->white;	/* ones */
561 	else
562 		m = checkimage(f->matte);
563 	if(d->display!=s->display || d->display!=m->display)
564 		return;
565 	locked = lockdisplay(d->display);
566 	drawop(d, IRECT(f->r), s, m, IPOINT(f->p), op);
567 	checkflush(f->dst);
568 	if(locked)
569 		unlockdisplay(d->display);
570 }
571 
572 void
573 Image_draw(void *fp)
574 {
575 	imagedraw(fp, SoverD);
576 }
577 
578 void
579 Image_drawop(void *fp)
580 {
581 	F_Image_drawop *f;
582 
583 	f = fp;
584 	imagedraw(fp, f->op);
585 }
586 
587 static void
588 imagegendraw(void *fp, int op)
589 {
590 	F_Image_gendraw *f;
591 	Image *d, *s, *m;
592 	int locked;
593 
594 	f = fp;
595 	d = checkimage(f->dst);
596 	if(f->src == H)
597 		s = d->display->black;
598 	else
599 		s = checkimage(f->src);
600 	if(f->matte == H)
601 		m = d->display->white;	/* ones */
602 	else
603 		m = checkimage(f->matte);
604 	if(d->display!=s->display || d->display!=m->display)
605 		return;
606 	locked = lockdisplay(d->display);
607 	gendrawop(d, IRECT(f->r), s, IPOINT(f->p0), m, IPOINT(f->p1), op);
608 	checkflush(f->dst);
609 	if(locked)
610 		unlockdisplay(d->display);
611 }
612 
613 void
614 Image_gendraw(void *fp)
615 {
616 	imagegendraw(fp, SoverD);
617 }
618 
619 void
620 Image_gendrawop(void *fp)
621 {
622 	F_Image_gendrawop *f;
623 
624 	f = fp;
625 	imagegendraw(fp, f->op);
626 }
627 
628 static void
629 drawline(void *fp, int op)
630 {
631 	F_Image_line *f;
632 	Image *d, *s;
633 	int locked;
634 
635 	f = fp;
636 	d = checkimage(f->dst);
637 	s = checkimage(f->src);
638 	if(d->display != s->display || f->radius < 0)
639 		return;
640 	locked = lockdisplay(d->display);
641 	lineop(d, IPOINT(f->p0), IPOINT(f->p1), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
642 	checkflush(f->dst);
643 	if(locked)
644 		unlockdisplay(d->display);
645 }
646 
647 void
648 Image_line(void *fp)
649 {
650 	drawline(fp, SoverD);
651 }
652 
653 void
654 Image_lineop(void *fp)
655 {
656 	F_Image_lineop *f;
657 
658 	f = fp;
659 	drawline(fp, f->op);
660 }
661 
662 static void
663 drawsplinepoly(void *fp, int smooth, int op)
664 {
665 	F_Image_poly *f;
666 	Image *d, *s;
667 	int locked;
668 
669 	f = fp;
670 	d = checkimage(f->dst);
671 	s = checkimage(f->src);
672 	if(d->display != s->display|| f->radius < 0)
673 		return;
674 	locked = lockdisplay(d->display);
675 	/* sleazy: we know that Draw_Points have same shape as Points */
676 	if(smooth)
677 		bezsplineop(d, (Point*)f->p->data, f->p->len,
678 			f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
679 	else
680 		polyop(d, (Point*)f->p->data, f->p->len, f->end0,
681 			f->end1, f->radius, s, IPOINT(f->sp), op);
682 	checkflush(f->dst);
683 	if(locked)
684 		unlockdisplay(d->display);
685 }
686 
687 void
688 Image_poly(void *fp)
689 {
690 	drawsplinepoly(fp, 0, SoverD);
691 }
692 
693 void
694 Image_polyop(void *fp)
695 {
696 	F_Image_polyop *f;
697 
698 	f = fp;
699 	drawsplinepoly(fp, 0, f->op);
700 }
701 
702 void
703 Image_bezspline(void *fp)
704 {
705 	drawsplinepoly(fp, 1, SoverD);
706 }
707 
708 void
709 Image_bezsplineop(void *fp)
710 {
711 	F_Image_bezsplineop *f;
712 
713 	f = fp;
714 	drawsplinepoly(fp, 1, f->op);
715 }
716 
717 static void
718 drawbezier(void *fp, int op)
719 {
720 	F_Image_bezier *f;
721 	Image *d, *s;
722 	int locked;
723 
724 	f = fp;
725 	d = checkimage(f->dst);
726 	s = checkimage(f->src);
727 	if(d->display != s->display || f->radius < 0)
728 		return;
729 	locked = lockdisplay(d->display);
730 	bezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
731 		  IPOINT(f->d), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
732 	checkflush(f->dst);
733 	if(locked)
734 		unlockdisplay(d->display);
735 }
736 
737 void
738 Image_bezier(void *fp)
739 {
740 	drawbezier(fp, SoverD);
741 }
742 
743 void
744 Image_bezierop(void *fp)
745 {
746 	F_Image_bezierop *f;
747 
748 	f = fp;
749 	drawbezier(fp, f->op);
750 }
751 
752 static void
753 drawfillbezier(void *fp, int op)
754 {
755 	F_Image_fillbezier *f;
756 	Image *d, *s;
757 	int locked;
758 
759 	f = fp;
760 	d = checkimage(f->dst);
761 	s = checkimage(f->src);
762 	if(d->display != s->display)
763 		return;
764 	locked = lockdisplay(d->display);
765 	fillbezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
766 			IPOINT(f->d), f->wind, s, IPOINT(f->sp), op);
767 	checkflush(f->dst);
768 	if(locked)
769 		unlockdisplay(d->display);
770 }
771 
772 void
773 Image_fillbezier(void *fp)
774 {
775 	drawfillbezier(fp, SoverD);
776 }
777 
778 void
779 Image_fillbezierop(void *fp)
780 {
781 	F_Image_fillbezierop *f;
782 
783 	f = fp;
784 	drawfillbezier(fp, f->op);
785 }
786 
787 static void
788 drawfillsplinepoly(void *fp, int smooth, int op)
789 {
790 	F_Image_fillpoly *f;
791 	Image *d, *s;
792 	int locked;
793 
794 	f = fp;
795 	d = checkimage(f->dst);
796 	s = checkimage(f->src);
797 	if(d->display != s->display)
798 		return;
799 	locked = lockdisplay(d->display);
800 	/* sleazy: we know that Draw_Points have same shape as Points */
801 	if(smooth)
802 		fillbezsplineop(d, (Point*)f->p->data, f->p->len,
803 			f->wind, s, IPOINT(f->sp), op);
804 	else
805 		fillpolyop(d, (Point*)f->p->data, f->p->len,
806 			f->wind, s, IPOINT(f->sp), op);
807 	checkflush(f->dst);
808 	if(locked)
809 		unlockdisplay(d->display);
810 }
811 
812 void
813 Image_fillpoly(void *fp)
814 {
815 	drawfillsplinepoly(fp, 0, SoverD);
816 }
817 
818 void
819 Image_fillpolyop(void *fp)
820 {
821 	F_Image_fillpolyop *f;
822 
823 	f = fp;
824 	drawfillsplinepoly(fp, 0, f->op);
825 }
826 
827 void
828 Image_fillbezspline(void *fp)
829 {
830 	drawfillsplinepoly(fp, 1, SoverD);
831 }
832 
833 void
834 Image_fillbezsplineop(void *fp)
835 {
836 	F_Image_fillbezsplineop *f;
837 
838 	f = fp;
839 	drawfillsplinepoly(fp, 1, f->op);
840 }
841 
842 static void
843 drawarcellipse(void *fp, int isarc, int alpha, int phi, int op)
844 {
845 	F_Image_arc *f;
846 	Image *d, *s;
847 	int locked;
848 
849 	f = fp;
850 	d = checkimage(f->dst);
851 	s = checkimage(f->src);
852 	if(d->display != s->display || f->thick < 0 || f->a<0 || f->b<0)
853 		return;
854 
855 	locked = lockdisplay(d->display);
856 	if(isarc)
857 		arcop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
858 			IPOINT(f->sp), alpha, phi, op);
859 	else
860 		ellipseop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
861 			IPOINT(f->sp), op);
862 	checkflush(f->dst);
863 	if(locked)
864 		unlockdisplay(d->display);
865 }
866 
867 void
868 Image_ellipse(void *fp)
869 {
870 	drawarcellipse(fp, 0, 0, 0, SoverD);
871 }
872 
873 void
874 Image_ellipseop(void *fp)
875 {
876 	F_Image_ellipseop *f;
877 
878 	f = fp;
879 	drawarcellipse(fp, 0, 0, 0, f->op);
880 }
881 
882 void
883 Image_arc(void *fp)
884 {
885 	F_Image_arc *f;
886 
887 	f = fp;
888 	drawarcellipse(fp, 1, f->alpha, f->phi, SoverD);
889 }
890 
891 void
892 Image_arcop(void *fp)
893 {
894 	F_Image_arcop *f;
895 
896 	f = fp;
897 	drawarcellipse(fp, 1, f->alpha, f->phi, f->op);
898 }
899 
900 static void
901 drawfillarcellipse(void *fp, int isarc, int alpha, int phi, int op)
902 {
903 	F_Image_fillarc *f;
904 	Image *d, *s;
905 	int locked;
906 
907 	f = fp;
908 	d = checkimage(f->dst);
909 	s = checkimage(f->src);
910 	if(d->display != s->display || f->a<0 || f->b<0)
911 		return;
912 
913 	locked = lockdisplay(d->display);
914 	if(isarc)
915 		fillarcop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), alpha, phi, op);
916 	else
917 		fillellipseop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), op);
918 	checkflush(f->dst);
919 	if(locked)
920 		unlockdisplay(d->display);
921 }
922 
923 void
924 Image_fillellipse(void *fp)
925 {
926 	drawfillarcellipse(fp, 0, 0, 0, SoverD);
927 }
928 
929 void
930 Image_fillellipseop(void *fp)
931 {
932 	F_Image_fillellipseop *f;
933 
934 	f = fp;
935 	drawfillarcellipse(fp, 0, 0, 0, f->op);
936 }
937 
938 void
939 Image_fillarc(void *fp)
940 {
941 	F_Image_fillarc *f;
942 
943 	f = fp;
944 	drawfillarcellipse(fp, 1, f->alpha, f->phi, SoverD);
945 }
946 
947 void
948 Image_fillarcop(void *fp)
949 {
950 	F_Image_fillarcop *f;
951 
952 	f = fp;
953 	drawfillarcellipse(fp, 1, f->alpha, f->phi, f->op);
954 }
955 
956 static void
957 drawtext(void *fp, int op)
958 {
959 	F_Image_text *f;
960 	Font *font;
961 	Point pt;
962 	Image *s, *d;
963 	String *str;
964 	int locked;
965 
966 	f = fp;
967 	if(f->dst == H || f->src == H)
968 		goto Return;
969 	if(f->font == H || f->str == H)
970 		goto Return;
971 	str = f->str;
972 	d = checkimage(f->dst);
973 	s = checkimage(f->src);
974 	font = checkfont(f->font);
975 	if(d->display!=s->display || d->display!=font->display)
976 		return;
977 	locked = lockdisplay(d->display);
978 	if(str->len >= 0)
979 		pt = stringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, op);
980 	else
981 		pt = runestringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, op);
982 	checkflush(f->dst);
983 	if(locked)
984 		unlockdisplay(d->display);
985     Return:
986 	P2P(*f->ret, pt);
987 }
988 
989 void
990 Image_text(void *fp)
991 {
992 	drawtext(fp, SoverD);
993 }
994 
995 void
996 Image_textop(void *fp)
997 {
998 	F_Image_textop *f;
999 
1000 	f = fp;
1001 	drawtext(fp, f->op);
1002 }
1003 
1004 static void
1005 drawtextbg(void *fp, int op)
1006 {
1007 	F_Image_textbg *f;
1008 	Font *font;
1009 	Point pt;
1010 	Image *s, *d, *bg;
1011 	String *str;
1012 	int locked;
1013 
1014 	f = fp;
1015 	if(f->dst == H || f->src == H)
1016 		goto Return;
1017 	if(f->font == H || f->str == H)
1018 		goto Return;
1019 	str = f->str;
1020 	d = checkimage(f->dst);
1021 	s = checkimage(f->src);
1022 	bg = checkimage(f->bg);
1023 	font = checkfont(f->font);
1024 	if(d->display!=s->display || d->display!=font->display)
1025 		return;
1026 	locked = lockdisplay(d->display);
1027 	if(str->len >= 0)
1028 		pt = stringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, bg, IPOINT(f->bgp), op);
1029 	else
1030 		pt = runestringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, bg, IPOINT(f->bgp), op);
1031 	checkflush(f->dst);
1032 	if(locked)
1033 		unlockdisplay(d->display);
1034     Return:
1035 	P2P(*f->ret, pt);
1036 }
1037 
1038 void
1039 Image_textbg(void *fp)
1040 {
1041 	drawtextbg(fp, SoverD);
1042 }
1043 
1044 void
1045 Image_textbgop(void *fp)
1046 {
1047 	F_Image_textbgop *f;
1048 
1049 	f = fp;
1050 	drawtextbg(fp, f->op);
1051 }
1052 
1053 static void
1054 drawborder(void *fp, int op)
1055 {
1056 	F_Image_border *f;
1057 	Image *d, *s;
1058 	int locked;
1059 
1060 	f = fp;
1061 	d = checkimage(f->dst);
1062 	s = checkimage(f->src);
1063 	if(d->display != s->display)
1064 		return;
1065 	locked = lockdisplay(d->display);
1066 	borderop(d, IRECT(f->r), f->i, s, IPOINT(f->sp), op);
1067 	checkflush(f->dst);
1068 	if(locked)
1069 		unlockdisplay(d->display);
1070 }
1071 
1072 void
1073 Image_border(void *fp)
1074 {
1075 	drawborder(fp, SoverD);
1076 }
1077 
1078 void
1079 Display_newimage(void *fp)
1080 {
1081 	F_Display_newimage *f;
1082 	Display *d;
1083 	int locked;
1084 
1085 	f = fp;
1086 	d = checkdisplay(f->d);
1087 	destroy(*f->ret);
1088 	*f->ret = H;
1089 	locked = lockdisplay(d);
1090 	*f->ret = allocdrawimage((DDisplay*)f->d, f->r, f->chans.desc,
1091 				nil, f->repl, f->color);
1092 	if(locked)
1093 		unlockdisplay(d);
1094 }
1095 
1096 void
1097 Display_colormix(void *fp)
1098 {
1099 	F_Display_colormix *f;
1100 	Display *disp;
1101 	Image *i;
1102 	int locked;
1103 
1104 	f = fp;
1105 	destroy(*f->ret);
1106 	*f->ret = H;
1107 	disp = checkdisplay(f->d);
1108 	locked = lockdisplay(disp);
1109 	i = allocimagemix(disp, f->c1, f->c2);
1110 	if(locked)
1111 		unlockdisplay(disp);
1112 	*f->ret = mkdrawimage(i, H, f->d, nil);
1113 }
1114 
1115 void
1116 Image_readpixels(void *fp)
1117 {
1118 	F_Image_readpixels *f;
1119 	Rectangle r;
1120 	Image *i;
1121 	int locked;
1122 
1123 	f = fp;
1124 	R2R(r, f->r);
1125 	i = checkimage(f->src);
1126 	locked = lockdisplay(i->display);
1127 	*f->ret = unloadimage(i, r, f->data->data, f->data->len);
1128 	if(locked)
1129 		unlockdisplay(i->display);
1130 }
1131 
1132 void
1133 Image_writepixels(void *fp)
1134 {
1135 	Rectangle r;
1136 	F_Image_writepixels *f;
1137 	Image *i;
1138 	int locked;
1139 
1140 	f = fp;
1141 	R2R(r, f->r);
1142 	i = checkimage(f->dst);
1143 	locked = lockdisplay(i->display);
1144 	*f->ret = loadimage(i, r, f->data->data, f->data->len);
1145 	checkflush(f->dst);
1146 	if(locked)
1147 		unlockdisplay(i->display);
1148 }
1149 
1150 void
1151 Image_arrow(void *fp)
1152 {
1153 	F_Image_arrow *f;
1154 
1155 	f = fp;
1156 	*f->ret = ARROW(f->a, f->b, f->c);
1157 }
1158 
1159 void
1160 Image_name(void *fp)
1161 {
1162 	F_Image_name *f;
1163 	Image *i;
1164 	int locked, ok;
1165 	char *name;
1166 
1167 	f = fp;
1168 	*f->ret = -1;
1169 	i = checkimage(f->src);
1170 	name = string2c(f->name);
1171 	locked = lockdisplay(i->display);
1172 	*f->ret = ok = nameimage(i, name, f->in);
1173 	if(locked)
1174 		unlockdisplay(i->display);
1175 	if(ok){
1176 		destroy(f->src->iname);
1177 		if(f->in){
1178 			f->src->iname = f->name;
1179 			D2H(f->name)->ref++;
1180 		}else
1181 			f->src->iname = H;
1182 	}
1183 }
1184 
1185 Image*
1186 display_open(Display *disp, char *name)
1187 {
1188 	Image *i;
1189 	int fd;
1190 
1191 	fd = libopen(name, OREAD);
1192 	if(fd < 0)
1193 		return nil;
1194 
1195 	i = readimage(disp, fd, 1);
1196 	libclose(fd);
1197 	return i;
1198 }
1199 
1200 void
1201 Display_open(void *fp)
1202 {
1203 	Image *i;
1204 	Display *disp;
1205 	F_Display_open *f;
1206 
1207 	f = fp;
1208 	destroy(*f->ret);
1209 	*f->ret = H;
1210 	disp = lookupdisplay(f->d);
1211 	if(disp == nil)
1212 		return;
1213 	i = display_open(disp, string2c(f->name));
1214 	if(i == nil)
1215 		return;
1216 	*f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
1217 }
1218 
1219 void
1220 Display_namedimage(void *fp)
1221 {
1222 	F_Display_namedimage *f;
1223 	Display *d;
1224 	Image *i;
1225 	Draw_Image *di;
1226 	int locked;
1227 
1228 	f = fp;
1229 	destroy(*f->ret);
1230 	*f->ret = H;
1231 	d = checkdisplay(f->d);
1232 	locked = lockdisplay(d);
1233 	i = namedimage(d, string2c(f->name));
1234 	if(locked)
1235 		unlockdisplay(d);
1236 	if(i == nil)
1237 		return;
1238 	di =  allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, i->repl, 0);
1239 	*f->ret = di;
1240 	if(di == H){
1241 		locked = lockdisplay(d);
1242 		freeimage(i);
1243 		if(locked)
1244 			unlockdisplay(d);
1245 	}else{
1246 		di->iname = f->name;
1247 		D2H(f->name)->ref++;
1248 	}
1249 }
1250 
1251 void
1252 Display_readimage(void *fp)
1253 {
1254 	Image *i;
1255 	Display *disp;
1256 	F_Display_readimage *f;
1257 	Sys_FD *fd;
1258 	int locked;
1259 
1260 	f = fp;
1261 	destroy(*f->ret);
1262 	*f->ret = H;
1263 	fd = f->fd;
1264 	if(fd == H)
1265 		return;
1266 	disp = checkdisplay(f->d);
1267 	i = readimage(disp, fd->fd, 1);
1268 	if(i == nil)
1269 		return;
1270 	*f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
1271 	if(*f->ret == H){
1272 		locked = lockdisplay(disp);
1273 		freeimage(i);
1274 		if(locked)
1275 			unlockdisplay(disp);
1276 	}
1277 }
1278 
1279 void
1280 Display_writeimage(void *fp)
1281 {
1282 	Image *i;
1283 	F_Display_writeimage *f;
1284 	Sys_FD *fd;
1285 
1286 	f = fp;
1287 	*f->ret = -1;
1288 	fd = f->fd;
1289 	if(fd == H)
1290 		return;
1291 	i = checkimage(f->i);
1292 	if(checkdisplay(f->d) != i->display)
1293 		return;
1294 	*f->ret = writeimage(fd->fd, i, 1);	/* TO DO: dolock? */
1295 }
1296 
1297 Draw_Screen*
1298 mkdrawscreen(Screen *s, Draw_Display *display)
1299 {
1300 	Heap *h;
1301 	DScreen *ds;
1302 	Draw_Image *dimage, *dfill;
1303 
1304 	dimage = mkdrawimage(s->image, H, display, nil);
1305 	dfill = mkdrawimage(s->fill, H, display, nil);
1306 	h = heap(TScreen);
1307 	if(h == H)
1308 		return nil;
1309 	ds = H2D(DScreen*, h);
1310 	ds->screen = s;
1311 	ds->drawscreen.fill = dfill;
1312 	D2H(dfill)->ref++;
1313 	ds->drawscreen.image = dimage;
1314 	D2H(dimage)->ref++;
1315 	ds->drawscreen.display = dimage->display;
1316 	D2H(dimage->display)->ref++;
1317 	ds->drawscreen.id = s->id;
1318 	ds->dref = s->display->limbo;
1319 	ds->dref->ref++;
1320 	return &ds->drawscreen;
1321 }
1322 
1323 static DScreen*
1324 allocdrawscreen(Draw_Image *dimage, Draw_Image *dfill, int public)
1325 {
1326 	Heap *h;
1327 	Screen *s;
1328 	DScreen *ds;
1329 	Image *image, *fill;
1330 
1331 	image = ((DImage*)dimage)->image;
1332 	fill = ((DImage*)dfill)->image;
1333 	s = allocscreen(image, fill, public);
1334 	if(s == 0)
1335 		return nil;
1336 	h = heap(TScreen);
1337 	if(h == H)
1338 		return nil;
1339 	ds = H2D(DScreen*, h);
1340 	ds->screen = s;
1341 	ds->drawscreen.fill = dfill;
1342 	D2H(dfill)->ref++;
1343 	ds->drawscreen.image = dimage;
1344 	D2H(dimage)->ref++;
1345 	ds->drawscreen.display = dimage->display;
1346 	D2H(dimage->display)->ref++;
1347 	ds->drawscreen.id = s->id;
1348 	ds->dref = image->display->limbo;
1349 	ds->dref->ref++;
1350 	return ds;
1351 }
1352 
1353 void
1354 Screen_allocate(void *fp)
1355 {
1356 	F_Screen_allocate *f;
1357 	DScreen *ds;
1358 	Image *image;
1359 	int locked;
1360 
1361 	f = fp;
1362 	destroy(*f->ret);
1363 	*f->ret = H;
1364 	image = checkimage(f->image);
1365 	checkimage(f->fill);
1366 	locked = lockdisplay(image->display);
1367 	ds = allocdrawscreen(f->image, f->fill, f->public);
1368 	if(ds != nil)
1369 		*f->ret = &ds->drawscreen;
1370 	if(locked)
1371 		unlockdisplay(image->display);
1372 }
1373 
1374 void
1375 Display_publicscreen(void *fp)
1376 {
1377 	F_Display_publicscreen *f;
1378 	Heap *h;
1379 	Screen *s;
1380 	DScreen *ds;
1381 	Display *disp;
1382 	int locked;
1383 
1384 	f = fp;
1385 	destroy(*f->ret);
1386 	*f->ret = H;
1387 	disp = checkdisplay(f->d);
1388 	locked = lockdisplay(disp);
1389 	s = publicscreen(disp, f->id, disp->image->chan);
1390 	if(locked)
1391 		unlockdisplay(disp);
1392 	if(s == nil)
1393 		return;
1394 	h = heap(TScreen);
1395 	if(h == H)
1396 		return;
1397 	ds = H2D(DScreen*, h);
1398 	ds->screen = s;
1399 	ds->drawscreen.fill = H;
1400 	ds->drawscreen.image =H;
1401 	ds->drawscreen.id = s->id;
1402 	ds->drawscreen.display = f->d;
1403 	D2H(f->d)->ref++;
1404 	ds->dref = disp->limbo;
1405 	ds->dref->ref++;
1406 	*f->ret = &ds->drawscreen;
1407 }
1408 
1409 void
1410 freedrawscreen(Heap *h, int swept)
1411 {
1412 	DScreen *ds;
1413 	Screen *s;
1414 	Display *disp;
1415 	int locked;
1416 
1417 	ds = H2D(DScreen*, h);
1418 	if(!swept) {
1419 		destroy(ds->drawscreen.image);
1420 		destroy(ds->drawscreen.fill);
1421 		destroy(ds->drawscreen.display);
1422 	}
1423 	s = lookupscreen(&ds->drawscreen);
1424 	if(s == nil){
1425 		if(!swept)
1426 			freeptrs(ds, TScreen);
1427 		return;
1428 	}
1429 	disp = s->display;
1430 	locked = lockdisplay(disp);
1431 	freescreen(s);
1432 	if(locked)
1433 		unlockdisplay(disp);
1434 	display_dec(ds->dref);
1435 	/* screen header will be freed by caller */
1436 }
1437 
1438 void
1439 Font_build(void *fp)
1440 {
1441 	F_Font_build *f;
1442 	Font *font;
1443 	DFont *dfont;
1444 	Heap *h;
1445 	char buf[128];
1446 	char *name, *data;
1447 	Subfont *df;
1448 	Display *disp;
1449 	int locked;
1450 
1451 	f = fp;
1452 	destroy(*f->ret);
1453 	*f->ret = H;
1454 	disp = checkdisplay(f->d);
1455 
1456 	name = string2c(f->name);
1457 	font = font_open(disp, name);
1458 	if(font == nil) {
1459 		if(strcmp(name, deffontname) == 0) {
1460 			df = disp->defaultsubfont;
1461 			sprint(buf, "%d %d\n0 %d\t%s\n",
1462 				df->height, df->ascent, df->n-1, name);
1463 			data = buf;
1464 		}
1465 		else
1466 		if(f->desc == H)
1467 			return;
1468 		else
1469 			data = string2c(f->desc);
1470 
1471 		locked = lockdisplay(disp);
1472 		font = buildfont(disp, data, name);
1473 		if(locked)
1474 			unlockdisplay(disp);
1475 		if(font == nil)
1476 			return;
1477 	}
1478 
1479 	h = heap(TFont);
1480 	if(h == H)
1481 		return;
1482 
1483 	dfont = H2D(DFont*, h);
1484 	dfont->font = font;
1485 	dfont->drawfont.name = f->name;
1486 	D2H(f->name)->ref++;
1487 	dfont->drawfont.height = font->height;
1488 	dfont->drawfont.ascent = font->ascent;
1489 	dfont->drawfont.display = f->d;
1490 	D2H(f->d)->ref++;
1491 	dfont->dref = disp->limbo;
1492 	dfont->dref->ref++;
1493 
1494 	*f->ret = &dfont->drawfont;
1495 }
1496 
1497 Font*
1498 font_open(Display *display, char *name)
1499 {
1500 	Cache *c;
1501 	Font *font;
1502 	int locked;
1503 
1504 	c = cachelookup(fcache, display, name);
1505 	if(c)
1506 		font = c->u.f;
1507 	else {
1508 		locked = lockdisplay(display);
1509 		font = openfont(display, name);
1510 		if(locked)
1511 			unlockdisplay(display);
1512 		if(font == nil)
1513 			return nil;
1514 		c = cacheinstall(fcache, display, name, font, "font");
1515 	}
1516 	if(c)
1517 		c->ref++;
1518 
1519 	return font;
1520 }
1521 
1522 void
1523 font_close(Font *f)
1524 {
1525 	Cache *c;
1526 	Display *disp;
1527 	int locked;
1528 	disp = f->display;
1529 	if(f->name == nil)
1530 		return;
1531 
1532 	/* fonts from Font_build() aren't always in fcache, but we still need to free them */
1533 	c = cachelookup(fcache, disp, f->name);
1534 	if(c != nil && f == c->u.f) {
1535 		if(c->ref <= 0)
1536 			return;
1537 		if(c->ref-- != 1)
1538 			return;
1539 		cacheuninstall(fcache, disp, f->name, "font");
1540 	}
1541 
1542 	locked = lockdisplay(disp);
1543 	freefont(f);
1544 	if(locked)
1545 		unlockdisplay(disp);
1546 }
1547 
1548 void
1549 freecachedsubfont(Subfont *sf)
1550 {
1551 	Cache *c;
1552 	Display *disp;
1553 
1554 	disp = sf->bits->display;
1555 	c = cachelookup(sfcache, disp, sf->name);
1556 	if(c == nil){
1557 		fprint(2, "subfont %s not cached\n", sf->name);
1558 		return;
1559 	}
1560 	if(c->ref > 0)
1561 		c->ref--;
1562 	/* if ref is zero, we leave it around for later harvesting by freeallsubfonts */
1563 }
1564 
1565 void
1566 freeallsubfonts(Display *d)
1567 {
1568 	int i;
1569 	Cache *c, *prev, *o;
1570 	Subfont *sf;
1571 	int locked;
1572 	if(cacheqlock == nil)	/* may not have allocated anything yet */
1573 		return;
1574 	libqlock(cacheqlock);
1575 	for(i=0; i<BIHASH; i++){
1576 		c = sfcache[i];
1577 		prev = 0;
1578 		while(c != nil){
1579 			if(c->ref==0 && (d==nil || c->display==d)){
1580 				if(prev == 0)
1581 					sfcache[i] = c->next;
1582 				else
1583 					prev->next = c->next;
1584 				free(c->name);
1585 				sf = c->u.sf;
1586 				if(--sf->ref==0){
1587 					free(sf->info);
1588 					locked = lockdisplay(c->display);
1589 					freeimage(sf->bits);
1590 					if(locked)
1591 						unlockdisplay(c->display);
1592 					free(sf);
1593 				}
1594 				o = c;
1595 				c = c->next;
1596 				free(o);
1597 			}else{
1598 				prev = c;
1599 				c = c->next;
1600 			}
1601 		}
1602 	}
1603 	libqunlock(cacheqlock);
1604 }
1605 
1606 void
1607 subfont_close(Subfont *sf)
1608 {
1609 	freecachedsubfont(sf);
1610 }
1611 
1612 void
1613 freesubfont(Subfont *sf)
1614 {
1615 	freecachedsubfont(sf);
1616 }
1617 
1618 void
1619 Font_open(void *fp)
1620 {
1621 	Heap *h;
1622 	Font *font;
1623 	Display *disp;
1624 	DFont *df;
1625 	F_Font_open *f;
1626 
1627 	f = fp;
1628 
1629 	destroy(*f->ret);
1630 	*f->ret = H;
1631 	disp = checkdisplay(f->d);
1632 
1633 	font = font_open(disp, string2c(f->name));
1634 	if(font == 0)
1635 		return;
1636 
1637 	h = heap(TFont);
1638 	if(h == H)
1639 		return;
1640 
1641 	df = H2D(DFont*, h);
1642 	df->font = font;
1643 	df->drawfont.name = f->name;
1644 	D2H(f->name)->ref++;
1645 	df->drawfont.height = font->height;
1646 	df->drawfont.ascent = font->ascent;
1647 	df->drawfont.display = f->d;
1648 	D2H(f->d)->ref++;
1649 	df->dref = disp->limbo;
1650 	df->dref->ref++;
1651 	*f->ret = &df->drawfont;
1652 }
1653 
1654 void
1655 Font_width(void *fp)
1656 {
1657 	F_Font_width *f;
1658 	Font *font;
1659 	char *s;
1660 	int locked;
1661 
1662 	f = fp;
1663 	s = string2c(f->str);
1664 	if(f->f == H || s[0]=='\0')
1665 		*f->ret = 0;
1666 	else{
1667 		font = checkfont(f->f);
1668 		locked = lockdisplay(font->display);
1669 		*f->ret = stringwidth(font, s);
1670 		if(locked)
1671 			unlockdisplay(font->display);
1672 	}
1673 }
1674 
1675 void
1676 Font_bbox(void *fp)
1677 {
1678 	F_Font_bbox *f;
1679 	Draw_Rect *ret;
1680 
1681 	/* place holder for the real thing */
1682 	f = fp;
1683 	ret = f->ret;
1684 	ret->min.x = ret->min.y = 0;
1685 	ret->max.x = ret->max.y = 0;
1686 }
1687 
1688 /*
1689  * BUG: would be nice if this cached the whole font.
1690  * Instead only the subfonts are cached and the fonts are
1691  * freed when released.
1692  */
1693 void
1694 freedrawfont(Heap*h, int swept)
1695 {
1696 	Draw_Font *d;
1697 	Font *f;
1698 	d = H2D(Draw_Font*, h);
1699 	f = lookupfont(d);
1700 	if(!swept) {
1701 		destroy(d->name);
1702 		destroy(d->display);
1703 	}
1704 	font_close(f);
1705 	display_dec(((DFont*)d)->dref);
1706 }
1707 
1708 void
1709 Chans_text(void *fp)
1710 {
1711 	F_Chans_text *f;
1712 	char buf[16];
1713 
1714 	f = fp;
1715 	destroy(*f->ret);
1716 	*f->ret = H;
1717 	if(chantostr(buf, f->c.desc) != nil)
1718 		retstr(buf, f->ret);
1719 }
1720 
1721 void
1722 Chans_depth(void *fp)
1723 {
1724 	F_Chans_depth *f;
1725 
1726 	f = fp;
1727 	*f->ret = chantodepth(f->c.desc);
1728 }
1729 
1730 void
1731 Chans_eq(void *fp)
1732 {
1733 	F_Chans_eq *f;
1734 
1735 	f = fp;
1736 	*f->ret = f->c.desc == f->d.desc;
1737 }
1738 
1739 void
1740 Chans_mk(void *fp)
1741 {
1742 	F_Chans_mk *f;
1743 
1744 	f = fp;
1745 	f->ret->desc = strtochan(string2c(f->s));
1746 }
1747 
1748 void
1749 Display_rgb(void *fp)
1750 {
1751 	ulong c;
1752 	Display *disp;
1753 	F_Display_rgb *f;
1754 	int locked;
1755 	void *r;
1756 
1757 	f = fp;
1758 	r = *f->ret;
1759 	*f->ret = H;
1760 	destroy(r);
1761 	disp = checkdisplay(f->d);
1762 
1763 	c = ((f->r&255)<<24)|((f->g&255)<<16)|((f->b&255)<<8)|0xFF;
1764 
1765 	locked = lockdisplay(disp);
1766 	*f->ret = color((DDisplay*)f->d, c);
1767 	if(locked)
1768 		unlockdisplay(disp);
1769 }
1770 
1771 void
1772 Display_rgb2cmap(void *fp)
1773 {
1774 	F_Display_rgb2cmap *f;
1775 
1776 	f = fp;
1777 	/* f->display is unused, but someday may have color map */
1778 	*f->ret = rgb2cmap(f->r, f->g, f->b);
1779 }
1780 
1781 void
1782 Display_cmap2rgb(void *fp)
1783 {
1784 	F_Display_cmap2rgb *f;
1785 	ulong c;
1786 
1787 	f = fp;
1788 	/* f->display is unused, but someday may have color map */
1789 	c = cmap2rgb(f->c);
1790 	f->ret->t0 = (c>>16)&0xFF;
1791 	f->ret->t1 = (c>>8)&0xFF;
1792 	f->ret->t2 = (c>>0)&0xFF;
1793 }
1794 
1795 void
1796 Display_cmap2rgba(void *fp)
1797 {
1798 	F_Display_cmap2rgba *f;
1799 
1800 	f = fp;
1801 	/* f->display is unused, but someday may have color map */
1802 	*f->ret = cmap2rgba(f->c);
1803 }
1804 
1805 void
1806 Draw_setalpha(void *fp)
1807 {
1808 	F_Draw_setalpha *f;
1809 
1810 	f = fp;
1811 	*f->ret = setalpha(f->c, f->a);
1812 }
1813 
1814 void
1815 Draw_icossin(void *fp)
1816 {
1817 	F_Draw_icossin *f;
1818 	int s, c;
1819 
1820 	f = fp;
1821 	icossin(f->deg, &s, &c);
1822 	f->ret->t0 = s;
1823 	f->ret->t1 = c;
1824 }
1825 
1826 void
1827 Draw_icossin2(void *fp)
1828 {
1829 	F_Draw_icossin2 *f;
1830 	int s, c;
1831 
1832 	f = fp;
1833 	icossin2(f->p.x, f->p.y, &s, &c);
1834 	f->ret->t0 = s;
1835 	f->ret->t1 = c;
1836 }
1837 
1838 void
1839 Draw_bytesperline(void *fp)
1840 {
1841 	F_Draw_bytesperline *f;
1842 
1843 	f = fp;
1844 	*f->ret = bytesperline(IRECT(f->r), f->d);
1845 }
1846 
1847 Draw_Image*
1848 color(DDisplay *dd, ulong color)
1849 {
1850 	int c;
1851 	Draw_Rect r;
1852 
1853 	r.min.x = 0;
1854 	r.min.y = 0;
1855 	r.max.x = 1;
1856 	r.max.y = 1;
1857 	c = (color&0xff) == 0xff ? RGB24: RGBA32;
1858 	return allocdrawimage(dd, r, c, nil, 1, color);
1859 }
1860 
1861 Draw_Image*
1862 mkdrawimage(Image *i, Draw_Screen *screen, Draw_Display *display, void *ref)
1863 {
1864 	Heap *h;
1865 	DImage *di;
1866 
1867 	h = heap(TImage);
1868 	if(h == H)
1869 		return H;
1870 
1871 	di = H2D(DImage*, h);
1872 	di->image = i;
1873 	di->drawimage.screen = screen;
1874 	if(screen != H)
1875 		D2H(screen)->ref++;
1876 	di->drawimage.display = display;
1877 	if(display != H)
1878 		D2H(display)->ref++;
1879 	di->refreshptr = ref;
1880 
1881 	R2R(di->drawimage.r, i->r);
1882 	R2R(di->drawimage.clipr, i->clipr);
1883 	di->drawimage.chans.desc = i->chan;
1884 	di->drawimage.depth = i->depth;
1885 	di->drawimage.repl = i->repl;
1886 	di->flush = 1;
1887 	di->dref = i->display->limbo;
1888 	di->dref->ref++;
1889 	return &di->drawimage;
1890 }
1891 
1892 void
1893 Screen_newwindow(void *fp)
1894 {
1895 	F_Screen_newwindow *f;
1896 	Image *i;
1897 	Screen *s;
1898 	Rectangle r;
1899 	int locked;
1900 	void *v;
1901 
1902 	f = fp;
1903 	s = checkscreen(f->screen);
1904 	R2R(r, f->r);
1905 
1906 	if(f->backing != Refnone && f->backing != Refbackup)
1907 		f->backing = Refbackup;
1908 
1909 	v = *f->ret;
1910 	*f->ret = H;
1911 	destroy(v);
1912 
1913 	locked = lockdisplay(s->display);
1914 	i = allocwindow(s, r, f->backing, f->color);
1915 	if(locked)
1916 		unlockdisplay(s->display);
1917 	if(i == nil)
1918 		return;
1919 
1920 	*f->ret = mkdrawimage(i, f->screen, f->screen->display, 0);
1921 }
1922 
1923 static
1924 void
1925 screentopbot(Draw_Screen *screen, Array *array, void (*topbot)(Image **, int))
1926 {
1927 	Screen *s;
1928 	Draw_Image **di;
1929 	Image **ip;
1930 	int i, n, locked;
1931 
1932 	s = checkscreen(screen);
1933 	di = (Draw_Image**)array->data;
1934 	ip = malloc(array->len * sizeof(Image*));
1935 	if(ip == nil)
1936 		return;
1937 	n = 0;
1938 	for(i=0; i<array->len; i++)
1939 		if(di[i] != H){
1940 			ip[n] = lookupimage(di[i]);
1941 			if(ip[n]==nil || ip[n]->screen != s){
1942 				free(ip);
1943 				return;
1944 			}
1945 			n++;
1946 		}
1947 	if(n == 0){
1948 		free(ip);
1949 		return;
1950 	}
1951 	locked = lockdisplay(s->display);
1952 	(*topbot)(ip, n);
1953 	free(ip);
1954 	flushimage(s->display, 1);
1955 	if(locked)
1956 		unlockdisplay(s->display);
1957 }
1958 
1959 void
1960 Screen_top(void *fp)
1961 {
1962 	F_Screen_top *f;
1963 	f = fp;
1964 	screentopbot(f->screen, f->wins, topnwindows);
1965 }
1966 
1967 void
1968 Screen_bottom(void *fp)
1969 {
1970 	F_Screen_top *f;
1971 	f = fp;
1972 	screentopbot(f->screen, f->wins, bottomnwindows);
1973 }
1974 
1975 void
1976 freedrawimage(Heap *h, int swept)
1977 {
1978 	Image *i;
1979 	int locked;
1980 	Display *disp;
1981 	Draw_Image *d;
1982 
1983 	d = H2D(Draw_Image*, h);
1984 	i = lookupimage(d);
1985 	if(i == nil) {
1986 		if(!swept)
1987 			freeptrs(d, TImage);
1988 		return;
1989 	}
1990 	disp = i->display;
1991 	locked = lockdisplay(disp);
1992 	freeimage(i);
1993 	if(locked)
1994 		unlockdisplay(disp);
1995 	display_dec(((DImage*)d)->dref);
1996 	/* image/layer header will be freed by caller */
1997 }
1998 
1999 void
2000 Image_top(void *fp)
2001 {
2002 	F_Image_top *f;
2003 	Image *i;
2004 	int locked;
2005 
2006 	f = fp;
2007 	i = checkimage(f->win);
2008 	locked = lockdisplay(i->display);
2009 	topwindow(i);
2010 	flushimage(i->display, 1);
2011 	if(locked)
2012 		unlockdisplay(i->display);
2013 }
2014 
2015 void
2016 Image_origin(void *fp)
2017 {
2018 	F_Image_origin *f;
2019 	Image *i;
2020 	int locked;
2021 
2022 	f = fp;
2023 	i = checkimage(f->win);
2024 	locked = lockdisplay(i->display);
2025 	if(originwindow(i, IPOINT(f->log), IPOINT(f->scr)) < 0)
2026 		*f->ret = -1;
2027 	else{
2028 		f->win->r = DRECT(i->r);
2029 		f->win->clipr = DRECT(i->clipr);
2030 		*f->ret = 1;
2031 	}
2032 	if(locked)
2033 		unlockdisplay(i->display);
2034 }
2035 
2036 void
2037 Image_bottom(void *fp)
2038 {
2039 	F_Image_top *f;
2040 	Image *i;
2041 	int locked;
2042 
2043 	f = fp;
2044 	i = checkimage(f->win);
2045 	locked = lockdisplay(i->display);
2046 	bottomwindow(i);
2047 	flushimage(i->display, 1);
2048 	if(locked)
2049 		unlockdisplay(i->display);
2050 }
2051 
2052 Draw_Image*
2053 allocdrawimage(DDisplay *ddisplay, Draw_Rect r, ulong chan, Image *iimage, int repl, int color)
2054 {
2055 	Heap *h;
2056 	DImage *di;
2057 	Rectangle rr;
2058 	Image *image;
2059 
2060 	image = iimage;
2061 	if(iimage == nil){
2062 		R2R(rr, r);
2063 		image = allocimage(ddisplay->display, rr, chan, repl, color);
2064 		if(image == nil)
2065 			return H;
2066 	}
2067 
2068 	h = heap(TImage);
2069 	if(h == H){
2070 		if(iimage == nil)
2071 			freeimage(image);
2072 		return H;
2073 	}
2074 
2075 	di = H2D(DImage*, h);
2076 	di->drawimage.r = r;
2077 	R2R(di->drawimage.clipr, image->clipr);
2078 	di->drawimage.chans.desc = chan;
2079 	di->drawimage.depth = chantodepth(chan);
2080 	di->drawimage.repl = repl;
2081 	di->drawimage.display = (Draw_Display*)ddisplay;
2082 	D2H(di->drawimage.display)->ref++;
2083 	di->drawimage.screen = H;
2084 	di->dref = ddisplay->display->limbo;
2085 	di->dref->ref++;
2086 	di->image = image;
2087 	di->refreshptr = 0;
2088 	di->flush = 1;
2089 
2090 	return &di->drawimage;
2091 }
2092 
2093 /*
2094  * Entry points called from the draw library
2095  */
2096 Subfont*
2097 lookupsubfont(Display *d, char *name)
2098 {
2099 	Cache *c;
2100 
2101 	c = cachelookup(sfcache, d, name);
2102 	if(c == nil)
2103 		return nil;
2104 	/*c->u.sf->ref++;*/	/* TO DO: need to revisit the reference counting */
2105 	return c->u.sf;
2106 }
2107 
2108 void
2109 installsubfont(char *name, Subfont *subfont)
2110 {
2111 	Cache *c;
2112 
2113 	c = cacheinstall(sfcache, subfont->bits->display, name, subfont, "subfont");
2114 	if(c)
2115 		c->ref++;
2116 }
2117 
2118 /*
2119  * BUG version
2120  */
2121 char*
2122 subfontname(char *cfname, char *fname, int maxdepth)
2123 {
2124 	char *t, *u, tmp1[256], tmp2[256];
2125 	int i, fd;
2126 
2127 	if(strcmp(cfname, deffontname) == 0)
2128 		return strdup(cfname);
2129 	t = cfname;
2130 	if(t[0] != '/'){
2131 		strcpy(tmp2, fname);
2132 		u = utfrrune(tmp2, '/');
2133 		if(u)
2134 			u[0] = 0;
2135 		else
2136 			strcpy(tmp2, ".");
2137 		snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
2138 		t = tmp1;
2139 	}
2140 
2141 	if(maxdepth > 8)
2142 		maxdepth = 8;
2143 
2144 	for(i=3; i>=0; i--){
2145 		if((1<<i) > maxdepth)
2146 			continue;
2147 		/* try i-bit grey */
2148 		snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
2149 		fd = libopen(tmp2, OREAD);
2150 		if(fd >= 0){
2151 			libclose(fd);
2152 			return strdup(tmp2);
2153 		}
2154 	}
2155 
2156 	return strdup(t);
2157 }
2158 
2159 void
2160 refreshslave(Display *d)
2161 {
2162 	int i, n, id;
2163 	uchar buf[5*(5*4)], *p;
2164 	Rectangle r;
2165 	Image *im;
2166 	int locked;
2167 
2168 	for(;;){
2169 		release();
2170 		n = kchanio(d->refchan, buf, sizeof buf, OREAD);
2171 		acquire();
2172 		if(n < 0)	/* probably caused by closedisplay() closing refchan */
2173 			return;	/* will fall off end of thread and close down */
2174 		locked = lockdisplay(d);
2175 		p = buf;
2176 		for(i=0; i<n; i+=5*4,p+=5*4){
2177 			id = BGLONG(p+0*4);
2178 			r.min.x = BGLONG(p+1*4);
2179 			r.min.y = BGLONG(p+2*4);
2180 			r.max.x = BGLONG(p+3*4);
2181 			r.max.y = BGLONG(p+4*4);
2182 			for(im=d->windows; im; im=im->next)
2183 				if(im->id == id)
2184 					break;
2185 			if(im && im->screen && im->reffn)
2186 				(*im->reffn)(im, r, im->refptr);
2187 		}
2188 		flushimage(d, 1);
2189 		if(locked)
2190 			unlockdisplay(d);
2191 	}
2192 }
2193 
2194 void
2195 startrefresh(Display *disp)
2196 {
2197 	USED(disp);
2198 }
2199 
2200 static
2201 int
2202 doflush(Display *d)
2203 {
2204 	int m, n;
2205 	char err[ERRMAX];
2206 	uchar *tp;
2207 
2208 	n = d->bufp-d->buf;
2209 	if(n <= 0)
2210 		return 1;
2211 
2212 	if(d->local == 0)
2213 		release();
2214 	if((m = kchanio(d->datachan, d->buf, n, OWRITE)) != n){
2215 		if(d->local == 0)
2216 			acquire();
2217 		kgerrstr(err, sizeof err);
2218 		if(_drawdebug || strcmp(err, "screen id in use") != 0 && strcmp(err, exImage) != 0){
2219 			print("flushimage fail: (%d not %d) d=%lux: %s\nbuffer: ", m, n, (ulong)d, err);
2220 			for(tp = d->buf; tp < d->bufp; tp++)
2221 				print("%.2x ", (int)*tp);
2222 			print("\n");
2223 		}
2224 		d->bufp = d->buf;	/* might as well; chance of continuing */
2225 		return -1;
2226 	}
2227 	d->bufp = d->buf;
2228 	if(d->local == 0)
2229 		acquire();
2230 	return 1;
2231 }
2232 
2233 int
2234 flushimage(Display *d, int visible)
2235 {
2236 	int ret;
2237 	Refreshq *r;
2238 
2239 	for(;;){
2240 		if(visible)
2241 			*d->bufp++ = 'v';	/* one byte always reserved for this */
2242 		ret = doflush(d);
2243 		if(d->refhead == nil)
2244 			break;
2245 		while(r = d->refhead){	/* assign = */
2246 			d->refhead = r->next;
2247 			if(d->refhead == nil)
2248 				d->reftail = nil;
2249 			r->reffn(nil, r->r, r->refptr);
2250 			free(r);
2251 		}
2252 	}
2253 	return ret;
2254 }
2255 
2256 /*
2257  * Turn off refresh for this window and remove any pending refresh events for it.
2258  */
2259 void
2260 delrefresh(Image *i)
2261 {
2262 	Refreshq *r, *prev, *next;
2263 	int locked;
2264 	Display *d;
2265 	void *refptr;
2266 
2267 	d = i->display;
2268 	/*
2269 	 * Any refresh function will do, because the data pointer is nil.
2270 	 * Can't use nil, though, because that turns backing store back on.
2271 	 */
2272 	if(d->local)
2273 		drawlsetrefresh(d->dataqid, i->id, memlnorefresh, nil);
2274 	refptr = i->refptr;
2275 	i->refptr = nil;
2276 	if(d->refhead==nil || refptr==nil)
2277 		return;
2278 	locked = lockdisplay(d);
2279 	prev = nil;
2280 	for(r=d->refhead; r; r=next){
2281 		next = r->next;
2282 		if(r->refptr == refptr){
2283 			if(prev)
2284 				prev->next = next;
2285 			else
2286 				d->refhead = next;
2287 			if(d->reftail == r)
2288 				d->reftail = prev;
2289 			free(r);
2290 		}else
2291 			prev = r;
2292 	}
2293 	if(locked)
2294 		unlockdisplay(d);
2295 }
2296 
2297 void
2298 queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr)
2299 {
2300 	Display *d;
2301 	Refreshq *rq;
2302 
2303 	d = i->display;
2304 	rq = malloc(sizeof(Refreshq));
2305 	if(rq == nil)
2306 		return;
2307 	if(d->reftail)
2308 		d->reftail->next = rq;
2309 	else
2310 		d->refhead = rq;
2311 	d->reftail = rq;
2312 	rq->reffn = reffn;
2313 	rq->refptr = refptr;
2314 	rq->r = r;
2315 }
2316 
2317 uchar*
2318 bufimage(Display *d, int n)
2319 {
2320 	uchar *p;
2321 
2322 	if(n<0 || n>Displaybufsize){
2323 		kwerrstr("bad count in bufimage");
2324 		return 0;
2325 	}
2326 	if(d->bufp+n > d->buf+Displaybufsize){
2327 		if(d->local==0 && currun()!=libqlowner(d->qlock)) {
2328 			print("bufimage: %lux %lux\n", (ulong)libqlowner(d->qlock), (ulong)currun());
2329 			abort();
2330 		}
2331 		if(doflush(d) < 0)
2332 			return 0;
2333 	}
2334 	p = d->bufp;
2335 	d->bufp += n;
2336 	/* return with buffer locked */
2337 	return p;
2338 }
2339 
2340 void
2341 drawerror(Display *d, char *s)
2342 {
2343 	USED(d);
2344 	fprint(2, "draw: %s: %r\n", s);
2345 }
2346