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