#include "u.h"#include "lib.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" 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; struct Draw{ int clientid; int nclient; Client** client; int nname; DName* name; int vers; int softscreen;}; struct Client{ Ref r; DImage* dimage[NHASH]; CScreen* cscreen; Refresh* refresh; Rendez refrend; QLock refq; 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"; static voiddlock(void){ qlock(&drawlock);} static voiddunlock(void){ qunlock(&drawlock);} static intdrawgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp){ int t; Qid q; ulong path; Client *cl; USED(n); USED(d); USED(nd); 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 || t == Qwinname){ if(s == 1 || t == Qwinname){ mkqid(&q, Qwinname, 0, QTFILE); devdir(c, q, "winname", 0, eve, 0444, dp); } else if(s == 0){ mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, "draw", 0, eve, 0555, dp); } else 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 *i, Rectangle r, void *v){ Refx *x; DImage *d; Client *c; Refresh *ref; USED(i); 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 || screenimage == nil || !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; } if(screenimage == nil || dst == nil || (l = dst->layer) == 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(screenimage && flushrect.min.x < flushrect.max.x) flushmemscreen(flushrect); flushrect = Rect(10000, 10000, -10000, -10000);} intdrawcmp(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; Lines 1–500 of 2145. Load more
#include "u.h" #include "lib.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" 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; struct Draw { int clientid; int nclient; Client** client; int nname; DName* name; int vers; int softscreen; }; struct Client { Ref r; DImage* dimage[NHASH]; CScreen* cscreen; Refresh* refresh; Rendez refrend; QLock refq; 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"; static void dlock(void) { qlock(&drawlock); } static void dunlock(void) { qunlock(&drawlock); } static int drawgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp) { int t; Qid q; ulong path; Client *cl; USED(n); USED(d); USED(nd); 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 || t == Qwinname){ if(s == 1 || t == Qwinname){ mkqid(&q, Qwinname, 0, QTFILE); devdir(c, q, "winname", 0, eve, 0444, dp); } else if(s == 0){ mkqid(&q, Q2nd, 0, QTDIR); devdir(c, q, "draw", 0, eve, 0555, dp); } else 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; } static int drawrefactive(void *a) { Client *c; c = a; return c->refreshme || c->refresh!=0; } 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 *i, Rectangle r, void *v) { Refx *x; DImage *d; Client *c; Refresh *ref; USED(i); 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 void addflush(Rectangle r) { int abb, ar, anbb; Rectangle nbb; if(sdraw.softscreen==0 || screenimage == nil || !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; } if(screenimage == nil || dst == nil || (l = dst->layer) == 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); } void drawflush(void) { if(screenimage && flushrect.min.x < flushrect.max.x) flushmemscreen(flushrect); flushrect = Rect(10000, 10000, -10000, -10000); } int drawcmp(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; } 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; } 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;