char* chantostr(char *buf, ulong cc) { ulong c, rc; char *p; if(chantodepth(cc) == 0) return nil; /* reverse the channel descriptor so we can easily generate the string in the right order */ rc = 0; for(c=cc; c; c>>=8){ rc <<= 8; rc |= c&0xFF; } p = buf; for(c=rc; c; c>>=8) { *p++ = channames[TYPE(c)]; *p++ = '0'+NBITS(c); } *p = 0; return buf; }
Memimage* allocmemimage(Rectangle r, ulong chan) { int d; uchar *p; ulong l, nw; Memdata *md; Memimage *i; if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor %.8lux", chan); return nil; } l = wordsperline(r, d); nw = l*Dy(r); md = malloc(sizeof(Memdata)); if(md == nil) return nil; md->ref = 1; md->base = poolalloc(imagmem, sizeof(Memdata*)+(1+nw)*sizeof(ulong)); if(md->base == nil){ free(md); return nil; } p = (uchar*)md->base; *(Memdata**)p = md; p += sizeof(Memdata*); *(ulong*)p = getcallerpc(&r); p += sizeof(ulong); /* if this changes, memimagemove must change too */ md->bdata = p; md->allocd = 1; i = allocmemimaged(r, chan, md); if(i == nil){ poolfree(imagmem, md->base); free(md); return nil; } md->imref = i; return i; }
int memsetchan(Memimage *i, ulong chan) { int d; int t, j, k; ulong cc; int bytes; if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor"); return -1; } i->depth = d; i->chan = chan; i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes); bytes = 1; for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){ t=TYPE(cc); if(t < 0 || t >= NChan){ werrstr("bad channel string"); return -1; } if(t == CGrey) i->flags |= Fgrey; if(t == CAlpha) i->flags |= Falpha; if(t == CMap && i->cmap == nil){ i->cmap = memdefcmap; i->flags |= Fcmap; } i->shift[t] = j; i->mask[t] = (1<<NBITS(cc))-1; i->nbits[t] = NBITS(cc); if(NBITS(cc) != 8) bytes = 0; } i->nchan = k; if(bytes) i->flags |= Fbytes; return 0; }
Memimage* allocmemimaged(Rectangle r, ulong chan, Memdata *md, void *X) { int d; ulong l; Memimage *i; if(Dx(r) <= 0 || Dy(r) <= 0){ werrstr("bad rectangle %R", r); return nil; } if((d = chantodepth(chan)) == 0) { werrstr("bad channel descriptor %.8lux", chan); return nil; } l = wordsperline(r, d); i = mallocz(sizeof(Memimage), 1); if(i == nil) return nil; i->X = X; i->data = md; i->zero = sizeof(ulong)*l*r.min.y; if(r.min.x >= 0) i->zero += (r.min.x*d)/8; else i->zero -= (-r.min.x*d+7)/8; i->zero = -i->zero; i->width = l; i->r = r; i->clipr = r; i->flags = 0; i->layer = nil; i->cmap = memdefcmap; if(memsetchan(i, chan) < 0){ free(i); return nil; } return i; }
Display* initdisplay(char *dev, char *win, void(*error)(Display*, char*)) { char buf[128], info[NINFO+1], *t, isnew; int n, datafd, ctlfd, reffd; Display *disp; Dir *dir; Image *image; fmtinstall('P', Pfmt); fmtinstall('R', Rfmt); if(dev == 0) dev = "/dev"; if(win == 0) win = "/dev"; if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){ werrstr("initdisplay: directory name too long"); return nil; } t = strdup(win); if(t == nil) return nil; sprint(buf, "%s/draw/new", dev); ctlfd = open(buf, ORDWR|OCEXEC); if(ctlfd < 0){ if(bind("#i", dev, MAFTER) < 0){ Error1: free(t); werrstr("initdisplay: %s: %r", buf); return 0; } ctlfd = open(buf, ORDWR|OCEXEC); } if(ctlfd < 0) goto Error1; if((n=read(ctlfd, info, sizeof info)) < 12){ Error2: close(ctlfd); goto Error1; } if(n==NINFO+1) n = NINFO; info[n] = '\0'; isnew = 0; if(n < NINFO) /* this will do for now, we need something better here */ isnew = 1; sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12)); datafd = open(buf, ORDWR|OCEXEC); if(datafd < 0) goto Error2; sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12)); reffd = open(buf, OREAD|OCEXEC); if(reffd < 0){ Error3: close(datafd); goto Error2; } disp = mallocz(sizeof(Display), 1); if(disp == 0){ Error4: close(reffd); goto Error3; } image = nil; if(0){ Error5: free(image); free(disp); goto Error4; } if(n >= NINFO){ image = mallocz(sizeof(Image), 1); if(image == nil) goto Error5; image->display = disp; image->id = 0; image->chan = strtochan(info+2*12); image->depth = chantodepth(image->chan); image->repl = atoi(info+3*12); image->r.min.x = atoi(info+4*12); image->r.min.y = atoi(info+5*12); image->r.max.x = atoi(info+6*12); image->r.max.y = atoi(info+7*12); image->clipr.min.x = atoi(info+8*12); image->clipr.min.y = atoi(info+9*12); image->clipr.max.x = atoi(info+10*12); image->clipr.max.y = atoi(info+11*12); } disp->_isnewdisplay = isnew; disp->bufsize = iounit(datafd); if(disp->bufsize <= 0) disp->bufsize = 8000; if(disp->bufsize < 512){ werrstr("iounit %d too small", disp->bufsize); goto Error5; } disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */ if(disp->buf == nil) goto Error5; disp->image = image; disp->dirno = atoi(info+0*12); disp->fd = datafd; disp->ctlfd = ctlfd; disp->reffd = reffd; disp->bufp = disp->buf; disp->error = error; disp->windir = t; disp->devdir = strdup(dev); qlock(&disp->qlock); disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite); disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack); if(disp->white == nil || disp->black == nil){ free(disp->devdir); free(disp->white); free(disp->black); goto Error5; } disp->opaque = disp->white; disp->transparent = disp->black; dir = dirfstat(ctlfd); if(dir!=nil && dir->type=='i'){ disp->local = 1; disp->dataqid = dir->qid.path; } if(dir!=nil && dir->qid.vers==1) /* other way to tell */ disp->_isnewdisplay = 1; free(dir); return disp; }
Image* _allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh) { uchar *a; char *err; Image *i; Rectangle clipr; int id; int depth; err = 0; i = 0; if(chan == 0){ werrstr("bad channel descriptor"); return nil; } depth = chantodepth(chan); if(depth == 0){ err = "bad channel descriptor"; Error: if(err) werrstr("allocimage: %s", err); else werrstr("allocimage: %r"); free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'b'; BPLONG(a+1, id); BPLONG(a+5, screenid); a[9] = refresh; BPLONG(a+10, chan); a[14] = repl; BPLONG(a+15, r.min.x); BPLONG(a+19, r.min.y); BPLONG(a+23, r.max.x); BPLONG(a+27, r.max.y); if(repl) /* huge but not infinite, so various offsets will leave it huge, not overflow */ clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF); else clipr = r; BPLONG(a+31, clipr.min.x); BPLONG(a+35, clipr.min.y); BPLONG(a+39, clipr.max.x); BPLONG(a+43, clipr.max.y); BPLONG(a+47, val); if(flushimage(d, 0) < 0) goto Error; if(ai) i = ai; else{ i = malloc(sizeof(Image)); if(i == nil){ a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } } i->display = d; i->id = id; i->depth = depth; i->chan = chan; i->r = r; i->clipr = clipr; i->repl = repl; i->screen = 0; i->next = 0; return i; }
Image* namedimage(Display *d, char *name) { uchar *a; char *err, buf[12*12+1]; Image *i; int id, n; ulong chan; err = 0; i = 0; n = strlen(name); if(n >= 256){ err = "name too long"; Error: if(err) werrstr("namedimage: %s", err); else werrstr("namedimage: %r"); if(i) free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+1+n); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'n'; BPLONG(a+1, id); a[5] = n; memmove(a+6, name, n); if(flushimage(d, 0) < 0) goto Error; if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12) goto Error; buf[12*12] = '\0'; i = malloc(sizeof(Image)); if(i == nil){ Error1: a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } i->display = d; i->id = id; if((chan=strtochan(buf+2*12))==0){ werrstr("bad channel '%.12s' from devdraw", buf+2*12); goto Error1; } i->chan = chan; i->depth = chantodepth(chan); i->repl = atoi(buf+3*12); i->r.min.x = atoi(buf+4*12); i->r.min.y = atoi(buf+5*12); i->r.max.x = atoi(buf+6*12); i->r.max.y = atoi(buf+7*12); i->clipr.min.x = atoi(buf+8*12); i->clipr.min.y = atoi(buf+9*12); i->clipr.max.x = atoi(buf+10*12); i->clipr.max.y = atoi(buf+11*12); i->screen = 0; i->next = 0; return i; }
static void vgactl(Cmdbuf *cb) { int align, i, size, x, y, z; char *chanstr, *p; ulong chan; Cmdtab *ct; VGAscr *scr; extern VGAdev *vgadev[]; extern VGAcur *vgacur[]; scr = &vgascreen[0]; ct = lookupcmd(cb, vgactlmsg, nelem(vgactlmsg)); switch(ct->index) { case CMhwgc: if(strcmp(cb->f[1], "off") == 0) { lock(&cursor); if(scr->cur) { if(scr->cur->disable) scr->cur->disable(scr); scr->cur = nil; } unlock(&cursor); return; } if(strcmp(cb->f[1], "soft") == 0) { lock(&cursor); swcursorinit(); if(scr->cur && scr->cur->disable) scr->cur->disable(scr); scr->cur = &swcursor; if(scr->cur->enable) scr->cur->enable(scr); unlock(&cursor); return; } for(i = 0; vgacur[i]; i++) { if(strcmp(cb->f[1], vgacur[i]->name)) continue; lock(&cursor); if(scr->cur && scr->cur->disable) scr->cur->disable(scr); scr->cur = vgacur[i]; if(scr->cur->enable) scr->cur->enable(scr); unlock(&cursor); return; } break; case CMtype: for(i = 0; vgadev[i]; i++) { if(strcmp(cb->f[1], vgadev[i]->name)) continue; if(scr->dev && scr->dev->disable) scr->dev->disable(scr); scr->dev = vgadev[i]; if(scr->dev->enable) scr->dev->enable(scr); return; } break; case CMtextmode: screeninit(); return; case CMsize: x = strtoul(cb->f[1], &p, 0); if(x == 0 || x > 10240) error(Ebadarg); if(*p) p++; y = strtoul(p, &p, 0); if(y == 0 || y > 10240) error(Ebadarg); if(*p) p++; z = strtoul(p, &p, 0); chanstr = cb->f[2]; if((chan = strtochan(chanstr)) == 0) error("bad channel"); if(chantodepth(chan) != z) error("depth, channel do not match"); cursoroff(1); deletescreenimage(); if(screensize(x, y, z, chan)) error(Egreg); vgascreenwin(scr); resetscreenimage(); cursoron(1); return; case CMactualsize: if(scr->gscreen == nil) error("set the screen size first"); x = strtoul(cb->f[1], &p, 0); if(x == 0 || x > 2048) error(Ebadarg); if(*p) p++; y = strtoul(p, nil, 0); if(y == 0 || y > 2048) error(Ebadarg); if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y) error("physical screen bigger than virtual"); physgscreenr = Rect(0,0,x,y); scr->gscreen->clipr = physgscreenr; return; case CMpalettedepth: x = strtoul(cb->f[1], &p, 0); if(x != 8 && x != 6) error(Ebadarg); scr->palettedepth = x; return; case CMdrawinit: memimagedraw(scr->gscreen, scr->gscreen->r, memblack, ZP, nil, ZP, S); if(scr && scr->dev && scr->dev->drawinit) scr->dev->drawinit(scr); return; case CMlinear: if(cb->nf!=2 && cb->nf!=3) error(Ebadarg); size = strtoul(cb->f[1], 0, 0); if(cb->nf == 2) align = 0; else align = strtoul(cb->f[2], 0, 0); if(screenaperture(size, align) < 0) error("not enough free address space"); return; /* case CMmemset: memset((void*)strtoul(cb->f[1], 0, 0), atoi(cb->f[2]), atoi(cb->f[3])); return; */ case CMblank: drawblankscreen(1); return; case CMunblank: drawblankscreen(0); return; case CMblanktime: blanktime = strtoul(cb->f[1], 0, 0); return; case CMpanning: if(strcmp(cb->f[1], "on") == 0) { if(scr == nil || scr->cur == nil) error("set screen first"); if(!scr->cur->doespanning) error("panning not supported"); scr->gscreen->clipr = scr->gscreen->r; panning = 1; } else if(strcmp(cb->f[1], "off") == 0) { scr->gscreen->clipr = physgscreenr; panning = 0; } else break; return; case CMhwaccel: if(strcmp(cb->f[1], "on") == 0) hwaccel = 1; else if(strcmp(cb->f[1], "off") == 0) hwaccel = 0; else break; return; case CMhwblank: if(strcmp(cb->f[1], "on") == 0) hwblank = 1; else if(strcmp(cb->f[1], "off") == 0) hwblank = 0; else break; return; } cmderror(cb, "bad VGA control message"); }
static void vgactl(char* a) { int align, i, n, size, x, y, z; char *chanstr, *field[6], *p; ulong chan; VGAscr *scr; extern VGAdev *vgadev[]; extern VGAcur *vgacur[]; Rectangle r; n = tokenize(a, field, nelem(field)); if(n < 1) error(Ebadarg); scr = &vgascreen[0]; if(strcmp(field[0], "hwgc") == 0){ if(n < 2) error(Ebadarg); if(strcmp(field[1], "off") == 0){ lock(&cursor); if(scr->cur){ if(scr->cur->disable) scr->cur->disable(scr); scr->cur = nil; } unlock(&cursor); return; } for(i = 0; vgacur[i]; i++){ if(strcmp(field[1], vgacur[i]->name)) continue; lock(&cursor); if(scr->cur && scr->cur->disable) scr->cur->disable(scr); scr->cur = vgacur[i]; if(scr->cur->enable) scr->cur->enable(scr); unlock(&cursor); return; } } else if(strcmp(field[0], "type") == 0){ if(n < 2) error(Ebadarg); for(i = 0; vgadev[i]; i++){ if(strcmp(field[1], vgadev[i]->name)) continue; if(scr->dev && scr->dev->disable) scr->dev->disable(scr); scr->dev = vgadev[i]; if(scr->dev->enable) scr->dev->enable(scr); return; } } else if(strcmp(field[0], "size") == 0){ if(n < 3) error(Ebadarg); if(drawhasclients()) error(Ebusy); x = strtoul(field[1], &p, 0); if(x == 0 || x > 2048) error(Ebadarg); if(*p) p++; y = strtoul(p, &p, 0); if(y == 0 || y > 2048) error(Ebadarg); if(*p) p++; z = strtoul(p, &p, 0); chanstr = field[2]; if((chan = strtochan(chanstr)) == 0) error("bad channel"); if(chantodepth(chan) != z) error("depth, channel do not match"); cursoroff(1); deletescreenimage(); if(screensize(x, y, z, chan)) error(Egreg); vgascreenwin(scr); cursoron(1); return; } else if(strcmp(field[0], "actualsize") == 0){ if(scr->gscreen == nil) error("set the screen size first"); if(n < 2) error(Ebadarg); x = strtoul(field[1], &p, 0); if(x == 0 || x > 2048) error(Ebadarg); if(*p) p++; y = strtoul(p, nil, 0); if(y == 0 || y > 2048) error(Ebadarg); if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y) error("physical screen bigger than virtual"); r = Rect(0,0,x,y); if(!eqrect(r, scr->gscreen->r)){ if(scr->cur == nil || scr->cur->doespanning == 0) error("virtual screen not supported"); } physgscreenr = r; return; } else if(strcmp(field[0], "palettedepth") == 0){ if(n < 2) error(Ebadarg); x = strtoul(field[1], &p, 0); if(x != 8 && x != 6) error(Ebadarg); scr->palettedepth = x; return; } else if(strcmp(field[0], "drawinit") == 0){ if(scr && scr->dev && scr->dev->drawinit) scr->dev->drawinit(scr); return; } else if(strcmp(field[0], "linear") == 0){ if(n < 2) error(Ebadarg); size = strtoul(field[1], 0, 0); if(n < 3) align = 0; else align = strtoul(field[2], 0, 0); if(screenaperture(size, align)) error("not enough free address space"); return; } /* else if(strcmp(field[0], "memset") == 0){ if(n < 4) error(Ebadarg); memset((void*)strtoul(field[1], 0, 0), atoi(field[2]), atoi(field[3])); return; } */ else if(strcmp(field[0], "blank") == 0){ if(n < 1) error(Ebadarg); drawblankscreen(1); return; } else if(strcmp(field[0], "blanktime") == 0){ if(n < 2) error(Ebadarg); blanktime = strtoul(field[1], 0, 0); return; } else if(strcmp(field[0], "hwaccel") == 0){ if(n < 2) error(Ebadarg); if(strcmp(field[1], "on") == 0) hwaccel = 1; else if(strcmp(field[1], "off") == 0) hwaccel = 0; return; } else if(strcmp(field[0], "hwblank") == 0){ if(n < 2) error(Ebadarg); if(strcmp(field[1], "on") == 0) hwblank = 1; else if(strcmp(field[1], "off") == 0) hwblank = 0; return; } error(Ebadarg); }
static void xread(Req *r) { int i, size, height, ascent; vlong path; Fmt fmt; XFont *f; char *data; Memsubfont *sf; Memimage *m; path = r->fid->qid.path; switch(QTYPE(path)) { case Qroot: dirread9p(r, rootgen, nil); break; case Qfontdir: dirread9p(r, fontgen, r->fid); break; case Qsizedir: dirread9p(r, sizegen, r->fid); break; case Qfontfile: fmtstrinit(&fmt); f = &xfont[QFONT(path)]; load(f); if(f->unit == 0 && f->loadheight == nil) { readstr(r, "font missing\n"); break; } height = 0; ascent = 0; if(f->unit > 0) { height = f->height * (int)QSIZE(path)/f->unit + 0.99999999; ascent = height - (int)(-f->originy * (int)QSIZE(path)/f->unit + 0.99999999); } if(f->loadheight != nil) f->loadheight(f, QSIZE(path), &height, &ascent); fmtprint(&fmt, "%11d %11d\n", height, ascent); for(i=0; i<nelem(f->range); i++) { if(f->range[i] == 0) continue; fmtprint(&fmt, "0x%04x 0x%04x x%04x.bit\n", i*SubfontSize, ((i+1)*SubfontSize) - 1, i*SubfontSize); } data = fmtstrflush(&fmt); readstr(r, data); free(data); break; case Qsubfontfile: f = &xfont[QFONT(path)]; load(f); if(r->fid->aux == nil) { r->fid->aux = mksubfont(f, f->name, QRANGE(path)*SubfontSize, ((QRANGE(path)+1)*SubfontSize)-1, QSIZE(path), QANTIALIAS(path)); if(r->fid->aux == nil) { responderrstr(r); return; } } sf = r->fid->aux; m = sf->bits; if(r->ifcall.offset < 5*12) { char *chan; if(QANTIALIAS(path)) chan = "k8"; else chan = "k1"; data = smprint("%11s %11d %11d %11d %11d ", chan, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y); readstr(r, data); free(data); break; } r->ifcall.offset -= 5*12; size = bytesperline(m->r, chantodepth(m->chan)) * Dy(m->r); if(r->ifcall.offset < size) { readbuf(r, byteaddr(m, m->r.min), size); break; } r->ifcall.offset -= size; data = emalloc9p(3*12+6*(sf->n+1)); sprint(data, "%11d %11d %11d ", sf->n, sf->height, sf->ascent); packinfo(sf->info, (uchar*)data+3*12, sf->n); readbuf(r, data, 3*12+6*(sf->n+1)); free(data); break; } respond(r, nil); }