ref: 0fdd9b51c7c4ada3a441c3a7baa58be31e24a22c
dir: /vol.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <bio.h> #include <draw.h> #include <mouse.h> #include <keyboard.h> enum{ Cback, Cbord, Cvol, Ctxt, Cmute, Ncols, Bordsz = 3, }; Image *cols[Ncols]; typedef struct Vol Vol; struct Vol{ char name[128]; char value[128]; int text; int stereo; int left; int right; int muted; Rectangle r; Rectangle lr; Rectangle rr; }; Rectangle frame; Vol *voltab; int nvol, tabsz; char *dev = "/dev/volume"; Mousectl *mctl; Keyboardctl *kctl; int writevol(Vol *v) { Biobuf *bf; if((bf = Bopen(dev, OWRITE)) == nil) return -1; if(v->text) Bprint(bf, "%s %s\n", v->name, v->value); else if(v->stereo) Bprint(bf, "%s %d %d\n", v->name, v->left, v->right); else Bprint(bf, "%s %d\n", v->name, v->left); Bterm(bf); return 0; } int quickquiet(Vol *v) { Biobuf *bf; if((bf = Bopen(dev, OWRITE)) == nil) return -1; Bprint(bf, "%s 0\n", v->name); v->left = v->right = 0; Bterm(bf); return 0; } int prompt(Vol *v) { int r; char buf[sizeof v->value] = {0}; strncpy(buf, v->value, sizeof buf); if((r = enter(v->name, buf, sizeof(buf)-UTFmax, mctl, kctl, nil)) < 0){ fprint(2, "prompt: %r\n"); return -1; }else if(r > 0) strncpy(v->value, buf, sizeof buf); return 0; } int readvol(char *path) { int n; Biobuf *bf; char *s, *fld[4]; Vol *v; if((bf = Bopen(path, OREAD)) == nil) return -1; nvol = 0; for(;;){ if((s = Brdstr(bf, '\n', 1)) == nil) break; if((n = getfields(s, fld, nelem(fld), 1, " ")) < 1 || n > 3) goto next; if(nvol++ >= tabsz){ tabsz += 16; if((voltab = realloc(voltab, tabsz * sizeof *voltab)) == nil) sysfatal("realloc: %r"); } v = voltab + nvol - 1; memset(v, 0, sizeof *v); strncpy(v->name, fld[0], sizeof(v->name)-1); if(strcmp(fld[0], "delay") == 0 || strcmp(fld[0], "speed") == 0 || strcmp(fld[0], "dev") == 0){ strncpy(v->value, fld[1], sizeof(v->value)-1); v->text = 1; goto next; } v->text = 0; v->stereo = n == 3; v->left = strtol(fld[1], nil, 10); if(n > 2){ v->right = strtol(fld[2], nil, 10); if(v->right == 0.0) v->stereo = 0; } next: free(s); } Bterm(bf); return 0; } Vol * getcur(Point p, int *right) { Vol *v; for(v=voltab; v<voltab+nvol; v++){ if(ptinrect(p, v->r)){ if(ptinrect(p, v->rr)) *right = 1; else *right = 0; break; } } return (v == voltab + nvol ? nil : v); } void redraw(void) { int h; Vol *v; Point p; Rectangle r, rr; draw(screen, screen->r, cols[Cback], nil, ZP); h = (Dy(frame) - nvol) / nvol; rr = frame; rr.max.y = frame.min.y + h + 1; for(v=voltab; v<voltab+nvol; v++){ border(screen, rr, 1, cols[Cbord], ZP); r = v->lr; if(v->text){ p = subpt(r.max, stringsize(font, v->value)); string(screen, p, cols[Ctxt], ZP, font, v->value); }else{ r.max.x = r.min.x + Dx(r) * v->left / 100; draw(screen, r, cols[v->muted ? Cmute : Cvol], nil, ZP); if(v->stereo){ r = v->rr; r.max.x = r.min.x + Dx(r) * v->right / 100; draw(screen, r, cols[v->muted ? Cmute : Cvol], nil, ZP); } } r = v->lr; string(screen, addpt(r.min, Pt(2,2)), cols[Ctxt], ZP, font, v->name); rr = rectaddpt(rr, Pt(0, h+1)); } flushimage(display, 1); } void snarfgeom(void) { int hh, h; Rectangle r, rr; Vol *v; frame = insetrect(screen->r, Bordsz+1); hh = (Dy(frame) - nvol) / nvol; rr = frame; rr.max.y = frame.min.y + hh + 1; for(v=voltab; v<voltab+nvol; v++){ r = insetrect(rr, 1); v->r = r; h = Dy(r); v->lr = r; if(v->stereo){ r.max.y -= Dy(r) / 2 + 1; v->lr.max.y = r.max.y; r = rectaddpt(r, Pt(0, h/2+1)); v->rr = r; } else v->rr = ZR; rr = rectaddpt(rr, Pt(0, hh + 1)); } } void load(void) { if(readvol(dev) < 0) sysfatal("readvol: %r"); snarfgeom(); } void reset(void) { load(); redraw(); } void usage(void) { fprint(2, "usage: %s [-f dev]\n", argv0); threadexits("usage"); } void threadmain(int argc, char **argv) { int i, right; double Δ; Rune r; Mouse mold; Vol *cur; ARGBEGIN{ case 'f': dev = EARGF(usage()); break; }ARGEND if(initdraw(0, 0, "vol") < 0) sysfatal("initdraw: %r"); if((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); if((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); fmtinstall('P', Pfmt); fmtinstall('R', Rfmt); Theme th[nelem(cols)] = { [Cback] { "back", DBlack }, [Cbord] { "border", DWhite }, [Cvol] { "paletext", 0x777777FF }, [Cmute] { "holdtext", DMedblue }, [Ctxt] { "text", 0x777777FF }, }; readtheme(th, nelem(th), nil); for(i=0; i<nelem(cols); i++) cols[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, th[i].c); if(readvol(dev) < 0) sysfatal("readvol: %r"); reset(); enum{AMOUSE, ARESIZE, AKEY, AEND}; Alt a[AEND+1] = { [AMOUSE] {mctl->c, &mctl->Mouse, CHANRCV}, [ARESIZE] {mctl->resizec, nil, CHANRCV}, [AKEY] {kctl->c, &r, CHANRCV}, [AEND] {nil, nil, CHANEND} }; for(cur=nil;;){ switch(alt(a)){ case AMOUSE: /* FIXME: maybe fsm should be flipped to work based on position * instead of button */ /* FIXME: device: choose from list of valid devices */ if(mctl->buttons != 0 && mctl->buttons != mold.buttons) cur = nil; if((mctl->buttons & 7) == 1){ if(cur == nil && (cur = getcur(mctl->xy, &right)) == nil) break; if(cur->text) break; Δ = 100.0 * (mctl->xy.x - cur->r.min.x) / Dx(cur->r); cur->left = cur->right = Δ; if(writevol(cur) < 0){ fprint(2, "writevol: %r\n"); load(); } redraw(); }else if((mctl->buttons & 7) == 2){ if(cur == nil && (cur = getcur(mctl->xy, &right)) == nil) break; if(cur->text) break; else{ Δ = 100.0 * (mctl->xy.x - cur->r.min.x) / Dx(cur->r); if(right) cur->right = Δ; else cur->left = Δ; if(writevol(cur) < 0){ fprint(2, "writevol: %r\n"); load(); } } redraw(); }else if((mctl->buttons & 7) == 4){ if(cur == nil && (cur = getcur(mctl->xy, &right)) == nil) break; if(cur->text) prompt(cur); /* FIXME */ //quickquiet(cur); redraw(); cur = nil; }else if(cur != nil){ if(writevol(cur) < 0) sysfatal("writevol: %r"); reset(); cur = nil; }else cur = nil; mold = mctl->Mouse; break; case ARESIZE: if(getwindow(display, Refnone) < 0) sysfatal("getwindow: %r"); reset(); break; case AKEY: switch(r){ case 'q': case Kdel: threadexitsall(nil); } break; } } }