#include #include #include #include #include #include #include #include #include #include <9p.h> #include "gui.h" #include "cook.h" Image* cols[MAXCOL]; Image* bord[NBORD]; Font* fonts[NFONT]; static Cursor whitearrow = { {0, 0}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }, {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, } }; Cursor nocursor; Point lastxy; // click to type static Mousectl* mctl; File* focus; Channel*resizec; int eventdebug; void incwin(File* f) { Panel* p; p = f->aux; if (p->nwins == 0) flagsons(f, Phide, 0, ++p->nwins, 1024); else flagsons(f, 0, Phide, p->nwins, p->nwins++); if (hassons(f, Phide)) p->flags |= Pmore; else { p->nwins = 0; p->flags &= ~Pmore; } } void minwin(File* f) { Panel* p; p = f->aux; p->nwins = 0; incwin(f); } void fullwin(File* f) { Panel* p; p = f->aux; p->nwins = 0; p->flags |= Predraw; flagsons(f, 0, Phide, 0, 1024); if (p->flags&Pmore) p->flags &= ~Pmore; } void maxwin(File* f) { Panel* p; if (f->parent != f){ p = f->parent->aux; p->flags |= Predraw; flagothersons(f->parent, Phide, 0, f); if (hassons(f->parent, Phide)) p->flags |= Pmore; else { p->nwins = 0; p->flags &= ~Pmore; } } } static void setatime(File* f) { long now; Panel* p; now = time(nil); for(;;){ p = f->aux; p->atime = now; if (p->flags&Ptop) break; if (f == f->parent) return; f = f->parent; } } void genkeyboard(Panel* p, Rune r) { if (r == Kdel) event(p, "interrupt"); else if (p->flags&Pedit) event(p, "keys %C", r); } static void hidecursor(void) { setcursor(mctl,&nocursor); } void argcursor(int yes) { setcursor(mctl, yes ? &whitearrow : nil); } void resize(void) { sendul(resizec, 1); } static void resizethread(void* arg) { int fd; ulong dummy; Alt a[] = { {arg, &dummy, CHANRCV}, {resizec, &dummy, CHANRCV}, {nil, nil, CHANEND}}; threadsetname("resizethread"); fd = open("#c/cons", OWRITE); for(;;){ switch(alt(a)){ case 0: if (getwindow(display, Refnone) <= 0){ fprint(fd, "getwindow: %r\n"); postnote(PNGROUP, getpid(), "getwindow"); sysfatal("getwindow"); } // and do a resize... case 1: layout(slash); showtree(slash, 0); flushimage(display, 1); break; default: abort(); } } } static char* terms[5]; void setterm(char* term) { int i; for (i = 0; i < nelem(terms); i++) if (terms[i] == nil){ terms[i] = smprint("call %s", term); return; } } static void destroythread(void*) { Panel* p; for(;;){ p = recvp(destroyc); focus = nil; panelok(p); edprint("closepanel %s (%ld ref)\n",p ? p->name : nil, p->ref); closepanel(p); resize(); } } static void kbufthread(void* a) { Channel*c = a; Rune r; Keyboardctl*kctl; Rune nr; threadsetname("kbufthread"); kctl = initkeyboard(nil); if (kctl == nil) sysfatal("initkeyboard"); ctlkeyboard(kctl, "rawon"); for(;;){ recv(kctl->c, &r); send(c, &r); if (r == Kup || r == Kdown){ /* Consume all repeats sent while * the panel is busy processing the last one */ nr = 0; while(nbrecv(kctl->c, &nr) > 0 && nr == r) ; if (nr) send(c, &nr); } } } static void useriothread(void*) { Cmouse m; Channel*mc; Panel* p; Channel*kbufc; int hide; File* f; int fd, n; Rune r; Alt a[] = { {nil, &m, CHANRCV}, {nil, &r, CHANRCV}, {nil, nil, CHANEND}}; threadsetname("useriothread"); mc = cookmouse(mctl->c); if (mc == nil) sysfatal("cookmouse"); kbufc = chancreate(sizeof(Rune), 20); a[0].c = mc; a[1].c = kbufc; threadcreate(kbufthread, kbufc, 8*1024); focus = nil; hide = 0; for(;;){ switch(alt(a)){ default: postnote(PNGROUP, getpid(), "mousealt"); sysfatal("mousealt"); case 0: Edprint("mouse %M: ", &m); if (hide){ hide = 0; argcursor(0); } f = focus = pointinpanel(m.xy, 1); if (f == nil) continue; incref(f); lastxy = m.xy; p = f->aux; if (!p || (p->flags&Pdead)){ closefile(f); focus = nil; continue; } if(p->file != f){ fprint(2, "panel %p %s, file %p focus %p\n", p, p->name, p->file, focus); abort(); } panelok(p); Edprint("for %s\n", p->name); if (m.buttons){ setatime(f); if (mousecmdarg(f, &m, mc)) argcursor(0); else if (hastag(f) && intag(p, m.xy)) tagmousecmd(f, &m, mc); else panels[p->type]->mouse(p, &m, mc); } closefile(f); break; case 1: Edprint("keyboard %C: ", r); if ((r&KF) == KF){ n = (r & ~KF) - 1; if (n >= 0 && n < nelem(terms) && terms[n]){ Edprint("KF %d\n", n); fd = open("/dev/mousectl", OWRITE); write(fd, terms[n], strlen(terms[n])); close(fd); continue; } } if (r == Kup || r == Kdown || focus == nil) focus = pointinpanel(lastxy, 1); if (eqpt(lastxy, ZP) || focus == nil) continue; f = focus; incref(f); if (!hide){ hide = 1; hidecursor(); } p = f->aux; if (!p || (p->flags&Pdead)){ focus = nil; closefile(f); continue; } setatime(f); if (f->parent != nil && f->aux != nil){ edprint("[%C]", (Rune)r); panelok(p); panels[p->type]->keyboard(p, r); } closefile(f); break; } } } /* R and B fonts may vary slightly. Adjust them to * the same height, so that we do not resize because * of R/B/T <-> R/B/T changes */ static int maxfontht; int fontheight(Font* f) { if (f == fonts[FL]) return f->height; else return maxfontht; } static Font* getfont(char* std, char* env) { Font* f; char* fname; f = nil; if (fname = getenv(env)){ f = openfont(display, fname); free(fname); } if (f == nil) f = openfont(display, std); if (f == nil) f = openfont(display, "/lib/font/bit/lucm/unicode.9.font"); return f; } static void loadfonts(void) { fonts[FR] = getfont("/lib/font/bit/Vera/Vera.12.font", "fontR"); fonts[FB] = getfont("/lib/font/bit/VeraBd/VeraBd.12.font", "fontB"); fonts[FT] = getfont("/lib/font/bit/VeraMono/VeraMono.12.font", "fontT"); fonts[FL] = getfont("/lib/font/bit/VeraMono/VeraMono.20.font", "fontL"); fonts[FS] = getfont("/lib/font/bit/VeraMono/VeraMono.10.font", "fontS"); maxfontht = fonts[FR]->height; if (fonts[FB]->height > maxfontht) maxfontht = fonts[FB]->height; if (fonts[FT]->height > maxfontht) maxfontht = fonts[FT]->height; } static void loadborders(void) { Rectangle r; Rectangle ir; Rectangle rr; Rectangle irr; rr = Rect(0, 0, Tagwid, 2*Taght); irr = insetrect(rr, 1); r = Rect(0, 0, Tagwid, Taght); ir = insetrect(r, 1); bord[Bback] = cols[BACK]; bord[Btag] = allocimage(display, rr, screen->chan, 0, CBack); bord[Bdtag] = allocimage(display, rr, screen->chan, 0, CBack); bord[Bmtag] = allocimage(display, rr, screen->chan, 0, CBack); bord[Bdmtag] = allocimage(display, rr, screen->chan, 0, CBack); draw(bord[Btag], r, cols[BORD], nil, ZP); draw(bord[Bmtag], rr, cols[BORD], nil, ZP); draw(bord[Bdtag], r, cols[BORD], nil, ZP); draw(bord[Bdtag], ir, cols[HBORD], nil, ZP); draw(bord[Bdmtag], rr, cols[BORD], nil, ZP); draw(bord[Bdmtag], irr, cols[HBORD], nil, ZP); bord[Bws1] = allocimage(display, r, screen->chan, 1, CBack); bord[Bws2] = allocimage(display, r, screen->chan, 1, CBack); bord[Bws3] = allocimage(display, r, screen->chan, 1, CBack); draw(bord[Bws1], r, cols[WS1], nil, ZP); draw(bord[Bws2], r, cols[WS2], nil, ZP); draw(bord[Bws3], r, cols[WS3], nil, ZP); r = Rect(0, 0, Inset + Tagwid, Inset); bord[Bn] = allocimage(display, r, screen->chan, 1, CBack); bord[Bs] = allocimage(display, r, screen->chan, 1, CBack); bord[Be] = allocimage(display, r, screen->chan, 1, CBack); bord[Bw] = allocimage(display, r, screen->chan, 1, CBack); bord[Bnw]= nil; // northwest is the tag. Don't care. bord[Bne] = allocimage(display, r, screen->chan, 1, CBack); bord[Bse] = allocimage(display, r, screen->chan, 1, CBack); bord[Bsw] = allocimage(display, r, screen->chan, 1, CBack); ir = Rect(0, 0, Inset+Tagwid, 1); draw(bord[Bn], ir, cols[BORD2], nil, ZP); ir = Rect(0, Inset-2, Inset+Tagwid, Inset); draw(bord[Bs], ir, cols[BORD], nil, ZP); ir = Rect(Inset-2, 0, Inset, Inset); draw(bord[Be], ir, cols[BORD], nil, ZP); ir = Rect(0, 0, 1, Inset); draw(bord[Bw], ir, cols[BORD2], nil, ZP); ir = Rect(0, 0, Inset-2, 1); draw(bord[Bne], ir, cols[BORD2], nil, ZP); ir = Rect(Inset-2, 0, Inset, Inset); draw(bord[Bne], ir, cols[BORD], nil, ZP); ir = Rect(0, Inset-2, Inset, Inset); draw(bord[Bse], ir, cols[BORD], nil, ZP); ir = Rect(Inset-2, 0, Inset, Inset); draw(bord[Bse], ir, cols[BORD], nil, ZP); ir = Rect(0, Inset-2, Inset+Tagwid, Inset); draw(bord[Bsw], ir, cols[BORD], nil, ZP); ir = Rect(0, 0, 1, Inset-2); draw(bord[Bsw], ir, cols[BORD2], nil, ZP); } static void loadcols(void) { cols[BACK] = allocimage(display, Rect(0,0,1,1), RGB24, 1, CBack); cols[HIGH] = allocimage(display, Rect(0,0,1,1), RGB24, 1, 0xADADADFF); cols[BORD] = allocimage(display, Rect(0,0,1,1), RGB24, 1, DDarkblue); cols[BORD2]= allocimage(display, Rect(0,0,1,1), RGB24, 1, DDarkblue); cols[TEXT] = display->black; cols[HTEXT] = display->black; cols[HBORD] = allocimage(display, Rect(0,0,1,1), RGB24, 1, DGreen); cols[WS1]= allocimage(display, Rect(0,0,1,1), RGB24, 1, DRed); cols[WS2]= allocimage(display, Rect(0,0,1,1), RGB24, 1, DBlue); cols[WS3]= allocimage(display, Rect(0,0,1,1), RGB24, 1, DGreen); } static void grapherr(Display*, char* s) { fprint(2, "drawerror: %s\n", s); abort(); } void initui(void) { fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); fmtinstall('T', Tfmt); fmtinstall('M', Mfmt); resizec = chancreate(sizeof(ulong), 10); if (initdraw(0, "/lib/font/bit/Vera/Vera.12.font", "omero") < 0 && initdraw(0, "/lib/font/bit/lucm/unicode.9.font", "omero") < 0) sysfatal("omero: initdraw: %r"); display->locking = 1; loadcols(); loadborders(); loadfonts(); mctl = initmouse("/dev/mouse", screen); if (mctl == nil) sysfatal("initmouse: %r"); threadcreate(resizethread, mctl->resizec, 16*1024); threadcreate(useriothread, nil, 16*1024); threadcreate(destroythread,nil, 16*1024); showtree(slash, 0); flushimage(display, 1); }