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
drawmodinit(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
drawhash(char * s)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*
cachelookup(Cache * cache[],Display * d,char * name)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*
cacheinstall(Cache ** cache,Display * d,char * name,void * ptr,char * type)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
cacheuninstall(Cache ** cache,Display * d,char * name,char * type)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*
lookupimage(Draw_Image * di)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*
lookupscreen(Draw_Screen * ds)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*
lookupfont(Draw_Font * df)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*
lookupdisplay(Draw_Display * dd)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*
checkimage(Draw_Image * di)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*
checkscreen(Draw_Screen * ds)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*
checkfont(Draw_Font * df)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*
checkdisplay(Draw_Display * dd)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
Display_allocate(void * fp)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
Display_getwindow(void * fp)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
Display_startrefresh(void * fp)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
display_dec(void * v)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
freedrawdisplay(Heap * h,int swept)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
Display_color(void * fp)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
Image_flush(void * fp)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
checkflush(Draw_Image * dst)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
imagedraw(void * fp,int op)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
Image_draw(void * fp)573 Image_draw(void *fp)
574 {
575 imagedraw(fp, SoverD);
576 }
577
578 void
Image_drawop(void * fp)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
imagegendraw(void * fp,int op)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
Image_gendraw(void * fp)614 Image_gendraw(void *fp)
615 {
616 imagegendraw(fp, SoverD);
617 }
618
619 void
Image_gendrawop(void * fp)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
drawline(void * fp,int op)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
Image_line(void * fp)648 Image_line(void *fp)
649 {
650 drawline(fp, SoverD);
651 }
652
653 void
Image_lineop(void * fp)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
drawsplinepoly(void * fp,int smooth,int op)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
Image_poly(void * fp)688 Image_poly(void *fp)
689 {
690 drawsplinepoly(fp, 0, SoverD);
691 }
692
693 void
Image_polyop(void * fp)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
Image_bezspline(void * fp)703 Image_bezspline(void *fp)
704 {
705 drawsplinepoly(fp, 1, SoverD);
706 }
707
708 void
Image_bezsplineop(void * fp)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
drawbezier(void * fp,int op)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
Image_bezier(void * fp)738 Image_bezier(void *fp)
739 {
740 drawbezier(fp, SoverD);
741 }
742
743 void
Image_bezierop(void * fp)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
drawfillbezier(void * fp,int op)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
Image_fillbezier(void * fp)773 Image_fillbezier(void *fp)
774 {
775 drawfillbezier(fp, SoverD);
776 }
777
778 void
Image_fillbezierop(void * fp)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
drawfillsplinepoly(void * fp,int smooth,int op)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
Image_fillpoly(void * fp)813 Image_fillpoly(void *fp)
814 {
815 drawfillsplinepoly(fp, 0, SoverD);
816 }
817
818 void
Image_fillpolyop(void * fp)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
Image_fillbezspline(void * fp)828 Image_fillbezspline(void *fp)
829 {
830 drawfillsplinepoly(fp, 1, SoverD);
831 }
832
833 void
Image_fillbezsplineop(void * fp)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
drawarcellipse(void * fp,int isarc,int alpha,int phi,int op)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
Image_ellipse(void * fp)868 Image_ellipse(void *fp)
869 {
870 drawarcellipse(fp, 0, 0, 0, SoverD);
871 }
872
873 void
Image_ellipseop(void * fp)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
Image_arc(void * fp)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
Image_arcop(void * fp)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
drawfillarcellipse(void * fp,int isarc,int alpha,int phi,int op)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
Image_fillellipse(void * fp)924 Image_fillellipse(void *fp)
925 {
926 drawfillarcellipse(fp, 0, 0, 0, SoverD);
927 }
928
929 void
Image_fillellipseop(void * fp)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
Image_fillarc(void * fp)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
Image_fillarcop(void * fp)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
drawtext(void * fp,int op)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
Image_text(void * fp)990 Image_text(void *fp)
991 {
992 drawtext(fp, SoverD);
993 }
994
995 void
Image_textop(void * fp)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
drawtextbg(void * fp,int op)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
Image_textbg(void * fp)1039 Image_textbg(void *fp)
1040 {
1041 drawtextbg(fp, SoverD);
1042 }
1043
1044 void
Image_textbgop(void * fp)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
drawborder(void * fp,int op)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
Image_border(void * fp)1073 Image_border(void *fp)
1074 {
1075 drawborder(fp, SoverD);
1076 }
1077
1078 void
Display_newimage(void * fp)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
Display_colormix(void * fp)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
Image_readpixels(void * fp)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
Image_writepixels(void * fp)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
Image_arrow(void * fp)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
Image_name(void * fp)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*
display_open(Display * disp,char * name)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
Display_open(void * fp)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
Display_namedimage(void * fp)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
Display_readimage(void * fp)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
Display_writeimage(void * fp)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*
mkdrawscreen(Screen * s,Draw_Display * display)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*
allocdrawscreen(Draw_Image * dimage,Draw_Image * dfill,int public)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
Screen_allocate(void * fp)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
Display_publicscreen(void * fp)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
freedrawscreen(Heap * h,int swept)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
Font_build(void * fp)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*
font_open(Display * display,char * name)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
font_close(Font * f)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
freecachedsubfont(Subfont * sf)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
freeallsubfonts(Display * d)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
subfont_close(Subfont * sf)1607 subfont_close(Subfont *sf)
1608 {
1609 freecachedsubfont(sf);
1610 }
1611
1612 void
freesubfont(Subfont * sf)1613 freesubfont(Subfont *sf)
1614 {
1615 freecachedsubfont(sf);
1616 }
1617
1618 void
Font_open(void * fp)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
Font_width(void * fp)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
Font_bbox(void * fp)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
freedrawfont(Heap * h,int swept)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
Chans_text(void * fp)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
Chans_depth(void * fp)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
Chans_eq(void * fp)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
Chans_mk(void * fp)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
Display_rgb(void * fp)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
Display_rgb2cmap(void * fp)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
Display_cmap2rgb(void * fp)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
Display_cmap2rgba(void * fp)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
Draw_setalpha(void * fp)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
Draw_icossin(void * fp)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
Draw_icossin2(void * fp)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
Draw_bytesperline(void * fp)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*
color(DDisplay * dd,ulong color)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*
mkdrawimage(Image * i,Draw_Screen * screen,Draw_Display * display,void * ref)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
Screen_newwindow(void * fp)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
screentopbot(Draw_Screen * screen,Array * array,void (* topbot)(Image **,int))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
Screen_top(void * fp)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
Screen_bottom(void * fp)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
freedrawimage(Heap * h,int swept)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
Image_top(void * fp)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
Image_origin(void * fp)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
Image_bottom(void * fp)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*
allocdrawimage(DDisplay * ddisplay,Draw_Rect r,ulong chan,Image * iimage,int repl,int color)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*
lookupsubfont(Display * d,char * name)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
installsubfont(char * name,Subfont * subfont)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*
subfontname(char * cfname,char * fname,int maxdepth)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
refreshslave(Display * d)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
startrefresh(Display * disp)2195 startrefresh(Display *disp)
2196 {
2197 USED(disp);
2198 }
2199
2200 static
2201 int
doflush(Display * d)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
flushimage(Display * d,int visible)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
delrefresh(Image * i)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
queuerefresh(Image * i,Rectangle r,Reffn reffn,void * refptr)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*
bufimage(Display * d,int n)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
drawerror(Display * d,char * s)2341 drawerror(Display *d, char *s)
2342 {
2343 USED(d);
2344 fprint(2, "draw: %s: %r\n", s);
2345 }
2346