📄 devdraw.c
字号:
#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"#define Image IMAGE#include "draw.h"#include "memdraw.h"#include "memlayer.h"#include "cursor.h"#include "screen.h"#define blankscreen(x)#define ishwimage(x) (0)enum{ Qtopdir = 0, Qnew, Qwinname, Q3rd, Q2nd, Qcolormap, Qctl, Qdata, Qrefresh,};/* * Qid path is: * 4 bits of file type (qids above) * 24 bits of mux slot number +1; 0 means not attached to client */#define QSHIFT 4 /* location in qid of client # */#define QID(q) ((((ulong)(q).path)&0x0000000F)>>0)#define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT)#define CLIENT(q) CLIENTPATH((q).path)#define NHASH (1<<5)#define HASHMASK (NHASH-1)#define IOUNIT (64*1024)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;ulong blanktime = 30; /* in minutes; a half hour */struct Draw{ int clientid; int nclient; Client** client; int nname; DName* name; int vers; int softscreen; int blanked; /* screen turned off */ ulong blanktime; /* time of last operation */ ulong savemap[3*256];};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; QLock drawlock;static Memimage *screenimage;static DImage* screendimage;static char screenname[40];static int screennameid;static Rectangle flushrect;static int waste;static DScreen* dscreen;extern void flushmemscreen(Rectangle); void drawmesg(Client*, void*, int); void drawuninstall(Client*, int); void drawfreedimage(DImage*); Client* drawclientofpath(ulong); DImage* allocdimage(Memimage*);static char Enodrawimage[] = "unknown id for draw image";static char Enodrawscreen[] = "unknown id for draw screen";static char Eshortdraw[] = "short draw message";static char Eshortread[] = "draw read too short";static char Eimageexists[] = "image id in use";static char Escreenexists[] = "screen id in use";static char Edrawmem[] = "image memory allocation failed";static char Ereadoutside[] = "readimage outside image";static char Ewriteoutside[] = "writeimage outside image";static char Enotfont[] = "image not a font";static char Eindex[] = "character index out of range";static char Enoclient[] = "no such draw client";static char Enameused[] = "image name in use";static char Enoname[] = "no image with that name";static char Eoldname[] = "named image no longer valid";static char Enamed[] = "image already has name";static char Ewrongname[] = "wrong name for image";voiddrawqlock(void){ qlock(&drawlock);}intdrawcanqlock(void){ return canqlock(&drawlock);}voiddrawqunlock(void){ qunlock(&drawlock);}static intdrawgen(Chan *c, char *_, Dirtab *__, int ___, int s, Dir *dp){ int t; Qid q; ulong path; Client *cl; q.vers = 0; if(s == DEVDOTDOT){ switch(QID(c->qid)){ case Qtopdir: case Q2nd: mkqid(&q, Qtopdir, 0, QTDIR); devdir(c, q, "#i", 0, eve, 0500, dp); break; case Q3rd: cl = drawclientofpath(c->qid.path); if(cl == nil) strcpy(up->genbuf, "??"); else sprint(up->genbuf, "%d", cl->clientid); mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, up->genbuf, 0, eve, 0500, dp); break; default: panic("drawwalk %llux", c->qid.path); } return 1; } /* * Top level directory contains the name of the device. */ t = QID(c->qid); if(t == Qtopdir){ switch(s){ case 0: mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, "draw", 0, eve, 0555, dp); break; case 1: mkqid(&q, Qwinname, 0, 0); devdir(c, q, "winname", 0, eve, 0444, dp); break; default: return -1; } return 1; } /* * Second level contains "new" plus all the clients. */ if(t == Q2nd || t == Qnew){ if(s == 0){ mkqid(&q, Qnew, 0, QTFILE); devdir(c, q, "new", 0, eve, 0666, dp); } else if(s <= sdraw.nclient){ cl = sdraw.client[s-1]; if(cl == 0) return 0; sprint(up->genbuf, "%d", cl->clientid); mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR); devdir(c, q, up->genbuf, 0, eve, 0555, dp); return 1; } else return -1; return 1; } /* * Third level. */ path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */ q.vers = c->qid.vers; q.type = QTFILE; switch(s){ case 0: q.path = path|Qcolormap; devdir(c, q, "colormap", 0, eve, 0600, dp); break; case 1: q.path = path|Qctl; devdir(c, q, "ctl", 0, eve, 0600, dp); break; case 2: q.path = path|Qdata; devdir(c, q, "data", 0, eve, 0600, dp); break; case 3: q.path = path|Qrefresh; devdir(c, q, "refresh", 0, eve, 0400, dp); break; default: return -1; } return 1;}staticintdrawrefactive(void *a){ Client *c; c = a; return c->refreshme || c->refresh!=0;}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; 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 = malloc(sizeof(Refresh)); 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){ print("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);}voiddrawflush(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);}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;}intdrawgoodname(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;}DImage*drawlookup(Client *client, int id, int checkname){ DImage *d; d = client->dimage[id&HASHMASK]; while(d){ if(d->id == id){ if(checkname && !drawgoodname(d)) error(Eoldname); return d; } d = d->next; } return 0;}DScreen*drawlookupdscreen(int id){ DScreen *s; s = dscreen; while(s){ if(s->id == id) return s; s = s->next; } return 0;}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; } error(Enodrawscreen); for(;;);}DImage*allocdimage(Memimage *i){ DImage *d; d = malloc(sizeof(DImage)); if(d == 0) return 0; d->ref = 1; d->name = 0; d->vers = 0; d->image = i; d->nfchar = 0; d->fchar = 0; d->fromname = 0; return d;}Memimage*drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen){ DImage *d; d = allocdimage(i); if(d == 0) return 0; d->id = id; d->dscreen = dscreen; d->next = client->dimage[id&HASHMASK]; client->dimage[id&HASHMASK] = d; return i;}Memscreen*drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public){ Memscreen *s; CScreen *c; c = malloc(sizeof(CScreen)); if(dimage && dimage->image && dimage->image->chan == 0) panic("bad image %p in drawinstallscreen", dimage->image); if(c == 0) return 0; if(d == 0){ d = malloc(sizeof(DScreen)); if(d == 0){ free(c); return 0; } s = malloc(sizeof(Memscreen)); 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;}voiddrawdelname(DName *name){ int i; i = name-sdraw.name; memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName)); sdraw.nname--;}voiddrawfreedscreen(DScreen *this){ DScreen *ds, *next; this->ref--; if(this->ref < 0) print("negative ref in drawfreedscreen\n"); if(this->ref > 0) return; ds = dscreen; if(ds == this){ dscreen = this->next; goto Found; } while((next = ds->next)){ /* assign = */ if(next == this){ ds->next = this->next; goto Found; } ds = next; } error(Enodrawimage); Found: if(this->dimage) drawfreedimage(this->dimage); if(this->dfill) drawfreedimage(this->dfill); free(this->screen); free(this);}voiddrawfreedimage(DImage *dimage){ int i; Memimage *l; DScreen *ds; dimage->ref--; if(dimage->ref < 0) print("negative ref in drawfreedimage\n"); if(dimage->ref > 0) return; /* any names? */ for(i=0; i<sdraw.nname; ) if(sdraw.name[i].dimage == dimage) drawdelname(sdraw.name+i); else i++; if(dimage->fromname){ /* acquired by name; owned by someone else*/ drawfreedimage(dimage->fromname); goto Return; } ds = dimage->dscreen; l = dimage->image; dimage->dscreen = nil; /* paranoia */ dimage->image = nil; if(ds){ if(l->data == screenimage->data) addflush(l->layer->screenr); if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */ free(l->layer->refreshptr); l->layer->refreshptr = nil; if(drawgoodname(dimage)) memldelete(l); else memlfree(l); drawfreedscreen(ds); }else freememimage(l); Return: free(dimage->fchar); free(dimage);}voiddrawuninstallscreen(Client *client, CScreen *this){ CScreen *cs, *next; cs = client->cscreen; if(cs == this){ client->cscreen = this->next; drawfreedscreen(this->dscreen); free(this); return; } while((next = cs->next)){ /* assign = */ if(next == this){ cs->next = this->next; drawfreedscreen(this->dscreen); free(this); return; } cs = next; }}voiddrawuninstall(Client *client, int id){ DImage *d, *next; d = client->dimage[id&HASHMASK]; if(d == 0) error(Enodrawimage); if(d->id == id){ client->dimage[id&HASHMASK] = d->next; drawfreedimage(d); return; } while((next = d->next)){ /* assign = */ if(next->id == id){ d->next = next->next; drawfreedimage(next); return; } d = next; } error(Enodrawimage);}voiddrawaddname(Client *client, DImage *di, int n, char *str){ DName *name, *ename, *new, *t; name = sdraw.name; ename = &name[sdraw.nname]; for(; name<ename; name++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -