123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701 |
- #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 <complete.h>
- #include "dat.h"
- #include "fns.h"
- #define MOVEIT if(0)
- enum
- {
- HiWater = 640000, /* max size of history */
- LoWater = 400000, /* min size of history after max'ed */
- MinWater = 20000, /* room to leave available when reallocating */
- };
- static int topped;
- static int id;
- static Image *cols[NCOL];
- static Image *grey;
- static Image *darkgrey;
- static Cursor *lastcursor;
- static Image *titlecol;
- static Image *lighttitlecol;
- static Image *holdcol;
- static Image *lightholdcol;
- static Image *paleholdcol;
- Window*
- wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
- {
- Window *w;
- Rectangle r;
- if(cols[0] == nil){
- /* greys are multiples of 0x11111100+0xFF, 14* being palest */
- grey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
- darkgrey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
- cols[BACK] = display->white;
- cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
- cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF);
- cols[TEXT] = display->black;
- cols[HTEXT] = display->black;
- titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
- lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
- holdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
- lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
- paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
- }
- w = emalloc(sizeof(Window));
- w->screenr = i->r;
- r = insetrect(i->r, Selborder+1);
- w->i = i;
- w->mc = *mc;
- w->ck = ck;
- w->cctl = cctl;
- w->cursorp = nil;
- w->conswrite = chancreate(sizeof(Conswritemesg), 0);
- w->consread = chancreate(sizeof(Consreadmesg), 0);
- w->mouseread = chancreate(sizeof(Mousereadmesg), 0);
- w->wctlread = chancreate(sizeof(Consreadmesg), 0);
- w->scrollr = r;
- w->scrollr.max.x = r.min.x+Scrollwid;
- w->lastsr = ZR;
- r.min.x += Scrollwid+Scrollgap;
- frinit(w, r, font, i, cols);
- w->maxtab = maxtab*stringwidth(font, "0");
- w->topped = ++topped;
- w->id = ++id;
- w->notefd = -1;
- w->scrolling = scrolling;
- w->dir = estrdup(startdir);
- w->label = estrdup("<unnamed>");
- r = insetrect(w->i->r, Selborder);
- draw(w->i, r, cols[BACK], nil, w->entire.min);
- wborder(w, Selborder);
- wscrdraw(w);
- incref(w); /* ref will be removed after mounting; avoids delete before ready to be deleted */
- return w;
- }
- void
- wsetname(Window *w)
- {
- int i, n;
- char err[ERRMAX];
-
- n = sprint(w->name, "window.%d.%d", w->id, w->namecount++);
- for(i='A'; i<='Z'; i++){
- if(nameimage(w->i, w->name, 1) > 0)
- return;
- errstr(err, sizeof err);
- if(strcmp(err, "image name in use") != 0)
- break;
- w->name[n] = i;
- w->name[n+1] = 0;
- }
- w->name[0] = 0;
- fprint(2, "rio: setname failed: %s\n", err);
- }
- void
- wresize(Window *w, Image *i, int move)
- {
- Rectangle r, or;
- or = w->i->r;
- if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
- draw(i, i->r, w->i, nil, w->i->r.min);
- freeimage(w->i);
- w->i = i;
- wsetname(w);
- w->mc.image = i;
- r = insetrect(i->r, Selborder+1);
- w->scrollr = r;
- w->scrollr.max.x = r.min.x+Scrollwid;
- w->lastsr = ZR;
- r.min.x += Scrollwid+Scrollgap;
- if(move)
- frsetrects(w, r, w->i);
- else{
- frclear(w, FALSE);
- frinit(w, r, w->font, w->i, cols);
- wsetcols(w);
- w->maxtab = maxtab*stringwidth(w->font, "0");
- r = insetrect(w->i->r, Selborder);
- draw(w->i, r, cols[BACK], nil, w->entire.min);
- wfill(w);
- wsetselect(w, w->q0, w->q1);
- wscrdraw(w);
- }
- wborder(w, Selborder);
- w->topped = ++topped;
- w->resized = TRUE;
- w->mouse.counter++;
- }
- void
- wrefresh(Window *w, Rectangle)
- {
- /* BUG: rectangle is ignored */
- if(w == input)
- wborder(w, Selborder);
- else
- wborder(w, Unselborder);
- if(w->mouseopen)
- return;
- draw(w->i, insetrect(w->i->r, Borderwidth), w->cols[BACK], nil, w->i->r.min);
- w->ticked = 0;
- if(w->p0 > 0)
- frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
- if(w->p1 < w->nchars)
- frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
- frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
- w->lastsr = ZR;
- wscrdraw(w);
- }
- int
- wclose(Window *w)
- {
- int i;
- i = decref(w);
- if(i > 0)
- return 0;
- if(i < 0)
- error("negative ref count");
- if(!w->deleted)
- wclosewin(w);
- wsendctlmesg(w, Exited, ZR, nil);
- return 1;
- }
- void
- winctl(void *arg)
- {
- Rune *rp, *bp, *tp, *up, *kbdr;
- uint qh;
- int nr, nb, c, wid, i, npart, initial, lastb;
- char *s, *t, part[3];
- Window *w;
- Mousestate *mp, m;
- enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
- Alt alts[NWALT+1];
- Mousereadmesg mrm;
- Conswritemesg cwm;
- Consreadmesg crm;
- Consreadmesg cwrm;
- Stringpair pair;
- Wctlmesg wcm;
- char buf[4*12+1];
- w = arg;
- snprint(buf, sizeof buf, "winctl-id%d", w->id);
- threadsetname(buf);
- mrm.cm = chancreate(sizeof(Mouse), 0);
- cwm.cw = chancreate(sizeof(Stringpair), 0);
- crm.c1 = chancreate(sizeof(Stringpair), 0);
- crm.c2 = chancreate(sizeof(Stringpair), 0);
- cwrm.c1 = chancreate(sizeof(Stringpair), 0);
- cwrm.c2 = chancreate(sizeof(Stringpair), 0);
-
- alts[WKey].c = w->ck;
- alts[WKey].v = &kbdr;
- alts[WKey].op = CHANRCV;
- alts[WMouse].c = w->mc.c;
- alts[WMouse].v = &w->mc.Mouse;
- alts[WMouse].op = CHANRCV;
- alts[WMouseread].c = w->mouseread;
- alts[WMouseread].v = &mrm;
- alts[WMouseread].op = CHANSND;
- alts[WCtl].c = w->cctl;
- alts[WCtl].v = &wcm;
- alts[WCtl].op = CHANRCV;
- alts[WCwrite].c = w->conswrite;
- alts[WCwrite].v = &cwm;
- alts[WCwrite].op = CHANSND;
- alts[WCread].c = w->consread;
- alts[WCread].v = &crm;
- alts[WCread].op = CHANSND;
- alts[WWread].c = w->wctlread;
- alts[WWread].v = &cwrm;
- alts[WWread].op = CHANSND;
- alts[NWALT].op = CHANEND;
- npart = 0;
- lastb = -1;
- for(;;){
- if(w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
- alts[WMouseread].op = CHANSND;
- else
- alts[WMouseread].op = CHANNOP;
- if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->nchars)
- alts[WCwrite].op = CHANNOP;
- else
- alts[WCwrite].op = CHANSND;
- if(w->deleted || !w->wctlready)
- alts[WWread].op = CHANNOP;
- else
- alts[WWread].op = CHANSND;
- /* this code depends on NL and EOT fitting in a single byte */
- /* kind of expensive for each loop; worth precomputing? */
- if(w->holding)
- alts[WCread].op = CHANNOP;
- else if(npart || (w->rawing && w->nraw>0))
- alts[WCread].op = CHANSND;
- else{
- alts[WCread].op = CHANNOP;
- for(i=w->qh; i<w->nr; i++){
- c = w->r[i];
- if(c=='\n' || c=='\004'){
- alts[WCread].op = CHANSND;
- break;
- }
- }
- }
- switch(alt(alts)){
- case WKey:
- for(i=0; kbdr[i]!=L'\0'; i++)
- wkeyctl(w, kbdr[i]);
- // wkeyctl(w, r);
- /// while(nbrecv(w->ck, &r))
- // wkeyctl(w, r);
- break;
- case WMouse:
- if(w->mouseopen) {
- w->mouse.counter++;
- /* queue click events */
- if(!w->mouse.qfull && lastb != w->mc.buttons) { /* add to ring */
- mp = &w->mouse.queue[w->mouse.wi];
- if(++w->mouse.wi == nelem(w->mouse.queue))
- w->mouse.wi = 0;
- if(w->mouse.wi == w->mouse.ri)
- w->mouse.qfull = TRUE;
- mp->Mouse = w->mc;
- mp->counter = w->mouse.counter;
- lastb = w->mc.buttons;
- }
- } else
- wmousectl(w);
- break;
- case WMouseread:
- /* send a queued event or, if the queue is empty, the current state */
- /* if the queue has filled, we discard all the events it contained. */
- /* the intent is to discard frantic clicking by the user during long latencies. */
- w->mouse.qfull = FALSE;
- if(w->mouse.wi != w->mouse.ri) {
- m = w->mouse.queue[w->mouse.ri];
- if(++w->mouse.ri == nelem(w->mouse.queue))
- w->mouse.ri = 0;
- } else
- m = (Mousestate){w->mc.Mouse, w->mouse.counter};
- w->mouse.lastcounter = m.counter;
- send(mrm.cm, &m.Mouse);
- continue;
- case WCtl:
- if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
- chanfree(crm.c1);
- chanfree(crm.c2);
- chanfree(mrm.cm);
- chanfree(cwm.cw);
- chanfree(cwrm.c1);
- chanfree(cwrm.c2);
- threadexits(nil);
- }
- continue;
- case WCwrite:
- recv(cwm.cw, &pair);
- rp = pair.s;
- nr = pair.ns;
- bp = rp;
- for(i=0; i<nr; i++)
- if(*bp++ == '\b'){
- --bp;
- initial = 0;
- tp = runemalloc(nr);
- runemove(tp, rp, i);
- up = tp+i;
- for(; i<nr; i++){
- *up = *bp++;
- if(*up == '\b')
- if(up == tp)
- initial++;
- else
- --up;
- else
- up++;
- }
- if(initial){
- if(initial > w->qh)
- initial = w->qh;
- qh = w->qh-initial;
- wdelete(w, qh, qh+initial);
- w->qh = qh;
- }
- free(rp);
- rp = tp;
- nr = up-tp;
- rp[nr] = 0;
- break;
- }
- w->qh = winsert(w, rp, nr, w->qh)+nr;
- if(w->scrolling || w->mouseopen)
- wshow(w, w->qh);
- wsetselect(w, w->q0, w->q1);
- wscrdraw(w);
- free(rp);
- break;
- case WCread:
- recv(crm.c1, &pair);
- t = pair.s;
- nb = pair.ns;
- i = npart;
- npart = 0;
- if(i)
- memmove(t, part, i);
- while(i<nb && (w->qh<w->nr || w->nraw>0)){
- if(w->qh == w->nr){
- wid = runetochar(t+i, &w->raw[0]);
- w->nraw--;
- runemove(w->raw, w->raw+1, w->nraw);
- }else
- wid = runetochar(t+i, &w->r[w->qh++]);
- c = t[i]; /* knows break characters fit in a byte */
- i += wid;
- if(!w->rawing && (c == '\n' || c=='\004')){
- if(c == '\004')
- i--;
- break;
- }
- }
- if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
- w->qh++;
- if(i > nb){
- npart = i-nb;
- memmove(part, t+nb, npart);
- i = nb;
- }
- pair.s = t;
- pair.ns = i;
- send(crm.c2, &pair);
- continue;
- case WWread:
- w->wctlready = 0;
- recv(cwrm.c1, &pair);
- if(w->deleted || w->i==nil)
- pair.ns = sprint(pair.s, "");
- else{
- s = "visible";
- for(i=0; i<nhidden; i++)
- if(hidden[i] == w){
- s = "hidden";
- break;
- }
- t = "notcurrent";
- if(w == input)
- t = "current";
- pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %s %s ",
- w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);
- }
- send(cwrm.c2, &pair);
- continue;
- }
- if(!w->deleted)
- flushimage(display, 1);
- }
- }
- void
- waddraw(Window *w, Rune *r, int nr)
- {
- w->raw = runerealloc(w->raw, w->nraw+nr);
- runemove(w->raw+w->nraw, r, nr);
- w->nraw += nr;
- }
- /*
- * Need to do this in a separate proc because if process we're interrupting
- * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
- */
- void
- interruptproc(void *v)
- {
- int *notefd;
- notefd = v;
- write(*notefd, "interrupt", 9);
- free(notefd);
- }
- int
- windfilewidth(Window *w, uint q0, int oneelement)
- {
- uint q;
- Rune r;
- q = q0;
- while(q > 0){
- r = w->r[q-1];
- if(r<=' ')
- break;
- if(oneelement && r=='/')
- break;
- --q;
- }
- return q0-q;
- }
- void
- showcandidates(Window *w, Completion *c)
- {
- int i;
- Fmt f;
- Rune *rp;
- uint nr, qline, q0;
- char *s;
- runefmtstrinit(&f);
- if (c->nmatch == 0)
- s = "[no matches in ";
- else
- s = "[";
- if(c->nfile > 32)
- fmtprint(&f, "%s%d files]\n", s, c->nfile);
- else{
- fmtprint(&f, "%s", s);
- for(i=0; i<c->nfile; i++){
- if(i > 0)
- fmtprint(&f, " ");
- fmtprint(&f, "%s", c->filename[i]);
- }
- fmtprint(&f, "]\n");
- }
- /* place text at beginning of line before host point */
- qline = w->qh;
- while(qline>0 && w->r[qline-1] != '\n')
- qline--;
- rp = runefmtstrflush(&f);
- nr = runestrlen(rp);
- q0 = w->q0;
- q0 += winsert(w, rp, runestrlen(rp), qline) - qline;
- free(rp);
- wsetselect(w, q0+nr, q0+nr);
- }
- Rune*
- namecomplete(Window *w)
- {
- int nstr, npath;
- Rune *rp, *path, *str;
- Completion *c;
- char *s, *dir, *root;
- /* control-f: filename completion; works back to white space or / */
- if(w->q0<w->nr && w->r[w->q0]>' ') /* must be at end of word */
- return nil;
- nstr = windfilewidth(w, w->q0, TRUE);
- str = runemalloc(nstr);
- runemove(str, w->r+(w->q0-nstr), nstr);
- npath = windfilewidth(w, w->q0-nstr, FALSE);
- path = runemalloc(npath);
- runemove(path, w->r+(w->q0-nstr-npath), npath);
- rp = nil;
- /* is path rooted? if not, we need to make it relative to window path */
- if(npath>0 && path[0]=='/'){
- dir = malloc(UTFmax*npath+1);
- sprint(dir, "%.*S", npath, path);
- }else{
- if(strcmp(w->dir, "") == 0)
- root = ".";
- else
- root = w->dir;
- dir = malloc(strlen(root)+1+UTFmax*npath+1);
- sprint(dir, "%s/%.*S", root, npath, path);
- }
- dir = cleanname(dir);
- s = smprint("%.*S", nstr, str);
- c = complete(dir, s);
- free(s);
- if(c == nil)
- goto Return;
- if(!c->advance)
- showcandidates(w, c);
- if(c->advance)
- rp = runesmprint("%s", c->string);
- Return:
- freecompletion(c);
- free(dir);
- free(path);
- free(str);
- return rp;
- }
- void
- wkeyctl(Window *w, Rune r)
- {
- uint q0 ,q1;
- int n, nb, nr;
- Rune *rp;
- int *notefd;
- if(r == 0)
- return;
- if(w->deleted)
- return;
- /* navigation keys work only when mouse is not open */
- if(!w->mouseopen)
- switch(r){
- case Kdown:
- n = w->maxlines/3;
- goto case_Down;
- case Kscrollonedown:
- n = mousescrollsize(w->maxlines);
- if(n <= 0)
- n = 1;
- goto case_Down;
- case Kpgdown:
- n = 2*w->maxlines/3;
- case_Down:
- q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+n*w->font->height));
- wsetorigin(w, q0, TRUE);
- return;
- case Kup:
- n = w->maxlines/3;
- goto case_Up;
- case Kscrolloneup:
- n = mousescrollsize(w->maxlines);
- if(n <= 0)
- n = 1;
- goto case_Up;
- case Kpgup:
- n = 2*w->maxlines/3;
- case_Up:
- q0 = wbacknl(w, w->org, n);
- wsetorigin(w, q0, TRUE);
- return;
- case Kleft:
- if(w->q0 > 0){
- q0 = w->q0-1;
- wsetselect(w, q0, q0);
- wshow(w, q0);
- }
- return;
- case Kright:
- if(w->q1 < w->nr){
- q1 = w->q1+1;
- wsetselect(w, q1, q1);
- wshow(w, q1);
- }
- return;
- case Khome:
- wshow(w, 0);
- return;
- case Kend:
- wshow(w, w->nr);
- return;
- case 0x01: /* ^A: beginning of line */
- if(w->q0==0 || w->q0==w->qh || w->r[w->q0-1]=='\n')
- return;
- nb = wbswidth(w, 0x15 /* ^U */);
- wsetselect(w, w->q0-nb, w->q0-nb);
- wshow(w, w->q0);
- return;
- case 0x05: /* ^E: end of line */
- q0 = w->q0;
- while(q0 < w->nr && w->r[q0]!='\n')
- q0++;
- wsetselect(w, q0, q0);
- wshow(w, w->q0);
- return;
- }
- if(w->rawing && (w->q0==w->nr || w->mouseopen)){
- waddraw(w, &r, 1);
- return;
- }
- if(r==0x1B || (w->holding && r==0x7F)){ /* toggle hold */
- if(w->holding)
- --w->holding;
- else
- w->holding++;
- wrepaint(w);
- if(r == 0x1B)
- return;
- }
- if(r != 0x7F){
- wsnarf(w);
- wcut(w);
- }
- switch(r){
- case 0x7F: /* send interrupt */
- w->qh = w->nr;
- wshow(w, w->qh);
- notefd = emalloc(sizeof(int));
- *notefd = w->notefd;
- proccreate(interruptproc, notefd, 4096);
- return;
- case 0x06: /* ^F: file name completion */
- case Kins: /* Insert: file name completion */
- rp = namecomplete(w);
- if(rp == nil)
- return;
- nr = runestrlen(rp);
- q0 = w->q0;
- q0 = winsert(w, rp, nr, q0);
- wshow(w, q0+nr);
- free(rp);
- return;
- case 0x08: /* ^H: erase character */
- case 0x15: /* ^U: erase line */
- case 0x17: /* ^W: erase word */
- if(w->q0==0 || w->q0==w->qh)
- return;
- nb = wbswidth(w, r);
- q1 = w->q0;
- q0 = q1-nb;
- if(q0 < w->org){
- q0 = w->org;
- nb = q1-q0;
- }
- if(nb > 0){
- wdelete(w, q0, q0+nb);
- wsetselect(w, q0, q0);
- }
- return;
- }
- /* otherwise ordinary character; just insert */
- q0 = w->q0;
- q0 = winsert(w, &r, 1, q0);
- wshow(w, q0+1);
- }
- void
- wsetcols(Window *w)
- {
- if(w->holding)
- if(w == input)
- w->cols[TEXT] = w->cols[HTEXT] = holdcol;
- else
- w->cols[TEXT] = w->cols[HTEXT] = lightholdcol;
- else
- if(w == input)
- w->cols[TEXT] = w->cols[HTEXT] = display->black;
- else
- w->cols[TEXT] = w->cols[HTEXT] = darkgrey;
- }
- void
- wrepaint(Window *w)
- {
- wsetcols(w);
- if(!w->mouseopen){
- if(font->maxdepth > 1)
- draw(w->Frame.b, w->Frame.r, cols[BACK], nil, ZP);
- _frredraw(w, w->Frame.r.min);
- }
- if(w == input){
- wborder(w, Selborder);
- wsetcursor(w, 0);
- }else
- wborder(w, Unselborder);
- }
- int
- wbswidth(Window *w, Rune c)
- {
- uint q, eq, stop;
- Rune r;
- int skipping;
- /* there is known to be at least one character to erase */
- if(c == 0x08) /* ^H: erase character */
- return 1;
- q = w->q0;
- stop = 0;
- if(q > w->qh)
- stop = w->qh;
- skipping = TRUE;
- while(q > stop){
- r = w->r[q-1];
- if(r == '\n'){ /* eat at most one more character */
- if(q == w->q0) /* eat the newline */
- --q;
- break;
- }
- if(c == 0x17){
- eq = isalnum(r);
- if(eq && skipping) /* found one; stop skipping */
- skipping = FALSE;
- else if(!eq && !skipping)
- break;
- }
- --q;
- }
- return w->q0-q;
- }
- void
- wsnarf(Window *w)
- {
- if(w->q1 == w->q0)
- return;
- nsnarf = w->q1-w->q0;
- snarf = runerealloc(snarf, nsnarf);
- snarfversion++; /* maybe modified by parent */
- runemove(snarf, w->r+w->q0, nsnarf);
- putsnarf();
- }
- void
- wcut(Window *w)
- {
- if(w->q1 == w->q0)
- return;
- wdelete(w, w->q0, w->q1);
- wsetselect(w, w->q0, w->q0);
- }
- void
- wpaste(Window *w)
- {
- uint q0;
- if(nsnarf == 0)
- return;
- wcut(w);
- q0 = w->q0;
- if(w->rawing && q0==w->nr){
- waddraw(w, snarf, nsnarf);
- wsetselect(w, q0, q0);
- }else{
- q0 = winsert(w, snarf, nsnarf, w->q0);
- wsetselect(w, q0, q0+nsnarf);
- }
- }
- void
- wplumb(Window *w)
- {
- Plumbmsg *m;
- static int fd = -2;
- char buf[32];
- uint p0, p1;
- Cursor *c;
- if(fd == -2)
- fd = plumbopen("send", OWRITE|OCEXEC);
- if(fd < 0)
- return;
- m = emalloc(sizeof(Plumbmsg));
- m->src = estrdup("rio");
- m->dst = nil;
- m->wdir = estrdup(w->dir);
- m->type = estrdup("text");
- p0 = w->q0;
- p1 = w->q1;
- if(w->q1 > w->q0)
- m->attr = nil;
- else{
- while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
- p0--;
- while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
- p1++;
- sprint(buf, "click=%d", w->q0-p0);
- m->attr = plumbunpackattr(buf);
- }
- if(p1-p0 > messagesize-1024){
- plumbfree(m);
- return; /* too large for 9P */
- }
- m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
- if(plumbsend(fd, m) < 0){
- c = lastcursor;
- riosetcursor(&query, 1);
- sleep(300);
- riosetcursor(c, 1);
- }
- plumbfree(m);
- }
- int
- winborder(Window *w, Point xy)
- {
- return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
- }
- void
- wmousectl(Window *w)
- {
- int but;
- if(w->mc.buttons == 1)
- but = 1;
- else if(w->mc.buttons == 2)
- but = 2;
- else if(w->mc.buttons == 4)
- but = 3;
- else{
- if(w->mc.buttons == 8)
- wkeyctl(w, Kscrolloneup);
- if(w->mc.buttons == 16)
- wkeyctl(w, Kscrollonedown);
- return;
- }
- incref(w); /* hold up window while we track */
- if(w->deleted)
- goto Return;
- if(ptinrect(w->mc.xy, w->scrollr)){
- if(but)
- wscroll(w, but);
- goto Return;
- }
- if(but == 1)
- wselect(w);
- /* else all is handled by main process */
- Return:
- wclose(w);
- }
- void
- wdelete(Window *w, uint q0, uint q1)
- {
- uint n, p0, p1;
- n = q1-q0;
- if(n == 0)
- return;
- runemove(w->r+q0, w->r+q1, w->nr-q1);
- w->nr -= n;
- if(q0 < w->q0)
- w->q0 -= min(n, w->q0-q0);
- if(q0 < w->q1)
- w->q1 -= min(n, w->q1-q0);
- if(q1 < w->qh)
- w->qh -= n;
- else if(q0 < w->qh)
- w->qh = q0;
- if(q1 <= w->org)
- w->org -= n;
- else if(q0 < w->org+w->nchars){
- p1 = q1 - w->org;
- if(p1 > w->nchars)
- p1 = w->nchars;
- if(q0 < w->org){
- w->org = q0;
- p0 = 0;
- }else
- p0 = q0 - w->org;
- frdelete(w, p0, p1);
- wfill(w);
- }
- }
- static Window *clickwin;
- static uint clickmsec;
- static Window *selectwin;
- static uint selectq;
- /*
- * called from frame library
- */
- void
- framescroll(Frame *f, int dl)
- {
- if(f != &selectwin->Frame)
- error("frameselect not right frame");
- wframescroll(selectwin, dl);
- }
- void
- wframescroll(Window *w, int dl)
- {
- uint q0;
- if(dl == 0){
- wscrsleep(w, 100);
- return;
- }
- if(dl < 0){
- q0 = wbacknl(w, w->org, -dl);
- if(selectq > w->org+w->p0)
- wsetselect(w, w->org+w->p0, selectq);
- else
- wsetselect(w, selectq, w->org+w->p0);
- }else{
- if(w->org+w->nchars == w->nr)
- return;
- q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
- if(selectq >= w->org+w->p1)
- wsetselect(w, w->org+w->p1, selectq);
- else
- wsetselect(w, selectq, w->org+w->p1);
- }
- wsetorigin(w, q0, TRUE);
- }
- void
- wselect(Window *w)
- {
- uint q0, q1;
- int b, x, y, first;
- first = 1;
- selectwin = w;
- /*
- * Double-click immediately if it might make sense.
- */
- b = w->mc.buttons;
- q0 = w->q0;
- q1 = w->q1;
- selectq = w->org+frcharofpt(w, w->mc.xy);
- if(clickwin==w && w->mc.msec-clickmsec<500)
- if(q0==q1 && selectq==w->q0){
- wdoubleclick(w, &q0, &q1);
- wsetselect(w, q0, q1);
- flushimage(display, 1);
- x = w->mc.xy.x;
- y = w->mc.xy.y;
- /* stay here until something interesting happens */
- do
- readmouse(&w->mc);
- while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
- w->mc.xy.x = x; /* in case we're calling frselect */
- w->mc.xy.y = y;
- q0 = w->q0; /* may have changed */
- q1 = w->q1;
- selectq = q0;
- }
- if(w->mc.buttons == b){
- w->scroll = framescroll;
- frselect(w, &w->mc);
- /* horrible botch: while asleep, may have lost selection altogether */
- if(selectq > w->nr)
- selectq = w->org + w->p0;
- w->Frame.scroll = nil;
- if(selectq < w->org)
- q0 = selectq;
- else
- q0 = w->org + w->p0;
- if(selectq > w->org+w->nchars)
- q1 = selectq;
- else
- q1 = w->org+w->p1;
- }
- if(q0 == q1){
- if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
- wdoubleclick(w, &q0, &q1);
- clickwin = nil;
- }else{
- clickwin = w;
- clickmsec = w->mc.msec;
- }
- }else
- clickwin = nil;
- wsetselect(w, q0, q1);
- flushimage(display, 1);
- while(w->mc.buttons){
- w->mc.msec = 0;
- b = w->mc.buttons;
- if(b & 6){
- if(b & 2){
- wsnarf(w);
- wcut(w);
- }else{
- if(first){
- first = 0;
- getsnarf();
- }
- wpaste(w);
- }
- }
- wscrdraw(w);
- flushimage(display, 1);
- while(w->mc.buttons == b)
- readmouse(&w->mc);
- clickwin = nil;
- }
- }
- void
- wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
- {
- Wctlmesg wcm;
- wcm.type = type;
- wcm.r = r;
- wcm.image = image;
- send(w->cctl, &wcm);
- }
- int
- wctlmesg(Window *w, int m, Rectangle r, Image *i)
- {
- char buf[64];
- switch(m){
- default:
- error("unknown control message");
- break;
- case Wakeup:
- break;
- case Moved:
- case Reshaped:
- if(w->deleted){
- freeimage(i);
- break;
- }
- w->screenr = r;
- strcpy(buf, w->name);
- wresize(w, i, m==Moved);
- w->wctlready = 1;
- proccreate(deletetimeoutproc, estrdup(buf), 4096);
- if(Dx(r) > 0){
- if(w != input)
- wcurrent(w);
- }else if(w == input)
- wcurrent(nil);
- flushimage(display, 1);
- break;
- case Refresh:
- if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
- break;
- if(!w->mouseopen)
- wrefresh(w, r);
- flushimage(display, 1);
- break;
- case Movemouse:
- if(sweeping || !ptinrect(r.min, w->i->r))
- break;
- wmovemouse(w, r.min);
- case Rawon:
- break;
- case Rawoff:
- if(w->deleted)
- break;
- while(w->nraw > 0){
- wkeyctl(w, w->raw[0]);
- --w->nraw;
- runemove(w->raw, w->raw+1, w->nraw);
- }
- break;
- case Holdon:
- case Holdoff:
- if(w->deleted)
- break;
- wrepaint(w);
- flushimage(display, 1);
- break;
- case Deleted:
- if(w->deleted)
- break;
- write(w->notefd, "hangup", 6);
- proccreate(deletetimeoutproc, estrdup(w->name), 4096);
- wclosewin(w);
- break;
- case Exited:
- frclear(w, TRUE);
- close(w->notefd);
- chanfree(w->mc.c);
- chanfree(w->ck);
- chanfree(w->cctl);
- chanfree(w->conswrite);
- chanfree(w->consread);
- chanfree(w->mouseread);
- chanfree(w->wctlread);
- free(w->raw);
- free(w->r);
- free(w->dir);
- free(w->label);
- free(w);
- break;
- }
- return m;
- }
- /*
- * Convert back to physical coordinates
- */
- void
- wmovemouse(Window *w, Point p)
- {
- p.x += w->screenr.min.x-w->i->r.min.x;
- p.y += w->screenr.min.y-w->i->r.min.y;
- moveto(mousectl, p);
- }
- void
- wborder(Window *w, int type)
- {
- Image *col;
- if(w->i == nil)
- return;
- if(w->holding){
- if(type == Selborder)
- col = holdcol;
- else
- col = paleholdcol;
- }else{
- if(type == Selborder)
- col = titlecol;
- else
- col = lighttitlecol;
- }
- border(w->i, w->i->r, Selborder, col, ZP);
- }
- Window*
- wpointto(Point pt)
- {
- int i;
- Window *v, *w;
- w = nil;
- for(i=0; i<nwindow; i++){
- v = window[i];
- if(ptinrect(pt, v->screenr))
- if(!v->deleted)
- if(w==nil || v->topped>w->topped)
- w = v;
- }
- return w;
- }
- void
- wcurrent(Window *w)
- {
- Window *oi;
- if(wkeyboard!=nil && w==wkeyboard)
- return;
- oi = input;
- input = w;
- if(oi!=w && oi!=nil)
- wrepaint(oi);
- if(w !=nil){
- wrepaint(w);
- wsetcursor(w, 0);
- }
- if(w != oi){
- if(oi){
- oi->wctlready = 1;
- wsendctlmesg(oi, Wakeup, ZR, nil);
- }
- if(w){
- w->wctlready = 1;
- wsendctlmesg(w, Wakeup, ZR, nil);
- }
- }
- }
- void
- wsetcursor(Window *w, int force)
- {
- Cursor *p;
- if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
- p = nil;
- else if(wpointto(mouse->xy) == w){
- p = w->cursorp;
- if(p==nil && w->holding)
- p = &whitearrow;
- }else
- p = nil;
- if(!menuing)
- riosetcursor(p, force && !menuing);
- }
- void
- riosetcursor(Cursor *p, int force)
- {
- if(!force && p==lastcursor)
- return;
- setcursor(mousectl, p);
- lastcursor = p;
- }
- Window*
- wtop(Point pt)
- {
- Window *w;
- w = wpointto(pt);
- if(w){
- if(w->topped == topped)
- return nil;
- topwindow(w->i);
- wcurrent(w);
- flushimage(display, 1);
- w->topped = ++topped;
- }
- return w;
- }
- void
- wtopme(Window *w)
- {
- if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
- topwindow(w->i);
- flushimage(display, 1);
- w->topped = ++ topped;
- }
- }
- void
- wbottomme(Window *w)
- {
- if(w!=nil && w->i!=nil && !w->deleted){
- bottomwindow(w->i);
- flushimage(display, 1);
- w->topped = - ++topped;
- }
- }
- Window*
- wlookid(int id)
- {
- int i;
- for(i=0; i<nwindow; i++)
- if(window[i]->id == id)
- return window[i];
- return nil;
- }
- void
- wclosewin(Window *w)
- {
- Rectangle r;
- int i;
- w->deleted = TRUE;
- if(w == input){
- input = nil;
- wsetcursor(w, 0);
- }
- if(w == wkeyboard)
- wkeyboard = nil;
- for(i=0; i<nhidden; i++)
- if(hidden[i] == w){
- --nhidden;
- memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
- break;
- }
- for(i=0; i<nwindow; i++)
- if(window[i] == w){
- --nwindow;
- memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
- w->deleted = TRUE;
- r = w->i->r;
- /* move it off-screen to hide it, in case client is slow in letting it go */
- MOVEIT originwindow(w->i, r.min, view->r.max);
- freeimage(w->i);
- w->i = nil;
- return;
- }
- error("unknown window in closewin");
- }
- void
- wsetpid(Window *w, int pid, int dolabel)
- {
- char buf[128];
- int fd;
- w->pid = pid;
- if(dolabel){
- sprint(buf, "rc %d", pid);
- free(w->label);
- w->label = estrdup(buf);
- }
- sprint(buf, "/proc/%d/notepg", pid);
- fd = open(buf, OWRITE|OCEXEC);
- if(w->notefd > 0)
- close(w->notefd);
- w->notefd = fd;
- }
- void
- winshell(void *args)
- {
- Window *w;
- Channel *pidc;
- void **arg;
- char *cmd, *dir;
- char **argv;
- arg = args;
- w = arg[0];
- pidc = arg[1];
- cmd = arg[2];
- argv = arg[3];
- dir = arg[4];
- rfork(RFNAMEG|RFFDG|RFENVG);
- if(filsysmount(filsys, w->id) < 0){
- fprint(2, "mount failed: %r\n");
- sendul(pidc, 0);
- threadexits("mount failed");
- }
- close(0);
- if(open("/dev/cons", OREAD) < 0){
- fprint(2, "can't open /dev/cons: %r\n");
- sendul(pidc, 0);
- threadexits("/dev/cons");
- }
- close(1);
- if(open("/dev/cons", OWRITE) < 0){
- fprint(2, "can't open /dev/cons: %r\n");
- sendul(pidc, 0);
- threadexits("open"); /* BUG? was terminate() */
- }
- if(wclose(w) == 0){ /* remove extra ref hanging from creation */
- notify(nil);
- dup(1, 2);
- if(dir)
- chdir(dir);
- procexec(pidc, cmd, argv);
- _exits("exec failed");
- }
- }
- static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
- static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
- static Rune left2[] = { L'\n', 0 };
- static Rune left3[] = { L'\'', L'"', L'`', 0 };
- Rune *left[] = {
- left1,
- left2,
- left3,
- nil
- };
- Rune *right[] = {
- right1,
- left2,
- left3,
- nil
- };
- void
- wdoubleclick(Window *w, uint *q0, uint *q1)
- {
- int c, i;
- Rune *r, *l, *p;
- uint q;
- for(i=0; left[i]!=nil; i++){
- q = *q0;
- l = left[i];
- r = right[i];
- /* try matching character to left, looking right */
- if(q == 0)
- c = '\n';
- else
- c = w->r[q-1];
- p = strrune(l, c);
- if(p != nil){
- if(wclickmatch(w, c, r[p-l], 1, &q))
- *q1 = q-(c!='\n');
- return;
- }
- /* try matching character to right, looking left */
- if(q == w->nr)
- c = '\n';
- else
- c = w->r[q];
- p = strrune(r, c);
- if(p != nil){
- if(wclickmatch(w, c, l[p-r], -1, &q)){
- *q1 = *q0+(*q0<w->nr && c=='\n');
- *q0 = q;
- if(c!='\n' || q!=0 || w->r[0]=='\n')
- (*q0)++;
- }
- return;
- }
- }
- /* try filling out word to right */
- while(*q1<w->nr && isalnum(w->r[*q1]))
- (*q1)++;
- /* try filling out word to left */
- while(*q0>0 && isalnum(w->r[*q0-1]))
- (*q0)--;
- }
- int
- wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
- {
- Rune c;
- int nest;
- nest = 1;
- for(;;){
- if(dir > 0){
- if(*q == w->nr)
- break;
- c = w->r[*q];
- (*q)++;
- }else{
- if(*q == 0)
- break;
- (*q)--;
- c = w->r[*q];
- }
- if(c == cr){
- if(--nest==0)
- return 1;
- }else if(c == cl)
- nest++;
- }
- return cl=='\n' && nest==1;
- }
- uint
- wbacknl(Window *w, uint p, uint n)
- {
- int i, j;
- /* look for start of this line if n==0 */
- if(n==0 && p>0 && w->r[p-1]!='\n')
- n = 1;
- i = n;
- while(i-->0 && p>0){
- --p; /* it's at a newline now; back over it */
- if(p == 0)
- break;
- /* at 128 chars, call it a line anyway */
- for(j=128; --j>0 && p>0; p--)
- if(w->r[p-1]=='\n')
- break;
- }
- return p;
- }
- void
- wshow(Window *w, uint q0)
- {
- int qe;
- int nl;
- uint q;
- qe = w->org+w->nchars;
- if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
- wscrdraw(w);
- else{
- nl = 4*w->maxlines/5;
- q = wbacknl(w, q0, nl);
- /* avoid going backwards if trying to go forwards - long lines! */
- if(!(q0>w->org && q<w->org))
- wsetorigin(w, q, TRUE);
- while(q0 > w->org+w->nchars)
- wsetorigin(w, w->org+1, FALSE);
- }
- }
- void
- wsetorigin(Window *w, uint org, int exact)
- {
- int i, a, fixup;
- Rune *r;
- uint n;
- if(org>0 && !exact){
- /* org is an estimate of the char posn; find a newline */
- /* don't try harder than 256 chars */
- for(i=0; i<256 && org<w->nr; i++){
- if(w->r[org] == '\n'){
- org++;
- break;
- }
- org++;
- }
- }
- a = org-w->org;
- fixup = 0;
- if(a>=0 && a<w->nchars){
- frdelete(w, 0, a);
- fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
- }else if(a<0 && -a<w->nchars){
- n = w->org - org;
- r = runemalloc(n);
- runemove(r, w->r+org, n);
- frinsert(w, r, r+n, 0);
- free(r);
- }else
- frdelete(w, 0, w->nchars);
- w->org = org;
- wfill(w);
- wscrdraw(w);
- wsetselect(w, w->q0, w->q1);
- if(fixup && w->p1 > w->p0)
- frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
- }
- void
- wsetselect(Window *w, uint q0, uint q1)
- {
- int p0, p1;
- /* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
- w->q0 = q0;
- w->q1 = q1;
- /* compute desired p0,p1 from q0,q1 */
- p0 = q0-w->org;
- p1 = q1-w->org;
- if(p0 < 0)
- p0 = 0;
- if(p1 < 0)
- p1 = 0;
- if(p0 > w->nchars)
- p0 = w->nchars;
- if(p1 > w->nchars)
- p1 = w->nchars;
- if(p0==w->p0 && p1==w->p1)
- return;
- /* screen disagrees with desired selection */
- if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
- /* no overlap or too easy to bother trying */
- frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
- frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
- goto Return;
- }
- /* overlap; avoid unnecessary painting */
- if(p0 < w->p0){
- /* extend selection backwards */
- frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
- }else if(p0 > w->p0){
- /* trim first part of selection */
- frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
- }
- if(p1 > w->p1){
- /* extend selection forwards */
- frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
- }else if(p1 < w->p1){
- /* trim last part of selection */
- frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
- }
- Return:
- w->p0 = p0;
- w->p1 = p1;
- }
- uint
- winsert(Window *w, Rune *r, int n, uint q0)
- {
- uint m;
- if(n == 0)
- return q0;
- if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
- m = min(HiWater-LoWater, min(w->org, w->qh));
- w->org -= m;
- w->qh -= m;
- if(w->q0 > m)
- w->q0 -= m;
- else
- w->q0 = 0;
- if(w->q1 > m)
- w->q1 -= m;
- else
- w->q1 = 0;
- w->nr -= m;
- runemove(w->r, w->r+m, w->nr);
- q0 -= m;
- }
- if(w->nr+n > w->maxr){
- /*
- * Minimize realloc breakage:
- * Allocate at least MinWater
- * Double allocation size each time
- * But don't go much above HiWater
- */
- m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
- if(m > HiWater)
- m = max(HiWater+MinWater, w->nr+n);
- if(m > w->maxr){
- w->r = runerealloc(w->r, m);
- w->maxr = m;
- }
- }
- runemove(w->r+q0+n, w->r+q0, w->nr-q0);
- runemove(w->r+q0, r, n);
- w->nr += n;
- /* if output touches, advance selection, not qh; works best for keyboard and output */
- if(q0 <= w->q1)
- w->q1 += n;
- if(q0 <= w->q0)
- w->q0 += n;
- if(q0 < w->qh)
- w->qh += n;
- if(q0 < w->org)
- w->org += n;
- else if(q0 <= w->org+w->nchars)
- frinsert(w, r, r+n, q0-w->org);
- return q0;
- }
- void
- wfill(Window *w)
- {
- Rune *rp;
- int i, n, m, nl;
- if(w->lastlinefull)
- return;
- rp = malloc(messagesize);
- do{
- n = w->nr-(w->org+w->nchars);
- if(n == 0)
- break;
- if(n > 2000) /* educated guess at reasonable amount */
- n = 2000;
- runemove(rp, w->r+(w->org+w->nchars), n);
- /*
- * it's expensive to frinsert more than we need, so
- * count newlines.
- */
- nl = w->maxlines-w->nlines;
- m = 0;
- for(i=0; i<n; ){
- if(rp[i++] == '\n'){
- m++;
- if(m >= nl)
- break;
- }
- }
- frinsert(w, rp, rp+i, w->nchars);
- }while(w->lastlinefull == FALSE);
- free(rp);
- }
- char*
- wcontents(Window *w, int *ip)
- {
- return runetobyte(w->r, w->nr, ip);
- }
|