diff options
Diffstat (limited to 'libinterp/draw.c')
| -rw-r--r-- | libinterp/draw.c | 2345 |
1 files changed, 2345 insertions, 0 deletions
diff --git a/libinterp/draw.c b/libinterp/draw.c new file mode 100644 index 00000000..55dacddf --- /dev/null +++ b/libinterp/draw.c @@ -0,0 +1,2345 @@ +#include <lib9.h> +#include <kernel.h> +#include "interp.h" +#include "isa.h" +#include "runt.h" +#include "raise.h" +#include "drawmod.h" +#include "draw.h" +#include "drawif.h" +#include "memdraw.h" +#include "memlayer.h" + +/* + * When a Display is remote, it must be locked to synchronize the + * outgoing message buffer with the refresh demon, which runs as a + * different process. When it is local, the refresh demon does nothing + * and it is sufficient to use the interpreter's own acquire/release protection + * to lock the buffer. + * + * Most action to the buffer is caused by calls from Limbo, so locking at + * the top before going into the library is good enough. However, the + * garbage collector can call the free routines at other times, so they + * need to protect themselves whether called through the Draw module + * or not; hence the need for check against recursive locking in lockdisplay(). + * This also means that we needn't lock around calls to destroy if it's + * extra work to do so. + */ + +typedef struct Cache Cache; +typedef struct DRef DRef; +typedef struct DDisplay DDisplay; +typedef struct DImage DImage; +typedef struct DScreen DScreen; +typedef struct DFont DFont; + +struct Cache +{ + int ref; + char* name; + Display*display; + union{ + Subfont* sf; + Font* f; + void* ptr; + }u; + Cache* next; +}; + +/* not visible to Limbo; used only for internal reference counting */ +struct DRef +{ + int ref; + Display* display; +}; + +struct DDisplay +{ + Draw_Display drawdisplay; + Display* display; + DRef* dref; +}; + +struct DImage +{ + Draw_Image drawimage; + Image* image; + void* refreshptr; + DRef* dref; + int flush; +}; + +struct DScreen +{ + Draw_Screen drawscreen; + Screen* screen; + DRef* dref; +}; + +struct DFont +{ + Draw_Font drawfont; + Font* font; + DRef* dref; +}; + +Cache* sfcache[BIHASH]; +Cache* fcache[BIHASH]; +void* cacheqlock; + +static Cache *cachelookup(Cache**, Display*, char*); + +uchar fontmap[] = Draw_Font_map; +uchar imagemap[] = Draw_Image_map; +uchar screenmap[] = Draw_Screen_map; +uchar displaymap[] = Draw_Display_map; + +Type* TFont; +Type* TImage; +Type* TScreen; +Type* TDisplay; + +Draw_Image* allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int); +Draw_Image* color(DDisplay*, ulong); +Draw_Screen *mkdrawscreen(Screen*, Draw_Display*); + +char deffontname[] = "*default*"; +void refreshslave(Display*); +void subfont_close(Subfont*); +void freeallsubfonts(Display*); + +void +drawmodinit(void) +{ + TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap)); + TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap)); + TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap)); + TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap)); + builtinmod("$Draw", Drawmodtab, Drawmodlen); +} + +static int +drawhash(char *s) +{ + int h; + + h = 0; + while(*s){ + h += *s++; + h <<= 1; + if(h & (1<<8)) + h |= 1; + } + return (h&0xFFFF)%BIHASH; +} + +static Cache* +cachelookup(Cache *cache[], Display *d, char *name) +{ + Cache *c; + + libqlock(cacheqlock); + c = cache[drawhash(name)]; + while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)) + c = c->next; + libqunlock(cacheqlock); + return c; +} + +Cache* +cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type) +{ + Cache *c; + int hash; + + USED(type); + c = cachelookup(cache, d, name); + if(c){ +/* print("%s %s already in cache\n", type, name); /**/ + return nil; + } + c = malloc(sizeof(Cache)); + if(c == nil) + return nil; + hash = drawhash(name); + c->ref = 0; /* will be incremented by caller */ + c->display = d; + c->name = strdup(name); + c->u.ptr = ptr; + libqlock(cacheqlock); + c->next = cache[hash]; + cache[hash] = c; + libqunlock(cacheqlock); + return c; +} + +void +cacheuninstall(Cache **cache, Display *d, char *name, char *type) +{ + Cache *c, *prev; + int hash; + + hash = drawhash(name); + libqlock(cacheqlock); + c = cache[hash]; + if(c == nil){ + Notfound: + libqunlock(cacheqlock); + print("%s not in %s cache\n", name, type); + return; + } + prev = nil; + while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){ + prev = c; + c = c->next; + } + if(c == nil) + goto Notfound; + if(prev == 0) + cache[hash] = c->next; + else + prev->next = c->next; + libqunlock(cacheqlock); + free(c->name); + free(c); +} + +Image* +lookupimage(Draw_Image *di) +{ + Display *disp; + Image *i; + int locked; + + if(di == H || D2H(di)->t != TImage) + return nil; + i = ((DImage*)di)->image; + if(i == nil) + return nil; + if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){ + disp = i->display; + locked = lockdisplay(disp); + replclipr(i, di->repl, IRECT(di->clipr)); + if(locked) + unlockdisplay(disp); + } + return i; +} + +Screen* +lookupscreen(Draw_Screen *ds) +{ + if(ds == H || D2H(ds)->t != TScreen) + return nil; + return ((DScreen*)ds)->screen; +} + +Font* +lookupfont(Draw_Font *df) +{ + if(df == H || D2H(df)->t != TFont) + return nil; + return ((DFont*)df)->font; +} + +Display* +lookupdisplay(Draw_Display *dd) +{ + if(dd == H || D2H(dd)->t != TDisplay) + return nil; + return ((DDisplay*)dd)->display; +} + +Image* +checkimage(Draw_Image *di) +{ + Image *i; + + if(di == H) + error("nil Image"); + i = lookupimage(di); + if(i == nil) + error(exType); + return i; +} + +Screen* +checkscreen(Draw_Screen *ds) +{ + Screen *s; + + if(ds == H) + error("nil Screen"); + s = lookupscreen(ds); + if(s == nil) + error(exType); + return s; +} + +Font* +checkfont(Draw_Font *df) +{ + Font *f; + + if(df == H) + error("nil Font"); + f = lookupfont(df); + if(f == nil) + error(exType); + return f; +} + +Display* +checkdisplay(Draw_Display *dd) +{ + Display *d; + + if(dd == H) + error("nil Display"); + d = lookupdisplay(dd); + if(d == nil) + error(exType); + return d; +} + +void +Display_allocate(void *fp) +{ + F_Display_allocate *f; + char buf[128], *dev; + Subfont *df; + Display *display; + DDisplay *dd; + Heap *h; + Draw_Rect r; + DRef *dr; + Cache *c; + + f = fp; + destroy(*f->ret); + *f->ret = H; + if(cacheqlock == nil){ + cacheqlock = libqlalloc(); + if(cacheqlock == nil) + return; + } + dev = string2c(f->dev); + if(dev[0] == 0) + dev = 0; + display = initdisplay(dev, dev, nil); /* TO DO: win, error */ + if(display == 0) + return; + + dr = malloc(sizeof(DRef)); + if(dr == nil) + return; + h = heap(TDisplay); + if(h == H){ + closedisplay(display); + return; + } + dd = H2D(DDisplay*, h); + dd->display = display; + *f->ret = &dd->drawdisplay; + dd->dref = dr; + display->limbo = dr; + dr->display = display; + dr->ref = 1; + df = getdefont(display); + if(df){ + display->defaultsubfont = df; + sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent, + df->n-1, deffontname); + display->defaultfont = buildfont(display, buf, deffontname); + if(display->defaultfont){ + c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font"); + if(c) + c->ref++; + /* else BUG? */ + } + } + + R2R(r, display->image->r); + dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0); + R2R(r, display->white->r); + dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0); + dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0); + dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0); + dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0); + + /* don't call unlockdisplay because the qlock was left up by initdisplay */ + libqunlock(display->qlock); +} + +void +Display_getwindow(void *fp) +{ + F_Display_getwindow *f; + Display *disp; + int locked; + Image *image; + Screen *screen; + char *wn; + void *r; + + f = fp; + r = f->ret->t0; + f->ret->t0 = H; + destroy(r); + r = f->ret->t1; + f->ret->t1 = H; + destroy(r); + disp = checkdisplay(f->d); + if(f->winname == H) + wn = "/dev/winname"; + else + wn = string2c(f->winname); + if(f->image == H) + image = nil; + else + image = checkimage(f->image); + if(f->screen == H) + screen = nil; + else + screen = checkscreen(f->screen); + locked = lockdisplay(disp); + if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){ + /* TO DO: eliminate f->image and f->screen's references to Image and Screen */ + goto Return; + } + if(screen != nil){ + if(f->screen != H){ + f->ret->t0 = f->screen; + D2H(f->screen)->ref++; + }else + f->ret->t0 = mkdrawscreen(screen, f->d); + } + if(image != nil){ + if(f->image != H){ + f->ret->t1 = f->image; + D2H(f->image)->ref++; + }else + f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil); + } + +Return: + if(locked) + unlockdisplay(disp); +} + +void +Display_startrefresh(void *fp) +{ + F_Display_startrefresh *f; + Display *disp; + + f = fp; + disp = checkdisplay(f->d); + refreshslave(disp); +} + +void +display_dec(void *v) +{ + DRef *dr; + Display *d; + int locked; + + dr = v; + if(dr->ref-- != 1) + return; + + d = dr->display; + locked = lockdisplay(d); + font_close(d->defaultfont); + subfont_close(d->defaultsubfont); + if(locked) + unlockdisplay(d); + freeallsubfonts(d); + closedisplay(d); + free(dr); +} + +void +freedrawdisplay(Heap *h, int swept) +{ + DDisplay *dd; + Display *d; + + dd = H2D(DDisplay*, h); + + if(!swept) { + destroy(dd->drawdisplay.image); + destroy(dd->drawdisplay.black); + destroy(dd->drawdisplay.white); + destroy(dd->drawdisplay.opaque); + destroy(dd->drawdisplay.transparent); + } + /* we've now released dd->image etc.; make sure they're not freed again */ + d = dd->display; + d->image = nil; + d->white = nil; + d->black = nil; + d->opaque = nil; + d->transparent = nil; + display_dec(dd->dref); + /* Draw_Display header will be freed by caller */ +} + +void +Display_color(void *fp) +{ + F_Display_color *f; + Display *d; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + d = checkdisplay(f->d); + locked = lockdisplay(d); + *f->ret = color((DDisplay*)f->d, f->color); + if(locked) + unlockdisplay(d); +} + +void +Image_flush(void *fp) +{ + F_Image_flush *f; + Image *d; + DImage *di; + int locked; + + f = fp; + d = checkimage(f->win); + di = (DImage*)f->win; + switch(f->func){ + case 0: /* Draw->Flushoff */ + di->flush = 0; + break; + case 1: /* Draw->Flushon */ + di->flush = 1; + /* fall through */ + case 2: /* Draw->Flushnow */ + locked = lockdisplay(d->display); + if(d->id==0 || d->screen!=0) + flushimage(d->display, 1); + if(locked) + unlockdisplay(d->display); + break; + default: + error(exInval); + } +} + +void +checkflush(Draw_Image *dst) +{ + DImage *di; + + di = (DImage*)dst; + if(di->flush && (di->image->id==0 || di->image->screen!=nil)) + flushimage(di->image->display, 1); +} + +static void +imagedraw(void *fp, int op) +{ + F_Image_draw *f; + Image *d, *s, *m; + int locked; + + f = fp; + d = checkimage(f->dst); + if(f->src == H) + s = d->display->black; + else + s = checkimage(f->src); + if(f->matte == H) + m = d->display->white; /* ones */ + else + m = checkimage(f->matte); + if(d->display!=s->display || d->display!=m->display) + return; + locked = lockdisplay(d->display); + drawop(d, IRECT(f->r), s, m, IPOINT(f->p), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_draw(void *fp) +{ + imagedraw(fp, SoverD); +} + +void +Image_drawop(void *fp) +{ + F_Image_drawop *f; + + f = fp; + imagedraw(fp, f->op); +} + +static void +imagegendraw(void *fp, int op) +{ + F_Image_gendraw *f; + Image *d, *s, *m; + int locked; + + f = fp; + d = checkimage(f->dst); + if(f->src == H) + s = d->display->black; + else + s = checkimage(f->src); + if(f->matte == H) + m = d->display->white; /* ones */ + else + m = checkimage(f->matte); + if(d->display!=s->display || d->display!=m->display) + return; + locked = lockdisplay(d->display); + gendrawop(d, IRECT(f->r), s, IPOINT(f->p0), m, IPOINT(f->p1), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_gendraw(void *fp) +{ + imagegendraw(fp, SoverD); +} + +void +Image_gendrawop(void *fp) +{ + F_Image_gendrawop *f; + + f = fp; + imagegendraw(fp, f->op); +} + +static void +drawline(void *fp, int op) +{ + F_Image_line *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display || f->radius < 0) + return; + locked = lockdisplay(d->display); + lineop(d, IPOINT(f->p0), IPOINT(f->p1), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_line(void *fp) +{ + drawline(fp, SoverD); +} + +void +Image_lineop(void *fp) +{ + F_Image_lineop *f; + + f = fp; + drawline(fp, f->op); +} + +static void +drawsplinepoly(void *fp, int smooth, int op) +{ + F_Image_poly *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display|| f->radius < 0) + return; + locked = lockdisplay(d->display); + /* sleazy: we know that Draw_Points have same shape as Points */ + if(smooth) + bezsplineop(d, (Point*)f->p->data, f->p->len, + f->end0, f->end1, f->radius, s, IPOINT(f->sp), op); + else + polyop(d, (Point*)f->p->data, f->p->len, f->end0, + f->end1, f->radius, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_poly(void *fp) +{ + drawsplinepoly(fp, 0, SoverD); +} + +void +Image_polyop(void *fp) +{ + F_Image_polyop *f; + + f = fp; + drawsplinepoly(fp, 0, f->op); +} + +void +Image_bezspline(void *fp) +{ + drawsplinepoly(fp, 1, SoverD); +} + +void +Image_bezsplineop(void *fp) +{ + F_Image_bezsplineop *f; + + f = fp; + drawsplinepoly(fp, 1, f->op); +} + +static void +drawbezier(void *fp, int op) +{ + F_Image_bezier *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display || f->radius < 0) + return; + locked = lockdisplay(d->display); + bezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c), + IPOINT(f->d), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_bezier(void *fp) +{ + drawbezier(fp, SoverD); +} + +void +Image_bezierop(void *fp) +{ + F_Image_bezierop *f; + + f = fp; + drawbezier(fp, f->op); +} + +static void +drawfillbezier(void *fp, int op) +{ + F_Image_fillbezier *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display) + return; + locked = lockdisplay(d->display); + fillbezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c), + IPOINT(f->d), f->wind, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_fillbezier(void *fp) +{ + drawfillbezier(fp, SoverD); +} + +void +Image_fillbezierop(void *fp) +{ + F_Image_fillbezierop *f; + + f = fp; + drawfillbezier(fp, f->op); +} + +static void +drawfillsplinepoly(void *fp, int smooth, int op) +{ + F_Image_fillpoly *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display) + return; + locked = lockdisplay(d->display); + /* sleazy: we know that Draw_Points have same shape as Points */ + if(smooth) + fillbezsplineop(d, (Point*)f->p->data, f->p->len, + f->wind, s, IPOINT(f->sp), op); + else + fillpolyop(d, (Point*)f->p->data, f->p->len, + f->wind, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_fillpoly(void *fp) +{ + drawfillsplinepoly(fp, 0, SoverD); +} + +void +Image_fillpolyop(void *fp) +{ + F_Image_fillpolyop *f; + + f = fp; + drawfillsplinepoly(fp, 0, f->op); +} + +void +Image_fillbezspline(void *fp) +{ + drawfillsplinepoly(fp, 1, SoverD); +} + +void +Image_fillbezsplineop(void *fp) +{ + F_Image_fillbezsplineop *f; + + f = fp; + drawfillsplinepoly(fp, 1, f->op); +} + +static void +drawarcellipse(void *fp, int isarc, int alpha, int phi, int op) +{ + F_Image_arc *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display || f->thick < 0 || f->a<0 || f->b<0) + return; + + locked = lockdisplay(d->display); + if(isarc) + arcop(d, IPOINT(f->c), f->a, f->b, f->thick, s, + IPOINT(f->sp), alpha, phi, op); + else + ellipseop(d, IPOINT(f->c), f->a, f->b, f->thick, s, + IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_ellipse(void *fp) +{ + drawarcellipse(fp, 0, 0, 0, SoverD); +} + +void +Image_ellipseop(void *fp) +{ + F_Image_ellipseop *f; + + f = fp; + drawarcellipse(fp, 0, 0, 0, f->op); +} + +void +Image_arc(void *fp) +{ + F_Image_arc *f; + + f = fp; + drawarcellipse(fp, 1, f->alpha, f->phi, SoverD); +} + +void +Image_arcop(void *fp) +{ + F_Image_arcop *f; + + f = fp; + drawarcellipse(fp, 1, f->alpha, f->phi, f->op); +} + +static void +drawfillarcellipse(void *fp, int isarc, int alpha, int phi, int op) +{ + F_Image_fillarc *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display || f->a<0 || f->b<0) + return; + + locked = lockdisplay(d->display); + if(isarc) + fillarcop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), alpha, phi, op); + else + fillellipseop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_fillellipse(void *fp) +{ + drawfillarcellipse(fp, 0, 0, 0, SoverD); +} + +void +Image_fillellipseop(void *fp) +{ + F_Image_fillellipseop *f; + + f = fp; + drawfillarcellipse(fp, 0, 0, 0, f->op); +} + +void +Image_fillarc(void *fp) +{ + F_Image_fillarc *f; + + f = fp; + drawfillarcellipse(fp, 1, f->alpha, f->phi, SoverD); +} + +void +Image_fillarcop(void *fp) +{ + F_Image_fillarcop *f; + + f = fp; + drawfillarcellipse(fp, 1, f->alpha, f->phi, f->op); +} + +static void +drawtext(void *fp, int op) +{ + F_Image_text *f; + Font *font; + Point pt; + Image *s, *d; + String *str; + int locked; + + f = fp; + if(f->dst == H || f->src == H) + goto Return; + if(f->font == H || f->str == H) + goto Return; + str = f->str; + d = checkimage(f->dst); + s = checkimage(f->src); + font = checkfont(f->font); + if(d->display!=s->display || d->display!=font->display) + return; + locked = lockdisplay(d->display); + if(str->len >= 0) + pt = stringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, op); + else + pt = runestringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); + Return: + P2P(*f->ret, pt); +} + +void +Image_text(void *fp) +{ + drawtext(fp, SoverD); +} + +void +Image_textop(void *fp) +{ + F_Image_textop *f; + + f = fp; + drawtext(fp, f->op); +} + +static void +drawtextbg(void *fp, int op) +{ + F_Image_textbg *f; + Font *font; + Point pt; + Image *s, *d, *bg; + String *str; + int locked; + + f = fp; + if(f->dst == H || f->src == H) + goto Return; + if(f->font == H || f->str == H) + goto Return; + str = f->str; + d = checkimage(f->dst); + s = checkimage(f->src); + bg = checkimage(f->bg); + font = checkfont(f->font); + if(d->display!=s->display || d->display!=font->display) + return; + locked = lockdisplay(d->display); + if(str->len >= 0) + pt = stringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, bg, IPOINT(f->bgp), op); + else + pt = runestringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, bg, IPOINT(f->bgp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); + Return: + P2P(*f->ret, pt); +} + +void +Image_textbg(void *fp) +{ + drawtextbg(fp, SoverD); +} + +void +Image_textbgop(void *fp) +{ + F_Image_textbgop *f; + + f = fp; + drawtextbg(fp, f->op); +} + +static void +drawborder(void *fp, int op) +{ + F_Image_border *f; + Image *d, *s; + int locked; + + f = fp; + d = checkimage(f->dst); + s = checkimage(f->src); + if(d->display != s->display) + return; + locked = lockdisplay(d->display); + borderop(d, IRECT(f->r), f->i, s, IPOINT(f->sp), op); + checkflush(f->dst); + if(locked) + unlockdisplay(d->display); +} + +void +Image_border(void *fp) +{ + drawborder(fp, SoverD); +} + +void +Display_newimage(void *fp) +{ + F_Display_newimage *f; + Display *d; + int locked; + + f = fp; + d = checkdisplay(f->d); + destroy(*f->ret); + *f->ret = H; + locked = lockdisplay(d); + *f->ret = allocdrawimage((DDisplay*)f->d, f->r, f->chans.desc, + nil, f->repl, f->color); + if(locked) + unlockdisplay(d); +} + +void +Display_colormix(void *fp) +{ + F_Display_colormix *f; + Display *disp; + Image *i; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + disp = checkdisplay(f->d); + locked = lockdisplay(disp); + i = allocimagemix(disp, f->c1, f->c2); + if(locked) + unlockdisplay(disp); + *f->ret = mkdrawimage(i, H, f->d, nil); +} + +void +Image_readpixels(void *fp) +{ + F_Image_readpixels *f; + Rectangle r; + Image *i; + int locked; + + f = fp; + R2R(r, f->r); + i = checkimage(f->src); + locked = lockdisplay(i->display); + *f->ret = unloadimage(i, r, f->data->data, f->data->len); + if(locked) + unlockdisplay(i->display); +} + +void +Image_writepixels(void *fp) +{ + Rectangle r; + F_Image_writepixels *f; + Image *i; + int locked; + + f = fp; + R2R(r, f->r); + i = checkimage(f->dst); + locked = lockdisplay(i->display); + *f->ret = loadimage(i, r, f->data->data, f->data->len); + checkflush(f->dst); + if(locked) + unlockdisplay(i->display); +} + +void +Image_arrow(void *fp) +{ + F_Image_arrow *f; + + f = fp; + *f->ret = ARROW(f->a, f->b, f->c); +} + +void +Image_name(void *fp) +{ + F_Image_name *f; + Image *i; + int locked, ok; + char *name; + + f = fp; + *f->ret = -1; + i = checkimage(f->src); + name = string2c(f->name); + locked = lockdisplay(i->display); + *f->ret = ok = nameimage(i, name, f->in); + if(locked) + unlockdisplay(i->display); + if(ok){ + destroy(f->src->iname); + if(f->in){ + f->src->iname = f->name; + D2H(f->name)->ref++; + }else + f->src->iname = H; + } +} + +Image* +display_open(Display *disp, char *name) +{ + Image *i; + int fd; + + fd = libopen(name, OREAD); + if(fd < 0) + return nil; + + i = readimage(disp, fd, 1); + libclose(fd); + return i; +} + +void +Display_open(void *fp) +{ + Image *i; + Display *disp; + F_Display_open *f; + + f = fp; + destroy(*f->ret); + *f->ret = H; + disp = lookupdisplay(f->d); + if(disp == nil) + return; + i = display_open(disp, string2c(f->name)); + if(i == nil) + return; + *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0); +} + +void +Display_namedimage(void *fp) +{ + F_Display_namedimage *f; + Display *d; + Image *i; + Draw_Image *di; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + d = checkdisplay(f->d); + locked = lockdisplay(d); + i = namedimage(d, string2c(f->name)); + if(locked) + unlockdisplay(d); + if(i == nil) + return; + di = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, i->repl, 0); + *f->ret = di; + if(di == H){ + locked = lockdisplay(d); + freeimage(i); + if(locked) + unlockdisplay(d); + }else{ + di->iname = f->name; + D2H(f->name)->ref++; + } +} + +void +Display_readimage(void *fp) +{ + Image *i; + Display *disp; + F_Display_readimage *f; + Sys_FD *fd; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + fd = f->fd; + if(fd == H) + return; + disp = checkdisplay(f->d); + i = readimage(disp, fd->fd, 1); + if(i == nil) + return; + *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0); + if(*f->ret == H){ + locked = lockdisplay(disp); + freeimage(i); + if(locked) + unlockdisplay(disp); + } +} + +void +Display_writeimage(void *fp) +{ + Image *i; + F_Display_writeimage *f; + Sys_FD *fd; + + f = fp; + *f->ret = -1; + fd = f->fd; + if(fd == H) + return; + i = checkimage(f->i); + if(checkdisplay(f->d) != i->display) + return; + *f->ret = writeimage(fd->fd, i, 1); /* TO DO: dolock? */ +} + +Draw_Screen* +mkdrawscreen(Screen *s, Draw_Display *display) +{ + Heap *h; + DScreen *ds; + Draw_Image *dimage, *dfill; + + dimage = mkdrawimage(s->image, H, display, nil); + dfill = mkdrawimage(s->fill, H, display, nil); + h = heap(TScreen); + if(h == H) + return nil; + ds = H2D(DScreen*, h); + ds->screen = s; + ds->drawscreen.fill = dfill; + D2H(dfill)->ref++; + ds->drawscreen.image = dimage; + D2H(dimage)->ref++; + ds->drawscreen.display = dimage->display; + D2H(dimage->display)->ref++; + ds->drawscreen.id = s->id; + ds->dref = s->display->limbo; + ds->dref->ref++; + return &ds->drawscreen; +} + +static DScreen* +allocdrawscreen(Draw_Image *dimage, Draw_Image *dfill, int public) +{ + Heap *h; + Screen *s; + DScreen *ds; + Image *image, *fill; + + image = ((DImage*)dimage)->image; + fill = ((DImage*)dfill)->image; + s = allocscreen(image, fill, public); + if(s == 0) + return nil; + h = heap(TScreen); + if(h == H) + return nil; + ds = H2D(DScreen*, h); + ds->screen = s; + ds->drawscreen.fill = dfill; + D2H(dfill)->ref++; + ds->drawscreen.image = dimage; + D2H(dimage)->ref++; + ds->drawscreen.display = dimage->display; + D2H(dimage->display)->ref++; + ds->drawscreen.id = s->id; + ds->dref = image->display->limbo; + ds->dref->ref++; + return ds; +} + +void +Screen_allocate(void *fp) +{ + F_Screen_allocate *f; + DScreen *ds; + Image *image; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + image = checkimage(f->image); + checkimage(f->fill); + locked = lockdisplay(image->display); + ds = allocdrawscreen(f->image, f->fill, f->public); + if(ds != nil) + *f->ret = &ds->drawscreen; + if(locked) + unlockdisplay(image->display); +} + +void +Display_publicscreen(void *fp) +{ + F_Display_publicscreen *f; + Heap *h; + Screen *s; + DScreen *ds; + Display *disp; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + disp = checkdisplay(f->d); + locked = lockdisplay(disp); + s = publicscreen(disp, f->id, disp->image->chan); + if(locked) + unlockdisplay(disp); + if(s == nil) + return; + h = heap(TScreen); + if(h == H) + return; + ds = H2D(DScreen*, h); + ds->screen = s; + ds->drawscreen.fill = H; + ds->drawscreen.image =H; + ds->drawscreen.id = s->id; + ds->drawscreen.display = f->d; + D2H(f->d)->ref++; + ds->dref = disp->limbo; + ds->dref->ref++; + *f->ret = &ds->drawscreen; +} + +void +freedrawscreen(Heap *h, int swept) +{ + DScreen *ds; + Screen *s; + Display *disp; + int locked; + + ds = H2D(DScreen*, h); + if(!swept) { + destroy(ds->drawscreen.image); + destroy(ds->drawscreen.fill); + destroy(ds->drawscreen.display); + } + s = lookupscreen(&ds->drawscreen); + if(s == nil){ + if(!swept) + freeptrs(ds, TScreen); + return; + } + disp = s->display; + locked = lockdisplay(disp); + freescreen(s); + if(locked) + unlockdisplay(disp); + display_dec(ds->dref); + /* screen header will be freed by caller */ +} + +void +Font_build(void *fp) +{ + F_Font_build *f; + Font *font; + DFont *dfont; + Heap *h; + char buf[128]; + char *name, *data; + Subfont *df; + Display *disp; + int locked; + + f = fp; + destroy(*f->ret); + *f->ret = H; + disp = checkdisplay(f->d); + + name = string2c(f->name); + font = font_open(disp, name); + if(font == nil) { + if(strcmp(name, deffontname) == 0) { + df = disp->defaultsubfont; + sprint(buf, "%d %d\n0 %d\t%s\n", + df->height, df->ascent, df->n-1, name); + data = buf; + } + else + if(f->desc == H) + return; + else + data = string2c(f->desc); + + locked = lockdisplay(disp); + font = buildfont(disp, data, name); + if(locked) + unlockdisplay(disp); + if(font == nil) + return; + } + + h = heap(TFont); + if(h == H) + return; + + dfont = H2D(DFont*, h); + dfont->font = font; + dfont->drawfont.name = f->name; + D2H(f->name)->ref++; + dfont->drawfont.height = font->height; + dfont->drawfont.ascent = font->ascent; + dfont->drawfont.display = f->d; + D2H(f->d)->ref++; + dfont->dref = disp->limbo; + dfont->dref->ref++; + + *f->ret = &dfont->drawfont; +} + +Font* +font_open(Display *display, char *name) +{ + Cache *c; + Font *font; + int locked; + + c = cachelookup(fcache, display, name); + if(c) + font = c->u.f; + else { + locked = lockdisplay(display); + font = openfont(display, name); + if(locked) + unlockdisplay(display); + if(font == nil) + return nil; + c = cacheinstall(fcache, display, name, font, "font"); + } + if(c) + c->ref++; + + return font; +} + +void +font_close(Font *f) +{ + Cache *c; + Display *disp; + int locked; + disp = f->display; + if(f->name == nil) + return; + + /* fonts from Font_build() aren't always in fcache, but we still need to free them */ + c = cachelookup(fcache, disp, f->name); + if(c != nil && f == c->u.f) { + if(c->ref <= 0) + return; + if(c->ref-- != 1) + return; + cacheuninstall(fcache, disp, f->name, "font"); + } + + locked = lockdisplay(disp); + freefont(f); + if(locked) + unlockdisplay(disp); +} + +void +freecachedsubfont(Subfont *sf) +{ + Cache *c; + Display *disp; + + disp = sf->bits->display; + c = cachelookup(sfcache, disp, sf->name); + if(c == nil){ + fprint(2, "subfont %s not cached\n", sf->name); + return; + } + if(c->ref > 0) + c->ref--; + /* if ref is zero, we leave it around for later harvesting by freeallsubfonts */ +} + +void +freeallsubfonts(Display *d) +{ + int i; + Cache *c, *prev, *o; + Subfont *sf; + int locked; + if(cacheqlock == nil) /* may not have allocated anything yet */ + return; + libqlock(cacheqlock); + for(i=0; i<BIHASH; i++){ + c = sfcache[i]; + prev = 0; + while(c != nil){ + if(c->ref==0 && (d==nil || c->display==d)){ + if(prev == 0) + sfcache[i] = c->next; + else + prev->next = c->next; + free(c->name); + sf = c->u.sf; + if(--sf->ref==0){ + free(sf->info); + locked = lockdisplay(c->display); + freeimage(sf->bits); + if(locked) + unlockdisplay(c->display); + free(sf); + } + o = c; + c = c->next; + free(o); + }else{ + prev = c; + c = c->next; + } + } + } + libqunlock(cacheqlock); +} + +void +subfont_close(Subfont *sf) +{ + freecachedsubfont(sf); +} + +void +freesubfont(Subfont *sf) +{ + freecachedsubfont(sf); +} + +void +Font_open(void *fp) +{ + Heap *h; + Font *font; + Display *disp; + DFont *df; + F_Font_open *f; + + f = fp; + + destroy(*f->ret); + *f->ret = H; + disp = checkdisplay(f->d); + + font = font_open(disp, string2c(f->name)); + if(font == 0) + return; + + h = heap(TFont); + if(h == H) + return; + + df = H2D(DFont*, h); + df->font = font; + df->drawfont.name = f->name; + D2H(f->name)->ref++; + df->drawfont.height = font->height; + df->drawfont.ascent = font->ascent; + df->drawfont.display = f->d; + D2H(f->d)->ref++; + df->dref = disp->limbo; + df->dref->ref++; + *f->ret = &df->drawfont; +} + +void +Font_width(void *fp) +{ + F_Font_width *f; + Font *font; + char *s; + int locked; + + f = fp; + s = string2c(f->str); + if(f->f == H || s[0]=='\0') + *f->ret = 0; + else{ + font = checkfont(f->f); + locked = lockdisplay(font->display); + *f->ret = stringwidth(font, s); + if(locked) + unlockdisplay(font->display); + } +} + +void +Font_bbox(void *fp) +{ + F_Font_bbox *f; + Draw_Rect *ret; + + /* place holder for the real thing */ + f = fp; + ret = f->ret; + ret->min.x = ret->min.y = 0; + ret->max.x = ret->max.y = 0; +} + +/* + * BUG: would be nice if this cached the whole font. + * Instead only the subfonts are cached and the fonts are + * freed when released. + */ +void +freedrawfont(Heap*h, int swept) +{ + Draw_Font *d; + Font *f; + d = H2D(Draw_Font*, h); + f = lookupfont(d); + if(!swept) { + destroy(d->name); + destroy(d->display); + } + font_close(f); + display_dec(((DFont*)d)->dref); +} + +void +Chans_text(void *fp) +{ + F_Chans_text *f; + char buf[16]; + + f = fp; + destroy(*f->ret); + *f->ret = H; + if(chantostr(buf, f->c.desc) != nil) + retstr(buf, f->ret); +} + +void +Chans_depth(void *fp) +{ + F_Chans_depth *f; + + f = fp; + *f->ret = chantodepth(f->c.desc); +} + +void +Chans_eq(void *fp) +{ + F_Chans_eq *f; + + f = fp; + *f->ret = f->c.desc == f->d.desc; +} + +void +Chans_mk(void *fp) +{ + F_Chans_mk *f; + + f = fp; + f->ret->desc = strtochan(string2c(f->s)); +} + +void +Display_rgb(void *fp) +{ + ulong c; + Display *disp; + F_Display_rgb *f; + int locked; + void *r; + + f = fp; + r = *f->ret; + *f->ret = H; + destroy(r); + disp = checkdisplay(f->d); + + c = ((f->r&255)<<24)|((f->g&255)<<16)|((f->b&255)<<8)|0xFF; + + locked = lockdisplay(disp); + *f->ret = color((DDisplay*)f->d, c); + if(locked) + unlockdisplay(disp); +} + +void +Display_rgb2cmap(void *fp) +{ + F_Display_rgb2cmap *f; + + f = fp; + /* f->display is unused, but someday may have color map */ + *f->ret = rgb2cmap(f->r, f->g, f->b); +} + +void +Display_cmap2rgb(void *fp) +{ + F_Display_cmap2rgb *f; + ulong c; + + f = fp; + /* f->display is unused, but someday may have color map */ + c = cmap2rgb(f->c); + f->ret->t0 = (c>>16)&0xFF; + f->ret->t1 = (c>>8)&0xFF; + f->ret->t2 = (c>>0)&0xFF; +} + +void +Display_cmap2rgba(void *fp) +{ + F_Display_cmap2rgba *f; + + f = fp; + /* f->display is unused, but someday may have color map */ + *f->ret = cmap2rgba(f->c); +} + +void +Draw_setalpha(void *fp) +{ + F_Draw_setalpha *f; + + f = fp; + *f->ret = setalpha(f->c, f->a); +} + +void +Draw_icossin(void *fp) +{ + F_Draw_icossin *f; + int s, c; + + f = fp; + icossin(f->deg, &s, &c); + f->ret->t0 = s; + f->ret->t1 = c; +} + +void +Draw_icossin2(void *fp) +{ + F_Draw_icossin2 *f; + int s, c; + + f = fp; + icossin2(f->p.x, f->p.y, &s, &c); + f->ret->t0 = s; + f->ret->t1 = c; +} + +void +Draw_bytesperline(void *fp) +{ + F_Draw_bytesperline *f; + + f = fp; + *f->ret = bytesperline(IRECT(f->r), f->d); +} + +Draw_Image* +color(DDisplay *dd, ulong color) +{ + int c; + Draw_Rect r; + + r.min.x = 0; + r.min.y = 0; + r.max.x = 1; + r.max.y = 1; + c = (color&0xff) == 0xff ? RGB24: RGBA32; + return allocdrawimage(dd, r, c, nil, 1, color); +} + +Draw_Image* +mkdrawimage(Image *i, Draw_Screen *screen, Draw_Display *display, void *ref) +{ + Heap *h; + DImage *di; + + h = heap(TImage); + if(h == H) + return H; + + di = H2D(DImage*, h); + di->image = i; + di->drawimage.screen = screen; + if(screen != H) + D2H(screen)->ref++; + di->drawimage.display = display; + if(display != H) + D2H(display)->ref++; + di->refreshptr = ref; + + R2R(di->drawimage.r, i->r); + R2R(di->drawimage.clipr, i->clipr); + di->drawimage.chans.desc = i->chan; + di->drawimage.depth = i->depth; + di->drawimage.repl = i->repl; + di->flush = 1; + di->dref = i->display->limbo; + di->dref->ref++; + return &di->drawimage; +} + +void +Screen_newwindow(void *fp) +{ + F_Screen_newwindow *f; + Image *i; + Screen *s; + Rectangle r; + int locked; + void *v; + + f = fp; + s = checkscreen(f->screen); + R2R(r, f->r); + + if(f->backing != Refnone && f->backing != Refbackup) + f->backing = Refbackup; + + v = *f->ret; + *f->ret = H; + destroy(v); + + locked = lockdisplay(s->display); + i = allocwindow(s, r, f->backing, f->color); + if(locked) + unlockdisplay(s->display); + if(i == nil) + return; + + *f->ret = mkdrawimage(i, f->screen, f->screen->display, 0); +} + +static +void +screentopbot(Draw_Screen *screen, Array *array, void (*topbot)(Image **, int)) +{ + Screen *s; + Draw_Image **di; + Image **ip; + int i, n, locked; + + s = checkscreen(screen); + di = (Draw_Image**)array->data; + ip = malloc(array->len * sizeof(Image*)); + if(ip == nil) + return; + n = 0; + for(i=0; i<array->len; i++) + if(di[i] != H){ + ip[n] = lookupimage(di[i]); + if(ip[n]==nil || ip[n]->screen != s){ + free(ip); + return; + } + n++; + } + if(n == 0){ + free(ip); + return; + } + locked = lockdisplay(s->display); + (*topbot)(ip, n); + free(ip); + flushimage(s->display, 1); + if(locked) + unlockdisplay(s->display); +} + +void +Screen_top(void *fp) +{ + F_Screen_top *f; + f = fp; + screentopbot(f->screen, f->wins, topnwindows); +} + +void +Screen_bottom(void *fp) +{ + F_Screen_top *f; + f = fp; + screentopbot(f->screen, f->wins, bottomnwindows); +} + +void +freedrawimage(Heap *h, int swept) +{ + Image *i; + int locked; + Display *disp; + Draw_Image *d; + + d = H2D(Draw_Image*, h); + i = lookupimage(d); + if(i == nil) { + if(!swept) + freeptrs(d, TImage); + return; + } + disp = i->display; + locked = lockdisplay(disp); + freeimage(i); + if(locked) + unlockdisplay(disp); + display_dec(((DImage*)d)->dref); + /* image/layer header will be freed by caller */ +} + +void +Image_top(void *fp) +{ + F_Image_top *f; + Image *i; + int locked; + + f = fp; + i = checkimage(f->win); + locked = lockdisplay(i->display); + topwindow(i); + flushimage(i->display, 1); + if(locked) + unlockdisplay(i->display); +} + +void +Image_origin(void *fp) +{ + F_Image_origin *f; + Image *i; + int locked; + + f = fp; + i = checkimage(f->win); + locked = lockdisplay(i->display); + if(originwindow(i, IPOINT(f->log), IPOINT(f->scr)) < 0) + *f->ret = -1; + else{ + f->win->r = DRECT(i->r); + f->win->clipr = DRECT(i->clipr); + *f->ret = 1; + } + if(locked) + unlockdisplay(i->display); +} + +void +Image_bottom(void *fp) +{ + F_Image_top *f; + Image *i; + int locked; + + f = fp; + i = checkimage(f->win); + locked = lockdisplay(i->display); + bottomwindow(i); + flushimage(i->display, 1); + if(locked) + unlockdisplay(i->display); +} + +Draw_Image* +allocdrawimage(DDisplay *ddisplay, Draw_Rect r, ulong chan, Image *iimage, int repl, int color) +{ + Heap *h; + DImage *di; + Rectangle rr; + Image *image; + + image = iimage; + if(iimage == nil){ + R2R(rr, r); + image = allocimage(ddisplay->display, rr, chan, repl, color); + if(image == nil) + return H; + } + + h = heap(TImage); + if(h == H){ + if(iimage == nil) + freeimage(image); + return H; + } + + di = H2D(DImage*, h); + di->drawimage.r = r; + R2R(di->drawimage.clipr, image->clipr); + di->drawimage.chans.desc = chan; + di->drawimage.depth = chantodepth(chan); + di->drawimage.repl = repl; + di->drawimage.display = (Draw_Display*)ddisplay; + D2H(di->drawimage.display)->ref++; + di->drawimage.screen = H; + di->dref = ddisplay->display->limbo; + di->dref->ref++; + di->image = image; + di->refreshptr = 0; + di->flush = 1; + + return &di->drawimage; +} + +/* + * Entry points called from the draw library + */ +Subfont* +lookupsubfont(Display *d, char *name) +{ + Cache *c; + + c = cachelookup(sfcache, d, name); + if(c == nil) + return nil; + /*c->u.sf->ref++;*/ /* TO DO: need to revisit the reference counting */ + return c->u.sf; +} + +void +installsubfont(char *name, Subfont *subfont) +{ + Cache *c; + + c = cacheinstall(sfcache, subfont->bits->display, name, subfont, "subfont"); + if(c) + c->ref++; +} + +/* + * BUG version + */ +char* +subfontname(char *cfname, char *fname, int maxdepth) +{ + char *t, *u, tmp1[256], tmp2[256]; + int i, fd; + + if(strcmp(cfname, deffontname) == 0) + return strdup(cfname); + t = cfname; + if(t[0] != '/'){ + strcpy(tmp2, fname); + u = utfrrune(tmp2, '/'); + if(u) + u[0] = 0; + else + strcpy(tmp2, "."); + snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t); + t = tmp1; + } + + if(maxdepth > 8) + maxdepth = 8; + + for(i=3; i>=0; i--){ + if((1<<i) > maxdepth) + continue; + /* try i-bit grey */ + snprint(tmp2, sizeof tmp2, "%s.%d", t, i); + fd = libopen(tmp2, OREAD); + if(fd >= 0){ + libclose(fd); + return strdup(tmp2); + } + } + + return strdup(t); +} + +void +refreshslave(Display *d) +{ + int i, n, id; + uchar buf[5*(5*4)], *p; + Rectangle r; + Image *im; + int locked; + + for(;;){ + release(); + n = kchanio(d->refchan, buf, sizeof buf, OREAD); + acquire(); + if(n < 0) /* probably caused by closedisplay() closing refchan */ + return; /* will fall off end of thread and close down */ + locked = lockdisplay(d); + p = buf; + for(i=0; i<n; i+=5*4,p+=5*4){ + id = BGLONG(p+0*4); + r.min.x = BGLONG(p+1*4); + r.min.y = BGLONG(p+2*4); + r.max.x = BGLONG(p+3*4); + r.max.y = BGLONG(p+4*4); + for(im=d->windows; im; im=im->next) + if(im->id == id) + break; + if(im && im->screen && im->reffn) + (*im->reffn)(im, r, im->refptr); + } + flushimage(d, 1); + if(locked) + unlockdisplay(d); + } +} + +void +startrefresh(Display *disp) +{ + USED(disp); +} + +static +int +doflush(Display *d) +{ + int m, n; + char err[ERRMAX]; + uchar *tp; + + n = d->bufp-d->buf; + if(n <= 0) + return 1; + + if(d->local == 0) + release(); + if((m = kchanio(d->datachan, d->buf, n, OWRITE)) != n){ + if(d->local == 0) + acquire(); + kgerrstr(err, sizeof err); + if(_drawdebug || strcmp(err, "screen id in use") != 0 && strcmp(err, exImage) != 0){ + print("flushimage fail: (%d not %d) d=%lux: %s\nbuffer: ", m, n, (ulong)d, err); + for(tp = d->buf; tp < d->bufp; tp++) + print("%.2x ", (int)*tp); + print("\n"); + } + d->bufp = d->buf; /* might as well; chance of continuing */ + return -1; + } + d->bufp = d->buf; + if(d->local == 0) + acquire(); + return 1; +} + +int +flushimage(Display *d, int visible) +{ + int ret; + Refreshq *r; + + for(;;){ + if(visible) + *d->bufp++ = 'v'; /* one byte always reserved for this */ + ret = doflush(d); + if(d->refhead == nil) + break; + while(r = d->refhead){ /* assign = */ + d->refhead = r->next; + if(d->refhead == nil) + d->reftail = nil; + r->reffn(nil, r->r, r->refptr); + free(r); + } + } + return ret; +} + +/* + * Turn off refresh for this window and remove any pending refresh events for it. + */ +void +delrefresh(Image *i) +{ + Refreshq *r, *prev, *next; + int locked; + Display *d; + void *refptr; + + d = i->display; + /* + * Any refresh function will do, because the data pointer is nil. + * Can't use nil, though, because that turns backing store back on. + */ + if(d->local) + drawlsetrefresh(d->dataqid, i->id, memlnorefresh, nil); + refptr = i->refptr; + i->refptr = nil; + if(d->refhead==nil || refptr==nil) + return; + locked = lockdisplay(d); + prev = nil; + for(r=d->refhead; r; r=next){ + next = r->next; + if(r->refptr == refptr){ + if(prev) + prev->next = next; + else + d->refhead = next; + if(d->reftail == r) + d->reftail = prev; + free(r); + }else + prev = r; + } + if(locked) + unlockdisplay(d); +} + +void +queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr) +{ + Display *d; + Refreshq *rq; + + d = i->display; + rq = malloc(sizeof(Refreshq)); + if(rq == nil) + return; + if(d->reftail) + d->reftail->next = rq; + else + d->refhead = rq; + d->reftail = rq; + rq->reffn = reffn; + rq->refptr = refptr; + rq->r = r; +} + +uchar* +bufimage(Display *d, int n) +{ + uchar *p; + + if(n<0 || n>Displaybufsize){ + kwerrstr("bad count in bufimage"); + return 0; + } + if(d->bufp+n > d->buf+Displaybufsize){ + if(d->local==0 && currun()!=libqlowner(d->qlock)) { + print("bufimage: %lux %lux\n", (ulong)libqlowner(d->qlock), (ulong)currun()); + abort(); + } + if(doflush(d) < 0) + return 0; + } + p = d->bufp; + d->bufp += n; + /* return with buffer locked */ + return p; +} + +void +drawerror(Display *d, char *s) +{ + USED(d); + fprint(2, "draw: %s: %r\n", s); +} |
