#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*); voiddrawmodinit(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 intdrawhash(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;} voidcacheuninstall(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;} voidDisplay_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);} voidDisplay_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);} voidDisplay_startrefresh(void *fp){ F_Display_startrefresh *f; Display *disp; f = fp; disp = checkdisplay(f->d); refreshslave(disp);} voiddisplay_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);} voidfreedrawdisplay(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 */} voidDisplay_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);Lines 1–500 of 2345. Load more
#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);