ref: 63f9a4fda36f916e543c8f3ea117b31c194a4db7
dir: /sys/src/cmd/abaco/main.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <thread.h> #include <mouse.h> #include <keyboard.h> #include <cursor.h> #include <frame.h> #include <regexp.h> #include <plumb.h> #include <html.h> #include "dat.h" #include "fns.h" enum { WPERCOL = 8, }; void mousethread(void *); void keyboardthread(void *); void iconinit(void); void plumbproc(void*); Channel *cexit; Channel *cplumb; Mousectl *mousectl; char *fontnames[2] = { "/lib/font/bit/lucidasans/unicode.8.font", "/lib/font/bit/lucidasans/passwd.6.font", }; int snarffd = -1; int mainpid; int plumbwebfd; int plumbsendfd ; char *webmountpt = "/mnt/web"; char *charset = "iso-8859-1"; int mainstacksize = STACK; void readpage(Column *, char *); int shutdown(void *, char *); void derror(Display *, char *s) { error(s); } static void usage(void) { fprint(2, "usage: %s [-c ncol] [-m mtpt] [-t charset] [url...]\n", argv0); exits("usage"); } void threadmain(int argc, char *argv[]) { Column *c; char buf[256]; int i, ncol; rfork(RFENVG|RFNAMEG); ncol = 1; ARGBEGIN{ case 'c': ncol = atoi(EARGF(usage())); if(ncol <= 0) usage(); break; case 'm': webmountpt = EARGF(usage()); break; case 'p': procstderr++; break; case 't': charset = EARGF(usage()); break; default: usage(); break; }ARGEND snprint(buf, sizeof(buf), "%s/ctl", webmountpt); webctlfd = open(buf, ORDWR); if(webctlfd < 0) sysfatal("can't initialize webfs: %r"); snarffd = open("/dev/snarf", OREAD|OCEXEC); if(initdraw(derror, fontnames[0], "abaco") < 0) sysfatal("can't open display: %r"); memimageinit(); iconinit(); timerinit(); initfontpaths(); cexit = chancreate(sizeof(int), 0); crefresh = chancreate(sizeof(Page *), 0); if(cexit==nil || crefresh==nil) sysfatal("can't create initial channels: %r"); mousectl = initmouse(nil, screen); if(mousectl == nil) sysfatal("can't initialize mouse: %r"); mouse = mousectl; keyboardctl = initkeyboard(nil); if(keyboardctl == nil) sysfatal("can't initialize keyboard: %r"); mainpid = getpid(); plumbwebfd = plumbopen("web", OREAD|OCEXEC); if(plumbwebfd >= 0){ cplumb = chancreate(sizeof(Plumbmsg*), 0); proccreate(plumbproc, nil, STACK); } plumbsendfd = plumbopen("send", OWRITE|OCEXEC); rowinit(&row, screen->clipr); for(i=0; i<ncol; i++){ c = rowadd(&row, nil, -1); if(c==nil && i==0) error("initializing columns"); } c = row.col[row.ncol-1]; for(i=0; i<argc; i++) if(i/WPERCOL >= row.ncol) readpage(c, argv[i]); else readpage(row.col[i/WPERCOL], argv[i]); flushimage(display, 1); threadcreate(keyboardthread, nil, STACK); threadcreate(mousethread, nil, STACK); threadnotify(shutdown, 1); recvul(cexit); threadexitsall(nil); } void readpage(Column *c, char *s) { Window *w; Runestr rs; w = coladd(c, nil, nil, -1); bytetorunestr(s, &rs); pageget(&w->page, &rs, nil, HGet, TRUE); closerunestr(&rs); } char *oknotes[] = { "delete", "hangup", "kill", "exit", nil }; int shutdown(void*, char *msg) { int i; for(i=0; oknotes[i]; i++) if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0) threadexitsall(msg); print("abaco: %s\n", msg); // abort(); return 0; } void plumbproc(void *) { Plumbmsg *m; threadsetname("plumbproc"); for(;;){ m = plumbrecv(plumbwebfd); if(m == nil) threadexits(nil); sendp(cplumb, m); } } enum { KTimer, KKey, NKALT, }; void keyboardthread(void *) { Timer *timer; Text *t; Rune r; static Alt alts[NKALT+1]; alts[KTimer].c = nil; alts[KTimer].v = nil; alts[KTimer].op = CHANNOP; alts[KKey].c = keyboardctl->c; alts[KKey].v = &r; alts[KKey].op = CHANRCV; alts[NKALT].op = CHANEND; timer = nil; threadsetname("keyboardthread"); for(;;){ switch(alt(alts)){ case KTimer: timerstop(timer); alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; break; case KKey: casekeyboard: typetext = rowwhich(&row, mouse->xy, r, TRUE); t = typetext; if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ activecol = t->col; if(timer != nil) timercancel(timer); if(t!=nil){ texttype(t, r); timer = timerstart(500); alts[KTimer].c = timer->c; alts[KTimer].op = CHANRCV; }else{ timer = nil; alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; } if(nbrecv(keyboardctl->c, &r) > 0) goto casekeyboard; flushimage(display, 1); break; } } } void mousethread(void *) { Plumbmsg *pm; Mouse m; Text *t; int but; enum { MResize, MMouse, MPlumb, MRefresh, NMALT }; static Alt alts[NMALT+1]; threadsetname("mousethread"); alts[MResize].c = mousectl->resizec; alts[MResize].v = nil; alts[MResize].op = CHANRCV; alts[MMouse].c = mousectl->c; alts[MMouse].v = &mousectl->Mouse; alts[MMouse].op = CHANRCV; alts[MPlumb].c = cplumb; alts[MPlumb].v = ± alts[MPlumb].op = CHANRCV; alts[MRefresh].c = crefresh; alts[MRefresh].v = nil; alts[MRefresh].op = CHANRCV; if(cplumb == nil) alts[MPlumb].op = CHANNOP; alts[NMALT].op = CHANEND; for(;;){ qlock(&row); flushrefresh(); qunlock(&row); flushimage(display, 1); switch(alt(alts)){ case MResize: if(getwindow(display, Refnone) < 0) error("resized"); scrlresize(); tmpresize(); rowresize(&row, screen->clipr); break; case MPlumb: plumblook(pm); plumbfree(pm); break; case MRefresh: break; case MMouse: m = mousectl->Mouse; if(m.buttons == 0) continue; qlock(&row); but = 0; if(m.buttons == 1) but = 1; else if(m.buttons == 2) but = 2; else if(m.buttons == 4) but = 3; if(m.buttons & (8|16)){ if(m.buttons & 8) but = Kscrolloneup; else but = Kscrollonedown; rowwhich(&row, m.xy, but, TRUE); }else if(but){ t = rowwhich(&row, m.xy, but, FALSE); if(t) textmouse(t, m.xy, but); } qunlock(&row); break; } } } Cursor boxcursor = { {-7, -7}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} }; void iconinit(void) { Rectangle r; /* Green */ tagcols[BACK] = allocimagemix(display, DPalegreen, DWhite); if(tagcols[BACK] == nil) error("allocimagemix"); tagcols[HIGH] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); tagcols[BORD] = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); tagcols[TEXT] = display->black; tagcols[HTEXT] = display->black; /* Grey */ textcols[BACK] = display->white; textcols[HIGH] = eallocimage(display, Rect(0,0,1,1), CMAP8,1, 0xCCCCCCFF); textcols[BORD] = display->black; textcols[TEXT] = display->black; textcols[HTEXT] = display->black; r = Rect(0, 0, Scrollsize+2, font->height+1); button = eallocimage(display, r, screen->chan, 0, DNofill); draw(button, r, tagcols[BACK], nil, r.min); r.max.x -= 2; border(button, r, 2, tagcols[BORD], ZP); r = button->r; colbutton = eallocimage(display, r, screen->chan, 0, 0x00994CFF); but2col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0xAA0000FF); but3col = eallocimage(display, Rect(0,0,1,2), screen->chan, 1, 0x444488FF); passfont = openfont(display, fontnames[1]); if(passfont == nil) error("openfont"); } /* * /dev/snarf updates when the file is closed, so we must open our own * fd here rather than use snarffd */ /* * rio truncates large snarf buffers, so this avoids using the * service if the string is huge */ enum { NSnarf = 1000, MAXSNARF = 100*1024, }; void putsnarf(Runestr *rs) { int fd, i, n; if(snarffd<0 || rs->nr==0) return; if(rs->nr > MAXSNARF) return; fd = open("/dev/snarf", OWRITE); if(fd < 0) return; for(i=0; i<rs->nr; i+=n){ n = rs->nr-i; if(n > NSnarf) n =NSnarf; if(fprint(fd, "%.*S", n, rs->r) < 0) break; } close(fd); } void getsnarf(Runestr *rs) { int i, n, nb, nulls; char *sn, buf[BUFSIZE]; if(snarffd < 0) return; sn = nil; i = 0; seek(snarffd, 0, 0); while((n=read(snarffd, buf, sizeof(buf))) > 0){ sn = erealloc(sn, i+n+1); memmove(sn+i, buf, n); i += n; sn[i] = 0; } if(i > 0){ rs->r = runemalloc(i+1); cvttorunes(sn, i, rs->r, &nb, &rs->nr, &nulls); free(sn); } }