📄 xfid.c
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h"#define MAXSNARF 100*1024char Einuse[] = "file in use";char Edeleted[] = "window deleted";char Ebadreq[] = "bad graphics request";char Etooshort[] = "buffer too small";char Ebadtile[] = "unknown tile";char Eshort[] = "short i/o request";char Elong[] = "snarf buffer too long";char Eunkid[] = "unknown id in attach";char Ebadrect[] = "bad rectangle in attach";char Ewindow[] = "cannot make window";char Enowindow[] = "window has no image";char Ebadmouse[] = "bad format on /dev/mouse";char Ebadwrect[] = "rectangle outside screen";char Ebadoffset[] = "window read not on scan line boundary";extern char Eperm[];static Xfid *xfidfree;static Xfid *xfid;static Channel *cxfidalloc; /* chan(Xfid*) */static Channel *cxfidfree; /* chan(Xfid*) */static char *tsnarf;static int ntsnarf;voidxfidallocthread(void*){ Xfid *x; enum { Alloc, Free, N }; static Alt alts[N+1]; alts[Alloc].c = cxfidalloc; alts[Alloc].v = nil; alts[Alloc].op = CHANRCV; alts[Free].c = cxfidfree; alts[Free].v = &x; alts[Free].op = CHANRCV; alts[N].op = CHANEND; for(;;){ switch(alt(alts)){ case Alloc: x = xfidfree; if(x) xfidfree = x->free; else{ x = emalloc(sizeof(Xfid)); x->c = chancreate(sizeof(void(*)(Xfid*)), 0); x->flushc = chancreate(sizeof(int), 0); /* notification only; no data */ x->flushtag = -1; x->next = xfid; xfid = x; threadcreate(xfidctl, x, 16384); } if(x->ref != 0){ fprint(2, "%p incref %ld\n", x, x->ref); error("incref"); } if(x->flushtag != -1) error("flushtag in allocate"); incref(x); sendp(cxfidalloc, x); break; case Free: if(x->ref != 0){ fprint(2, "%p decref %ld\n", x, x->ref); error("decref"); } if(x->flushtag != -1) error("flushtag in free"); x->free = xfidfree; xfidfree = x; break; } }}Channel*xfidinit(void){ cxfidalloc = chancreate(sizeof(Xfid*), 0); cxfidfree = chancreate(sizeof(Xfid*), 0); threadcreate(xfidallocthread, nil, STACK); return cxfidalloc;}voidxfidctl(void *arg){ Xfid *x; void (*f)(Xfid*); char buf[64]; x = arg; snprint(buf, sizeof buf, "xfid.%p", x); threadsetname(buf); for(;;){ f = recvp(x->c); (*f)(x); if(decref(x) == 0) sendp(cxfidfree, x); }}voidxfidflush(Xfid *x){ Fcall t; Xfid *xf; for(xf=xfid; xf; xf=xf->next) if(xf->flushtag == x->oldtag){ xf->flushtag = -1; xf->flushing = TRUE; incref(xf); /* to hold data structures up at tail of synchronization */ if(xf->ref == 1) error("ref 1 in flush"); if(canqlock(&xf->active)){ qunlock(&xf->active); sendul(xf->flushc, 0); }else{ qlock(&xf->active); /* wait for him to finish */ qunlock(&xf->active); } xf->flushing = FALSE; if(decref(xf) == 0) sendp(cxfidfree, xf); break; } filsysrespond(x->fs, x, &t, nil);}voidxfidattach(Xfid *x){ Fcall t; int id, hideit, scrollit; Window *w; char *err, *n, *dir, errbuf[ERRMAX]; int pid, newlymade; Rectangle r; Image *i; t.qid = x->f->qid; qlock(&all); w = nil; err = Eunkid; newlymade = FALSE; hideit = 0; if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */ n = x->aname+1; pid = strtoul(n, &n, 0); if(*n == ',') n++; r.min.x = strtoul(n, &n, 0); if(*n == ',') n++; r.min.y = strtoul(n, &n, 0); if(*n == ',') n++; r.max.x = strtoul(n, &n, 0); if(*n == ',') n++; r.max.y = strtoul(n, &n, 0); Allocate: if(!goodrect(r)) err = Ebadrect; else{ if(hideit) i = allocimage(display, r, screen->chan, 0, DWhite); else i = allocwindow(wscreen, r, Refbackup, DWhite); if(i){ border(i, r, Selborder, display->black, ZP); if(pid == 0) pid = -1; /* make sure we don't pop a shell! - UGH */ w = new(i, hideit, scrolling, pid, nil, nil, nil); flushimage(display, 1); newlymade = TRUE; }else err = Ewindow; } }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */ pid = 0; if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0) err = errbuf; else goto Allocate; }else{ id = atoi(x->aname); w = wlookid(id); } x->f->w = w; if(w == nil){ qunlock(&all); x->f->busy = FALSE; filsysrespond(x->fs, x, &t, err); return; } if(!newlymade) /* counteract dec() in winshell() */ incref(w); qunlock(&all); filsysrespond(x->fs, x, &t, nil);}voidxfidopen(Xfid *x){ Fcall t; Window *w; w = x->f->w; if(w->deleted){ filsysrespond(x->fs, x, &t, Edeleted); return; } switch(FILE(x->f->qid)){ case Qconsctl: if(w->ctlopen){ filsysrespond(x->fs, x, &t, Einuse); return; } w->ctlopen = TRUE; break; case Qkbdin: if(w != wkeyboard){ filsysrespond(x->fs, x, &t, Eperm); return; } break; case Qmouse: if(w->mouseopen){ filsysrespond(x->fs, x, &t, Einuse); return; } /* * Reshaped: there's a race if the appl. opens the * window, is resized, and then opens the mouse, * but that's rare. The alternative is to generate * a resized event every time a new program starts * up in a window that has been resized since the * dawn of time. We choose the lesser evil. */ w->resized = FALSE; w->mouseopen = TRUE; break; case Qsnarf: if(x->mode==ORDWR || x->mode==OWRITE){ if(tsnarf) free(tsnarf); /* collision, but OK */ ntsnarf = 0; tsnarf = malloc(1); } break; case Qwctl: if(x->mode==OREAD || x->mode==ORDWR){ /* * It would be much nicer to implement fan-out for wctl reads, * so multiple people can see the resizings, but rio just isn't * structured for that. It's structured for /dev/cons, which gives * alternate data to alternate readers. So to keep things sane for * wctl, we compromise and give an error if two people try to * open it. Apologies. */ if(w->wctlopen){ filsysrespond(x->fs, x, &t, Einuse); return; } w->wctlopen = TRUE; w->wctlready = 1; wsendctlmesg(w, Wakeup, ZR, nil); } break; } t.qid = x->f->qid; t.iounit = messagesize-IOHDRSZ; x->f->open = TRUE; x->f->mode = x->mode; filsysrespond(x->fs, x, &t, nil);}voidxfidclose(Xfid *x){ Fcall t; Window *w; int nb, nulls; w = x->f->w; switch(FILE(x->f->qid)){ case Qconsctl: if(w->rawing){ w->rawing = FALSE; wsendctlmesg(w, Rawoff, ZR, nil); } if(w->holding){ w->holding = FALSE; wsendctlmesg(w, Holdoff, ZR, nil); } w->ctlopen = FALSE; break; case Qcursor: w->cursorp = nil; wsetcursor(w, FALSE); break; case Qmouse: w->resized = FALSE; w->mouseopen = FALSE; if(w->i != nil) wsendctlmesg(w, Refresh, w->i->r, nil); break; /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */ case Qsnarf: if(x->f->mode==ORDWR || x->f->mode==OWRITE){ snarf = runerealloc(snarf, ntsnarf+1); cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls); free(tsnarf); tsnarf = nil; ntsnarf = 0; } break; case Qwctl: if(x->f->mode==OREAD || x->f->mode==ORDWR) w->wctlopen = FALSE; break; } wclose(w); filsysrespond(x->fs, x, &t, nil);}voidxfidwrite(Xfid *x){ Fcall fc; int c, cnt, qid, nb, off, nr; char buf[256], *p; Point pt; Window *w; Rune *r; Conswritemesg cwm; Stringpair pair; enum { CWdata, CWflush, NCW }; Alt alts[NCW+1]; w = x->f->w; if(w->deleted){ filsysrespond(x->fs, x, &fc, Edeleted); return; } qid = FILE(x->f->qid); cnt = x->count; off = x->offset; x->data[cnt] = 0; switch(qid){ case Qcons: nr = x->f->nrpart; if(nr > 0){ memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */ memmove(x->data, x->f->rpart, nr); cnt += nr; x->f->nrpart = 0; } r = runemalloc(cnt); cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil); /* approach end of buffer */ while(fullrune(x->data+nb, cnt-nb)){ c = nb; nb += chartorune(&r[nr], x->data+c); if(r[nr]) nr++; } if(nb < cnt){ memmove(x->f->rpart, x->data+nb, cnt-nb); x->f->nrpart = cnt-nb; } x->flushtag = x->tag; alts[CWdata].c = w->conswrite; alts[CWdata].v = &cwm; alts[CWdata].op = CHANRCV; alts[CWflush].c = x->flushc; alts[CWflush].v = nil; alts[CWflush].op = CHANRCV; alts[NCW].op = CHANEND; switch(alt(alts)){ case CWdata: break; case CWflush: filsyscancel(x); return; } /* received data */ x->flushtag = -1; if(x->flushing){ recv(x->flushc, nil); /* wake up flushing xfid */ pair.s = runemalloc(1); pair.ns = 0; send(cwm.cw, &pair); /* wake up window with empty data */ filsyscancel(x); return; } qlock(&x->active); pair.s = r; pair.ns = nr; send(cwm.cw, &pair); fc.count = x->count; filsysrespond(x->fs, x, &fc, nil);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -