123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include <keyboard.h>
- #include <fcall.h>
- #include <plumb.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;
- Window*
- wmk(Mousectl *mc, Channel *ck, Channel *cctl)
- {
- print_func_entry();
- Window *w;
- w = emalloc(sizeof(Window));
- // NO. w->mc = nil; // *mc;
- w->ck = ck;
- w->cctl = cctl;
- 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->id = ++id;
- w->notefd = -1;
- w->dir = estrdup(startdir);
- w->label = estrdup("<unnamed>");
- incref(w); /* ref will be removed after mounting; avoids delete before ready to be deleted */
- print_func_exit();
- return w;
- }
- void
- wsetname(Window *w)
- {
- print_func_entry();
- 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);
- print_func_exit();
- }
- int
- wclose(Window *w)
- {
- print_func_entry();
- int i;
- i = decref(w);
- if(i > 0) {
- print_func_exit();
- return 0;
- }
- if(i < 0)
- error("negative ref count");
- if(!w->deleted)
- wclosewin(w);
- wsendctlmesg(w, Exited, nil);
- print_func_exit();
- return 1;
- }
- void
- winctl(void *arg)
- {
- print_func_entry();
- Rune *rp, *bp, *kbdr;
- int nr, nb, c, wid, i, npart, lastb;
- char *s, *t, part[3];
- Window *w;
- Mousestate *mp, m;
- enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
- Alt alts[NWALT+1];
- int walt;
- 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 = CHANNOP; // XXXCHANRCV;
- alts[WMouseread].c = w->mouseread;
- alts[WMouseread].v = &mrm;
- alts[WMouseread].op = CHANNOP; // XXXCHANSND;
- 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(;;){
- // TODO: mouses
- if(0 && w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
- alts[WMouseread].op = CHANSND;
- else
- alts[WMouseread].op = CHANNOP;
- 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->run[i];
- if(c=='\n' || c=='\004'){
- alts[WCread].op = CHANSND;
- break;
- }
- }
- }
- walt = alt(alts);
- switch(walt){
- 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.Mouse;
- mp->counter = w->mouse.counter;
- lastb = w->mc.buttons;
- }
- } else
- fprint(2, "MOUSECTL\n"); //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:
- exits("WCtl can't do");
- #if 0
- 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);
- }
- #endif
- continue;
- case WCwrite:
- recv(cwm.cw, &pair);
- rp = pair.s;
- nr = pair.ns;
- bp = rp;
- for(i=0; i<nr; i++) {
- // See rio for the run conversion crap. For now, I'm not going to
- // worry about it. This is designed to target Akaros too.
- fprint(/*w->Console->out*/1, "%c", *bp++);
- }
- 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->run[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->run[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)
- 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, "%s %s ",t, s);
- }
- send(cwrm.c2, &pair);
- continue;
- }
- }
- print_func_exit();
- }
- 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->run, w->run+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->run = runerealloc(w->run, m);
- w->maxr = m;
- }
- }
- runemove(w->run+q0+n, w->run+q0, w->nr-q0);
- runemove(w->run+q0, r, n);
- w->nr += n;
- /* if output touches, advance selection, not qh; works best for keyboard and output */
- // TODO don't know if we might want this for displaying text.
- 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;
- return q0;
- }
- void
- wkeyctl(Window *w, Rune r)
- {
- uint q0;
- if(r == 0)
- return;
- if(w->deleted)
- return;
- fprint(2, "wkyctl: skipping all ctl chars\n");
- #if 0
- uint q0 ,q1;
- int n, nb, nr;
- Rune *rp;
- int *notefd;
- /* 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->run[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->run[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;
- }
- wshow(w, q0+1);
- #endif
- /* otherwise ordinary character; just insert */
- q0 = w->q0;
- q0 = winsert(w, &r, 1, q0);
- }
- void
- waddraw(Window *w, Rune *r, int nr)
- {
- print_func_entry();
- w->raw = runerealloc(w->raw, w->nraw+nr);
- runemove(w->raw+w->nraw, r, nr);
- w->nraw += nr;
- print_func_exit();
- }
- /*
- * 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)
- {
- print_func_entry();
- int *notefd;
- notefd = v;
- write(*notefd, "interrupt", 9);
- free(notefd);
- print_func_exit();
- }
- //static Window *clickwin;
- //static uint clickmsec;
- //static Window *selectwin;
- //static uint selectq;
- void
- wsendctlmesg(Window *w, int type, Console *image)
- {
- print_func_entry();
- Wctlmesg wcm;
- wcm.type = type;
- send(w->cctl, &wcm);
- print_func_exit();
- }
- int
- wctlmesg(Window *w, int m, Console *i)
- {
- print_func_entry();
- switch(m){
- default:
- error("unknown control message");
- break;
- case Wakeup:
- break;
- 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;
- break;
- case Deleted:
- if(w->deleted)
- break;
- write(w->notefd, "hangup", 6);
- proccreate(deletetimeoutproc, estrdup(w->name), 4096);
- wclosewin(w);
- break;
- case Exited:
- 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->run);
- free(w->dir);
- free(w->label);
- free(w);
- break;
- }
- print_func_exit();
- return m;
- }
- void
- wcurrent(Window *w)
- {
- print_func_entry();
- if (0) {
- Window *oi;
- if(wkeyboard!=nil && w==wkeyboard) {
- print_func_exit();
- return;
- }
- oi = input;
- input = w;
- if(w != oi){
- if(oi){
- oi->wctlready = 1;
- wsendctlmesg(oi, Wakeup, nil);
- }
- if(w){
- w->wctlready = 1;
- wsendctlmesg(w, Wakeup, nil);
- }
- }
- }
- input = w;
- print_func_exit();
- }
- Window*
- wtop(void)
- {
- print_func_entry();
- exits("wtop!");
- #if 0
- Window *w;
- w = wpointto(pt);
- if(w){
- if(w->topped == topped)
- return nil;
- topwindow(w->i);
- wcurrent(w);
- w->topped = ++topped;
- }
- #endif
- print_func_exit();
- return nil;
- }
- Window*
- wlookid(int id)
- {
- print_func_entry();
- int i;
- fprint(2, "%d:", id);
- for(i=0; i<nwindow; i++)
- if(window[i]->id == id) {
- fprint(2, "FOUND @%p", window[i]);
- print_func_exit();
- return window[i];
- }
- fprint(2, "NOT FOUND;");
- print_func_exit();
- return nil;
- }
- void
- wclosewin(Window *w)
- {
- print_func_entry();
- int i;
- w->deleted = TRUE;
- if(w == input){
- input = nil;
- }
- 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]));
- hidden[nhidden] = nil;
- 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;
- print_func_exit();
- return;
- }
- error("unknown window in closewin");
- print_func_exit();
- }
- void
- wsetpid(Window *w, int pid, int dolabel)
- {
- print_func_entry();
- 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;
- print_func_exit();
- }
- void
- winshell(void *args)
- {
- print_func_entry();
- 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");
- }
- print_func_exit();
- }
- int
- winfmt(Fmt *f)
- {
- Window *w;
- w = va_arg(f->args, Window*);
- if (w < (void *)4096)
- return fmtprint(f, "BOGUS w!: %p", w);
- return fmtprint(f, "%p: %s", w, w->label);
- }
|