📄 devdraw.c
字号:
if(drawcmp(name->name, str, n) == 0) error(Enameused); t = smalloc((sdraw.nname+1)*sizeof(DName)); memmove(t, sdraw.name, sdraw.nname*sizeof(DName)); free(sdraw.name); sdraw.name = t; new = &sdraw.name[sdraw.nname++]; new->name = smalloc(n+1); memmove(new->name, str, n); new->name[n] = 0; new->dimage = di; new->client = client; new->vers = ++sdraw.vers;}Client*drawnewclient(void){ Client *cl, **cp; int i; for(i=0; i<sdraw.nclient; i++){ cl = sdraw.client[i]; if(cl == 0) break; } if(i == sdraw.nclient){ cp = malloc((sdraw.nclient+1)*sizeof(Client*)); if(cp == 0) return 0; memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*)); free(sdraw.client); sdraw.client = cp; sdraw.nclient++; cp[i] = 0; } cl = malloc(sizeof(Client)); if(cl == 0) return 0; memset(cl, 0, sizeof(Client)); cl->slot = i; cl->clientid = ++sdraw.clientid; cl->op = SoverD; sdraw.client[i] = cl; return cl;}static intdrawclientop(Client *cl){ int op; op = cl->op; cl->op = SoverD; return op;}intdrawhasclients(void){ /* * if draw has ever been used, we can't resize the frame buffer, * even if all clients have exited (nclients is cumulative); it's too * hard to make work. */ return sdraw.nclient != 0;}Client*drawclientofpath(ulong path){ Client *cl; int slot; slot = CLIENTPATH(path); if(slot == 0) return nil; cl = sdraw.client[slot-1]; if(cl==0 || cl->clientid==0) return nil; return cl;}Client*drawclient(Chan *c){ Client *client; client = drawclientofpath(c->qid.path); if(client == nil) error(Enoclient); return client;}Memimage*drawimage(Client *client, uchar *a){ DImage *d; d = drawlookup(client, BGLONG(a), 1); if(d == nil) error(Enodrawimage); return d->image;}voiddrawrectangle(Rectangle *r, uchar *a){ r->min.x = BGLONG(a+0*4); r->min.y = BGLONG(a+1*4); r->max.x = BGLONG(a+2*4); r->max.y = BGLONG(a+3*4);}voiddrawpoint(Point *p, uchar *a){ p->x = BGLONG(a+0*4); p->y = BGLONG(a+1*4);}Pointdrawchar(Memimage *dst, Memimage *rdst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op){ FChar *fc; Rectangle r; Point sp1; static Memimage *tmp; fc = &font->fchar[index]; r.min.x = p.x+fc->left; r.min.y = p.y-(font->ascent-fc->miny); r.max.x = r.min.x+(fc->maxx-fc->minx); r.max.y = r.min.y+(fc->maxy-fc->miny); sp1.x = sp->x+fc->left; sp1.y = sp->y+fc->miny; /* * If we're drawing greyscale fonts onto a VGA screen, * it's very costly to read the screen memory to do the * alpha blending inside memdraw. If this is really a stringbg, * then rdst is the bg image (in main memory) which we can * refer to for the underlying dst pixels instead of reading dst * directly. */ if(ishwimage(dst) && !ishwimage(rdst) && font->image->depth > 1){ if(tmp == nil || tmp->chan != dst->chan || Dx(tmp->r) < Dx(r) || Dy(tmp->r) < Dy(r)){ if(tmp) freememimage(tmp); tmp = allocmemimage(Rect(0,0,Dx(r),Dy(r)), dst->chan); if(tmp == nil) goto fallback; } memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), rdst, r.min, memopaque, ZP, S); memdraw(tmp, Rect(0,0,Dx(r),Dy(r)), src, sp1, font->image, Pt(fc->minx, fc->miny), op); memdraw(dst, r, tmp, ZP, memopaque, ZP, S); }else{ fallback: memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op); } p.x += fc->width; sp->x += fc->width; return p;}static DImage*makescreenimage(void){ void *X; int width, depth; ulong chan; DImage *di; Memdata *md; Memimage *i; Rectangle r; md = malloc(sizeof *md); if(md == nil) return nil; md->allocd = 1; md->base = nil; md->bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X); if(md->bdata == nil){ free(md); return nil; } md->ref = 1; i = allocmemimaged(r, chan, md, X); if(i == nil){ free(md); return nil; } i->width = width; i->clipr = r; di = allocdimage(i); if(di == nil){ freememimage(i); /* frees md */ return nil; } if(!waserror()){ snprint(screenname, sizeof screenname, "noborder.screen.%d", ++screennameid); drawaddname(nil, di, strlen(screenname), screenname); poperror(); } return di;}voiddrawreplacescreenimage(Memimage *m){ int i; DImage *di; if(screendimage == nil) return; /* * Replace the screen image because the screen * was resized. Clients still have references to the * old screen image, so we can't free it just yet. */ drawqlock(); di = allocdimage(m); if(di == nil){ print("no memory to replace screen image\n"); freememimage(m); drawqunlock(); return; } /* Replace old screen image in global name lookup. */ for(i=0; i<sdraw.nname; i++){ if(sdraw.name[i].dimage == screendimage) if(sdraw.name[i].client == nil){ sdraw.name[i].dimage = di; break; } } drawfreedimage(screendimage); screendimage = di; screenimage = m; /* * Every client, when it starts, gets a copy of the * screen image as image 0. Clients only use it * for drawing if there is no /dev/winname, but * this /dev/draw provides a winname (early ones * didn't; winname originated in rio), so the * image only ends up used to find the screen * resolution and pixel format during initialization. * Silently remove the now-outdated image 0s. */ for(i=0; i<sdraw.nclient; i++){ if(sdraw.client[i] && !waserror()){ drawuninstall(sdraw.client[i], 0); poperror(); } } drawqunlock(); mouseresize();}static intinitscreenimage(void){ if(screenimage != nil) return 1; screendimage = makescreenimage(); if(screendimage == nil) return 0; screenimage = screendimage->image;// iprint("initscreenimage %p %p\n", screendimage, screenimage); mouseresize(); return 1;}voiddeletescreenimage(void){ drawqlock(); if(screenimage){ /* will be freed via screendimage; disable */ screenimage->clipr = ZR; screenimage = nil; } if(screendimage){ drawfreedimage(screendimage); screendimage = nil; } drawqunlock();}voidresetscreenimage(void){ drawqlock(); initscreenimage(); drawqunlock();}static Chan*drawattach(char *spec){ drawqlock(); if(!conf.monitor || !initscreenimage()){ drawqunlock(); error("no frame buffer"); } drawqunlock(); return devattach('i', spec);}static Walkqid*drawwalk(Chan *c, Chan *nc, char **name, int nname){ if(screenimage == nil) error("no frame buffer"); return devwalk(c, nc, name, nname, 0, 0, drawgen);}static intdrawstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, drawgen);}static Chan*drawopen(Chan *c, int omode){ Client *cl; DName *dn; DImage *di; if(c->qid.type & QTDIR){ c = devopen(c, omode, 0, 0, drawgen); c->iounit = IOUNIT; } drawqlock(); if(waserror()){ drawqunlock(); nexterror(); } if(QID(c->qid) == Qnew){ cl = drawnewclient(); if(cl == 0) error(Enodev); c->qid.path = Qctl|((cl->slot+1)<<QSHIFT); } switch(QID(c->qid)){ case Qwinname: break; case Qnew: break; case Qctl: cl = drawclient(c); if(cl->busy) error(Einuse); cl->busy = 1; flushrect = Rect(10000, 10000, -10000, -10000); dn = drawlookupname(strlen(screenname), screenname); if(dn == 0) error("draw: cannot happen 2"); if(drawinstall(cl, 0, dn->dimage->image, 0) == 0) error(Edrawmem); di = drawlookup(cl, 0, 0); if(di == 0) error("draw: cannot happen 1"); di->vers = dn->vers; di->name = smalloc(strlen(screenname)+1); strcpy(di->name, screenname); di->fromname = dn->dimage; di->fromname->ref++; incref(&cl->r); break; case Qcolormap: case Qdata: case Qrefresh: cl = drawclient(c); incref(&cl->r); break; } drawqunlock(); poperror(); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; c->iounit = IOUNIT; return c;}static voiddrawclose(Chan *c){ int i; DImage *d, **dp; Client *cl; Refresh *r; if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */ return; drawqlock(); if(waserror()){ drawqunlock(); nexterror(); } cl = drawclient(c); if(QID(c->qid) == Qctl) cl->busy = 0; if((c->flag&COPEN) && (decref(&cl->r)==0)){ while((r = cl->refresh)){ /* assign = */ cl->refresh = r->next; free(r); } /* free names */ for(i=0; i<sdraw.nname; ) if(sdraw.name[i].client == cl) drawdelname(sdraw.name+i); else i++; while(cl->cscreen) drawuninstallscreen(cl, cl->cscreen); /* all screens are freed, so now we can free images */ dp = cl->dimage; for(i=0; i<NHASH; i++){ while((d = *dp) != nil){ *dp = d->next; drawfreedimage(d); } dp++; } sdraw.client[cl->slot] = 0; drawflush(); /* to erase visible, now dead windows */ free(cl); } drawqunlock(); poperror();}longdrawread(Chan *c, void *a, long n, vlong off){ int index, m; ulong red, green, blue; Client *cl; uchar *p; Refresh *r; DImage *di; Memimage *i; ulong offset = off; char buf[16]; if(c->qid.type & QTDIR) return devdirread(c, a, n, 0, 0, drawgen); if(QID(c->qid) == Qwinname) return readstr(off, a, n, screenname); cl = drawclient(c); drawqlock(); if(waserror()){ drawqunlock(); nexterror(); } switch(QID(c->qid)){ case Qctl: if(n < 12*12) error(Eshortread); if(cl->infoid < 0) error(Enodrawimage); if(cl->infoid == 0){ i = screenimage; if(i == nil) error(Enodrawimage); }else{ di = drawlookup(cl, cl->infoid, 1); if(di == nil) error(Enodrawimage); i = di->image; } n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ", cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl, i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y, i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); cl->infoid = -1; break; case Qcolormap: drawactive(1); /* to restore map from backup */ p = malloc(4*12*256+1); if(p == 0) error(Enomem); m = 0; for(index = 0; index < 256; index++){ getcolor(index, &red, &green, &blue); m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24); } n = readstr(offset, a, n, (char*)p); free(p); break; case Qdata: if(cl->readdata == nil) error("no draw data"); if(n < cl->nreaddata) error(Eshortread); n = cl->nreaddata; memmove(a, cl->readdata, cl->nreaddata); free(cl->readdata); cl->readdata = nil; break; case Qrefresh: if(n < 5*4) error(Ebadarg); for(;;){ if(cl->refreshme || cl->refresh) break; drawqunlock(); if(waserror()){ drawqlock(); /* restore lock for waserror() above */ nexterror(); } sleep(&cl->refrend, drawrefactive, cl); poperror(); drawqlock(); } p = a; while(cl->refresh && n>=5*4){ r = cl->refresh; BPLONG(p+0*4, r->dimage->id); BPLONG(p+1*4, r->r.min.x); BPLONG(p+2*4, r->r.min.y); BPLONG(p+3*4, r->r.max.x); BPLONG(p+4*4, r->r.max.y); cl->refresh = r->next; free(r); p += 5*4; n -= 5*4; } cl->refreshme = 0; n = p-(uchar*)a; break; } drawqunlock(); poperror(); return n;}voiddrawwakeall(void){ Client *cl; int i; for(i=0; i<sdraw.nclient; i++){ cl = sdraw.client[i]; if(cl && (cl->refreshme || cl->refresh)) wakeup(&cl->refrend); }}static longdrawwrite(Chan *c, void *a, long n, vlong _){ char buf[128], *fields[4], *q; Client *cl; int i, m, red, green, blue, x; if(c->qid.type & QTDIR) error(Eisdir); cl = drawclient(c); drawqlock(); if(waserror()){ drawwakeall(); drawqunlock(); nexterror(); } switch(QID(c->qid)){ case Qctl: if(n != 4) error("unknown draw control request"); cl->infoid = BGLONG((uchar*)a); break; case Qcolormap: drawactive(1); /* to restore map from backup */ m = n; n = 0; while(m > 0){ x = m; if(x > sizeof(buf)-1) x = sizeof(buf)-1; q = memccpy(buf, a, '\n', x); if(q == 0) break; i = q-buf; n += i; a = (char*)a + i; m -= i; *q = 0; if(tokenize(buf, fields, nelem(fields)) != 4) error(Ebadarg); i = strtoul(fields[0], 0, 0); red = strtoul(fields[1], 0, 0); green = strtoul(fields[2], 0, 0); blue = strtoul(fields[3], &q, 0); if(fields[3] == q) error(Ebadarg); if(red>255 || green>255 || blue>255 || i<0 || i>255) error(Ebadarg); red |= red<<8; red |= red<<16; green |= green<<8; green |= green<<16; blue |= blue<<8; blue |= blue<<16; setcolor(i, red, green, blue); } break; case Qdata: drawmesg(cl, a, n); drawwakeall(); break; default: error(Ebadusefd); } drawqunlock(); poperror(); return n;}uchar*drawcoord(uchar *p, uchar *maxp, int oldx, int *newx){ int b, x; if(p >= maxp) error(Eshortdraw); b = *p++; x = b & 0x7F; if(b & 0x80){ if(p+1 >= maxp) error(Eshortdraw); x |= *p++ << 7; x |= *p++ << 15; if(x & (1<<22)) x |= ~0<<23; }else{ if(b & 0x40) x |= ~0<<7; x += oldx; } *newx = x; return p;}static voidprintmesg(char *fmt, uchar *a, int plsprnt){ char buf[256]; char *p, *q; if(1|| plsprnt==0){ return; } q = buf; *q++ = *a++; for(p=fmt; *p; p++){ switch(*p){ case 'l': q += sprint(q, " %ld", (long)BGLONG(a)); a += 4; break; case 'L': q += sprint(q, " %.8lux", (ulong)BGLONG(a)); a += 4; break; case 'R': q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12)); a += 16; break; case 'P': q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4)); a += 8; break; case 'b': q += sprint(q, " %d", *a++); break; case 's': q += sprint(q, " %d", BGSHORT(a)); a += 2; break; case 'S': q += sprint(q, " %.4ux", BGSHORT(a)); a += 2; break; } } *q++ = '\n'; *q = 0; iprint("%.*s", (int)(q-buf), buf);}voiddrawmesg(Client *client, void *av, int n){ int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush; uchar *u, *a, refresh; char *fmt; ulong value, chan; Rectangle r, clipr; Point p, q, *pp, sp; Memimage *i, *bg, *dst, *src, *mask; Memimage *l, **lp; Memscreen *scrn; DImage *font, *ll, *di, *ddst, *dsrc; DName *dn; DScreen *dscrn; FChar *fc; Refx *refx; CScreen *cs; Refreshfn reffn; a = av; m = 0; fmt = nil; if(waserror()){ if(fmt) printmesg(fmt, a, 1); /* iprint("error: %s\n", up->errstr); */ nexterror(); } while((n-=m) > 0){ a += m; switch(*a){ default: error("bad draw command"); /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */ case 'b': printmesg(fmt="LLbLbRRL", a, 0); m = 1+4+4+1+4+1+4*4+4*4+4; if(n < m) error(Eshortdraw); dstid = BGLONG(a+1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -