/* * /dev/draw simulator -- handles the messages prepared by the draw library. * Doesn't simulate the file system part, just the messages. */ #include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <memlayer.h>#include "devdraw.h" extern void _flushmemscreen(Rectangle); #define NHASH (1<<5)#define HASHMASK (NHASH-1) typedef struct Client Client;typedef struct Draw Draw;typedef struct DImage DImage;typedef struct DScreen DScreen;typedef struct CScreen CScreen;typedef struct FChar FChar;typedef struct Refresh Refresh;typedef struct Refx Refx;typedef struct DName DName; struct Draw{ QLock lk; int clientid; int nclient; Client* client[1]; int nname; DName* name; int vers; int softscreen;}; struct Client{ /*Ref r;*/ DImage* dimage[NHASH]; CScreen* cscreen; Refresh* refresh; Rendez refrend; uchar* readdata; int nreaddata; int busy; int clientid; int slot; int refreshme; int infoid; int op;}; struct Refresh{ DImage* dimage; Rectangle r; Refresh* next;}; struct Refx{ Client* client; DImage* dimage;}; struct DName{ char *name; Client *client; DImage* dimage; int vers;}; struct FChar{ int minx; /* left edge of bits */ int maxx; /* right edge of bits */ uchar miny; /* first non-zero scan-line */ uchar maxy; /* last non-zero scan-line + 1 */ schar left; /* offset of baseline */ uchar width; /* width of baseline */}; /* * Reference counts in DImages: * one per open by original client * one per screen image or fill * one per image derived from this one by name */struct DImage{ int id; int ref; char *name; int vers; Memimage* image; int ascent; int nfchar; FChar* fchar; DScreen* dscreen; /* 0 if not a window */ DImage* fromname; /* image this one is derived from, by name */ DImage* next;}; struct CScreen{ DScreen* dscreen; CScreen* next;}; struct DScreen{ int id; int public; int ref; DImage *dimage; DImage *dfill; Memscreen* screen; Client* owner; DScreen* next;}; static Draw sdraw;static Client *client0;static Memimage *screenimage;static Rectangle flushrect;static int waste;static DScreen* dscreen;static int drawuninstall(Client*, int);static Memimage* drawinstall(Client*, int, Memimage*, DScreen*);static void drawfreedimage(DImage*); void_initdisplaymemimage(Memimage *m){ screenimage = m; m->screenref = 1; client0 = mallocz(sizeof(Client), 1); if(client0 == nil){ fprint(2, "initdraw: allocating client0: out of memory"); abort(); } client0->slot = 0; client0->clientid = ++sdraw.clientid; client0->op = SoverD; sdraw.client[0] = client0; sdraw.nclient = 1; sdraw.softscreen = 1;} void_drawreplacescreenimage(Memimage *m){ /* * Replace the screen image because the screen * was resized. * * In theory there should only be one reference * to the current screen image, and that's through * client0's image 0, installed a few lines above. * Once the client drops the image, the underlying backing * store freed properly. The client is being notified * about the resize through external means, so all we * need to do is this assignment. */ Memimage *om; qlock(&sdraw.lk); om = screenimage; screenimage = m; m->screenref = 1; if(om && --om->screenref == 0){ _freememimage(om); } qunlock(&sdraw.lk);} staticvoiddrawrefreshscreen(DImage *l, Client *client){ while(l != nil && l->dscreen == nil) l = l->fromname; if(l != nil && l->dscreen->owner != client) l->dscreen->owner->refreshme = 1;} staticvoiddrawrefresh(Memimage *m, Rectangle r, void *v){ Refx *x; DImage *d; Client *c; Refresh *ref; USED(m); if(v == 0) return; x = v; c = x->client; d = x->dimage; for(ref=c->refresh; ref; ref=ref->next) if(ref->dimage == d){ combinerect(&ref->r, r); return; } ref = mallocz(sizeof(Refresh), 1); if(ref){ ref->dimage = d; ref->r = r; ref->next = c->refresh; c->refresh = ref; }} static voidaddflush(Rectangle r){ int abb, ar, anbb; Rectangle nbb; if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) return; if(flushrect.min.x >= flushrect.max.x){ flushrect = r; waste = 0; return; } nbb = flushrect; combinerect(&nbb, r); ar = Dx(r)*Dy(r); abb = Dx(flushrect)*Dy(flushrect); anbb = Dx(nbb)*Dy(nbb); /* * Area of new waste is area of new bb minus area of old bb, * less the area of the new segment, which we assume is not waste. * This could be negative, but that's OK. */ waste += anbb-abb - ar; if(waste < 0) waste = 0; /* * absorb if: * total area is small * waste is less than half total area * rectangles touch */ if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){ flushrect = nbb; return; } /* emit current state */ if(flushrect.min.x < flushrect.max.x) _flushmemscreen(flushrect); flushrect = r; waste = 0;} staticvoiddstflush(int dstid, Memimage *dst, Rectangle r){ Memlayer *l; if(dstid == 0){ combinerect(&flushrect, r); return; } /* how can this happen? -rsc, dec 12 2002 */ if(dst == 0){ fprint(2, "nil dstflush\n"); return; } l = dst->layer; if(l == nil) return; do{ if(l->screen->image->data != screenimage->data) return; r = rectaddpt(r, l->delta); l = l->screen->image->layer; }while(l); addflush(r);} staticvoiddrawflush(void){ if(flushrect.min.x < flushrect.max.x) _flushmemscreen(flushrect); flushrect = Rect(10000, 10000, -10000, -10000);} staticintdrawcmp(char *a, char *b, int n){ if(strlen(a) != n) return 1; return memcmp(a, b, n);} staticDName*drawlookupname(int n, char *str){ DName *name, *ename; name = sdraw.name; ename = &name[sdraw.nname]; for(; name<ename; name++) if(drawcmp(name->name, str, n) == 0) return name; return 0;} staticintdrawgoodname(DImage *d){ DName *n; /* if window, validate the screen's own images */ if(d->dscreen) if(drawgoodname(d->dscreen->dimage) == 0 || drawgoodname(d->dscreen->dfill) == 0) return 0; if(d->name == nil) return 1; n = drawlookupname(strlen(d->name), d->name); if(n==nil || n->vers!=d->vers) return 0; return 1;} staticDImage*drawlookup(Client *client, int id, int checkname){ DImage *d; d = client->dimage[id&HASHMASK]; while(d){ if(d->id == id){ /* * BUG: should error out but too hard. * Return 0 instead. */ if(checkname && !drawgoodname(d)) return 0; return d; } d = d->next; } return 0;} staticDScreen*drawlookupdscreen(int id){ DScreen *s; s = dscreen; while(s){ if(s->id == id) return s; s = s->next; } return 0;} staticDScreen*drawlookupscreen(Client *client, int id, CScreen **cs){ CScreen *s; s = client->cscreen; while(s){ if(s->dscreen->id == id){ *cs = s; return s->dscreen; } s = s->next; } /* caller must check! */ return 0;} staticMemimage*drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen){ DImage *d; d = mallocz(sizeof(DImage), 1); if(d == 0) return 0; d->id = id; d->ref = 1; d->name = 0; d->vers = 0; d->image = i; if(i->screenref) ++i->screenref; d->nfchar = 0; d->fchar = 0; d->fromname = 0; d->dscreen = dscreen; d->next = client->dimage[id&HASHMASK]; client->dimage[id&HASHMASK] = d; return i;} staticMemscreen*drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public){ Memscreen *s; CScreen *c; c = mallocz(sizeof(CScreen), 1); if(dimage && dimage->image && dimage->image->chan == 0){ fprint(2, "bad image %p in drawinstallscreen", dimage->image); abort(); } if(c == 0) return 0; if(d == 0){ d = mallocz(sizeof(DScreen), 1); if(d == 0){ free(c); return 0; } s = mallocz(sizeof(Memscreen), 1); if(s == 0){ free(c); free(d); return 0; } s->frontmost = 0; s->rearmost = 0; d->dimage = dimage; if(dimage){ s->image = dimage->image; dimage->ref++; } d->dfill = dfill; if(dfill){ s->fill = dfill->image; dfill->ref++; } d->ref = 0; d->id = id; d->screen = s; d->public = public; d->next = dscreen; d->owner = client; dscreen = d; } c->dscreen = d; d->ref++; c->next = client->cscreen; client->cscreen = c; return d->screen;} staticvoiddrawdelname(DName *name){ int i; i = name-sdraw.name; memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName)); sdraw.nname--;} staticvoiddrawfreedscreen(DScreen *this){ DScreen *ds, *next; this->ref--; if(this->ref < 0) fprint(2, "negative ref in drawfreedscreen\n"); if(this->ref > 0) return; ds = dscreen;Lines 1–500 of 1607. Load more
/* * /dev/draw simulator -- handles the messages prepared by the draw library. * Doesn't simulate the file system part, just the messages. */ #include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <memlayer.h> #include "devdraw.h" extern void _flushmemscreen(Rectangle); #define NHASH (1<<5) #define HASHMASK (NHASH-1) typedef struct Client Client; typedef struct Draw Draw; typedef struct DImage DImage; typedef struct DScreen DScreen; typedef struct CScreen CScreen; typedef struct FChar FChar; typedef struct Refresh Refresh; typedef struct Refx Refx; typedef struct DName DName; struct Draw { QLock lk; int clientid; int nclient; Client* client[1]; int nname; DName* name; int vers; int softscreen; }; struct Client { /*Ref r;*/ DImage* dimage[NHASH]; CScreen* cscreen; Refresh* refresh; Rendez refrend; uchar* readdata; int nreaddata; int busy; int clientid; int slot; int refreshme; int infoid; int op; }; struct Refresh { DImage* dimage; Rectangle r; Refresh* next; }; struct Refx { Client* client; DImage* dimage; }; struct DName { char *name; Client *client; DImage* dimage; int vers; }; struct FChar { int minx; /* left edge of bits */ int maxx; /* right edge of bits */ uchar miny; /* first non-zero scan-line */ uchar maxy; /* last non-zero scan-line + 1 */ schar left; /* offset of baseline */ uchar width; /* width of baseline */ }; /* * Reference counts in DImages: * one per open by original client * one per screen image or fill * one per image derived from this one by name */ struct DImage { int id; int ref; char *name; int vers; Memimage* image; int ascent; int nfchar; FChar* fchar; DScreen* dscreen; /* 0 if not a window */ DImage* fromname; /* image this one is derived from, by name */ DImage* next; }; struct CScreen { DScreen* dscreen; CScreen* next; }; struct DScreen { int id; int public; int ref; DImage *dimage; DImage *dfill; Memscreen* screen; Client* owner; DScreen* next; }; static Draw sdraw; static Client *client0; static Memimage *screenimage; static Rectangle flushrect; static int waste; static DScreen* dscreen; static int drawuninstall(Client*, int); static Memimage* drawinstall(Client*, int, Memimage*, DScreen*); static void drawfreedimage(DImage*); void _initdisplaymemimage(Memimage *m) { screenimage = m; m->screenref = 1; client0 = mallocz(sizeof(Client), 1); if(client0 == nil){ fprint(2, "initdraw: allocating client0: out of memory"); abort(); } client0->slot = 0; client0->clientid = ++sdraw.clientid; client0->op = SoverD; sdraw.client[0] = client0; sdraw.nclient = 1; sdraw.softscreen = 1; } void _drawreplacescreenimage(Memimage *m) { /* * Replace the screen image because the screen * was resized. * * In theory there should only be one reference * to the current screen image, and that's through * client0's image 0, installed a few lines above. * Once the client drops the image, the underlying backing * store freed properly. The client is being notified * about the resize through external means, so all we * need to do is this assignment. */ Memimage *om; qlock(&sdraw.lk); om = screenimage; screenimage = m; m->screenref = 1; if(om && --om->screenref == 0){ _freememimage(om); } qunlock(&sdraw.lk); } static void drawrefreshscreen(DImage *l, Client *client) { while(l != nil && l->dscreen == nil) l = l->fromname; if(l != nil && l->dscreen->owner != client) l->dscreen->owner->refreshme = 1; } static void drawrefresh(Memimage *m, Rectangle r, void *v) { Refx *x; DImage *d; Client *c; Refresh *ref; USED(m); if(v == 0) return; x = v; c = x->client; d = x->dimage; for(ref=c->refresh; ref; ref=ref->next) if(ref->dimage == d){ combinerect(&ref->r, r); return; } ref = mallocz(sizeof(Refresh), 1); if(ref){ ref->dimage = d; ref->r = r; ref->next = c->refresh; c->refresh = ref; } } static void addflush(Rectangle r) { int abb, ar, anbb; Rectangle nbb; if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r)) return; if(flushrect.min.x >= flushrect.max.x){ flushrect = r; waste = 0; return; } nbb = flushrect; combinerect(&nbb, r); ar = Dx(r)*Dy(r); abb = Dx(flushrect)*Dy(flushrect); anbb = Dx(nbb)*Dy(nbb); /* * Area of new waste is area of new bb minus area of old bb, * less the area of the new segment, which we assume is not waste. * This could be negative, but that's OK. */ waste += anbb-abb - ar; if(waste < 0) waste = 0; /* * absorb if: * total area is small * waste is less than half total area * rectangles touch */ if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){ flushrect = nbb; return; } /* emit current state */ if(flushrect.min.x < flushrect.max.x) _flushmemscreen(flushrect); flushrect = r; waste = 0; } static void dstflush(int dstid, Memimage *dst, Rectangle r) { Memlayer *l; if(dstid == 0){ combinerect(&flushrect, r); return; } /* how can this happen? -rsc, dec 12 2002 */ if(dst == 0){ fprint(2, "nil dstflush\n"); return; } l = dst->layer; if(l == nil) return; do{ if(l->screen->image->data != screenimage->data) return; r = rectaddpt(r, l->delta); l = l->screen->image->layer; }while(l); addflush(r); } static void drawflush(void) { if(flushrect.min.x < flushrect.max.x) _flushmemscreen(flushrect); flushrect = Rect(10000, 10000, -10000, -10000); } static int drawcmp(char *a, char *b, int n) { if(strlen(a) != n) return 1; return memcmp(a, b, n); } static DName* drawlookupname(int n, char *str) { DName *name, *ename; name = sdraw.name; ename = &name[sdraw.nname]; for(; name<ename; name++) if(drawcmp(name->name, str, n) == 0) return name; return 0; } static int drawgoodname(DImage *d) { DName *n; /* if window, validate the screen's own images */ if(d->dscreen) if(drawgoodname(d->dscreen->dimage) == 0 || drawgoodname(d->dscreen->dfill) == 0) return 0; if(d->name == nil) return 1; n = drawlookupname(strlen(d->name), d->name); if(n==nil || n->vers!=d->vers) return 0; return 1; } static DImage* drawlookup(Client *client, int id, int checkname) { DImage *d; d = client->dimage[id&HASHMASK]; while(d){ if(d->id == id){ /* * BUG: should error out but too hard. * Return 0 instead. */ if(checkname && !drawgoodname(d)) return 0; return d; } d = d->next; } return 0; } static DScreen* drawlookupdscreen(int id) { DScreen *s; s = dscreen; while(s){ if(s->id == id) return s; s = s->next; } return 0; } static DScreen* drawlookupscreen(Client *client, int id, CScreen **cs) { CScreen *s; s = client->cscreen; while(s){ if(s->dscreen->id == id){ *cs = s; return s->dscreen; } s = s->next; } /* caller must check! */ return 0; } static Memimage* drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen) { DImage *d; d = mallocz(sizeof(DImage), 1); if(d == 0) return 0; d->id = id; d->ref = 1; d->name = 0; d->vers = 0; d->image = i; if(i->screenref) ++i->screenref; d->nfchar = 0; d->fchar = 0; d->fromname = 0; d->dscreen = dscreen; d->next = client->dimage[id&HASHMASK]; client->dimage[id&HASHMASK] = d; return i; } static Memscreen* drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public) { Memscreen *s; CScreen *c; c = mallocz(sizeof(CScreen), 1); if(dimage && dimage->image && dimage->image->chan == 0){ fprint(2, "bad image %p in drawinstallscreen", dimage->image); abort(); } if(c == 0) return 0; if(d == 0){ d = mallocz(sizeof(DScreen), 1); if(d == 0){ free(c); return 0; } s = mallocz(sizeof(Memscreen), 1); if(s == 0){ free(c); free(d); return 0; } s->frontmost = 0; s->rearmost = 0; d->dimage = dimage; if(dimage){ s->image = dimage->image; dimage->ref++; } d->dfill = dfill; if(dfill){ s->fill = dfill->image; dfill->ref++; } d->ref = 0; d->id = id; d->screen = s; d->public = public; d->next = dscreen; d->owner = client; dscreen = d; } c->dscreen = d; d->ref++; c->next = client->cscreen; client->cscreen = c; return d->screen; } static void drawdelname(DName *name) { int i; i = name-sdraw.name; memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName)); sdraw.nname--; } static void drawfreedscreen(DScreen *this) { DScreen *ds, *next; this->ref--; if(this->ref < 0) fprint(2, "negative ref in drawfreedscreen\n"); if(this->ref > 0) return; ds = dscreen;