ref: 6a761aa78791cdb90ccbd0babcf538043882c9b3
dir: /zuke.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <event.h> #include <keyboard.h> #include <bio.h> #include <thread.h> static int plen; static struct { char *file; char *name; }*plist; static int pid, pcur, pcurplaying; static int scroll, scrollsz, pause; static Image *cola, *colb; static Font *f; static Channel ctl; static int audio; int mainstacksize = 32768; static void redraw(Image *screen, int new) { Point p, sp; int i; sp.x = sp.y = 0; if(new) draw(screen, screen->r, cola, nil, ZP); p.x = screen->r.min.x + 2; p.y = screen->r.min.y + 2; scrollsz = Dy(screen->r) / f->height - 1; for(i = scroll; i < plen; i++){ if(p.y > screen->r.max.y) break; if(pcurplaying == i){ Point right, left; left.y = right.y = p.y - 1; left.x = p.x; right.x = screen->r.max.x; line(screen, left, right, 0, 0, 0, colb, sp); left.y = right.y = p.y + f->height; line(screen, left, right, 0, 0, 0, colb, sp); } if(pcur == i){ Rectangle sel; sel = screen->r; sel.min.y = p.y; sel.max.y = p.y + f->height; draw(screen, sel, colb, nil, ZP); string(screen, p, cola, sp, f, plist[i].name); } else string(screen, p, colb, sp, f, plist[i].name); p.y += f->height; } flushimage(display, 1); } typedef struct Relayctx Relayctx; struct Relayctx { int in, out; Channel *ev; }; typedef struct Decctx Decctx; struct Decctx { int in, out; Channel *quit, *wait; }; static void relay(void *v) { int n; char *buf; Ioproc *io; Relayctx *ctx; ctx = v; io = ioproc(); buf = malloc(65536); sendp(ctx->ev, nil); while((n = ioread(io, ctx->in, buf, 65536)) > 0){ if(iowrite(io, ctx->out, buf, n) != n) break; } free(buf); closeioproc(io); sendp(ctx->ev, nil); } typedef struct Playctx Playctx; struct Playctx { Channel *quit; Channel *wait; int p[4]; }; static void player(void *dec_) { Decctx *dec; static Relayctx rel[2]; Alt a[3]; dec = dec_; threadsetname("player"); if(rel[0].ev == nil){ rel[0].ev = chancreate(sizeof(void*), 0); rel[1].ev = chancreate(sizeof(void*), 0); } audio = open("/dev/audio", OWRITE); pcurplaying = pcur; again: rel[0].in = open(plist[pcurplaying].file, OREAD); rel[0].out = dec->in; rel[1].in = dec->out; rel[1].out = audio; if(audio < 0 || rel[0].in < 0){ close(audio); close(rel[0].in); fprint(2, "%r\n"); threadexits(nil); } threadcreate(relay, &rel[0], 4096); recvp(rel[0].ev); threadcreate(relay, &rel[1], 4096); recvp(rel[1].ev); memset(a, 0, sizeof(a)); a[0].op = a[1].op = CHANRCV; a[0].c = dec->quit; a[1].c = rel[0].ev; a[2].op = CHANEND; while(1){ int r; r = alt(a); close(rel[0].in); if(r == 1){ if(++pcurplaying >= plen) pcurplaying = 0; redraw(screen, 1); goto again; } else{ close(rel[1].in); close(rel[0].out); recvp(rel[0].ev); recvp(rel[1].ev); close(audio); sendp(dec->wait, nil); break; } } threadexits(nil); } static void play(void) { static Decctx ctx; int p[4]; if(ctx.quit == nil){ ctx.quit = chancreate(sizeof(void*), 0); ctx.wait = chancreate(sizeof(void*), 0); } if(pcur == pcurplaying) return; if(pid != 0){ sendp(ctx.quit, nil); recvp(ctx.wait); } pid = 0; pcurplaying = -1; if(pcur < 0) return; if(ctx.quit == nil) ctx.quit = chancreate(sizeof(void*), 0); pipe(&p[0]); pipe(&p[2]); if((pid = rfork(RFFDG|RFREND|RFPROC)) == 0){ close(p[1]); dup(p[0], 0); close(p[2]); dup(p[3], 1); close(2); open("/dev/null", OWRITE); execl("/bin/rc", "-c", "play", "-o", "/fd/1", "/fd/0", nil); } if(pid < 0) sysfatal("%r"); close(p[0]); close(p[3]); ctx.in = p[1]; ctx.out = p[2]; pid = proccreate(player, &ctx, 4096); pcurplaying = pcur; } static void readplist(void) { Biobuf b; Binit(&b, 0, OREAD); for(plen = 0;; plen++){ char *s[2]; int n; s[0] = Brdstr(&b, '\n', 1); if(s[0] == nil) break; plist = realloc(plist, sizeof(*plist)*(plen+1)); n = getfields(s[0], s, 2, 1, "\t"); if(n < 1) break; plist[plen].file = plist[plen].name = s[0]; if(n > 1) plist[plen].name = s[1]; else if((plist[plen].name = strrchr(s[0], '/')) != nil) plist[plen].name++; } } static void usage(void) { fprint(2, "usage: zuke [-b]\n"); exits("usage"); } void eresized(int new) { if(getwindow(display, Refnone) < 0) sysfatal("can't reattach to window: %r"); redraw(screen, new); } void threadmain(int argc, char **argv) { int inv; inv = 0; ARGBEGIN{ case 'b': inv = 1; break; default: usage(); }ARGEND readplist(); if(plen < 1){ fprint(2, "empty playlist\n"); exits("empty"); } if(initdraw(0, 0, "zuke") < 0) sysfatal("initdraw failed"); f = display->defaultfont; cola = inv ? display->black : display->white; colb = inv ? display->white : display->black; einit(Emouse | Ekeyboard); srand(time(0)); pcurplaying = -1; redraw(screen, 1); for(;;){ int oldpcur, oldpcurplaying, key; Event e; oldpcurplaying = pcurplaying; oldpcur = pcur; key = event(&e); if(key == Emouse){ if(e.mouse.buttons > 0){ pcur = scroll + (e.mouse.xy.y - screen->r.min.y)/f->height; if(e.mouse.buttons == 4) play(); } } else if(key == Ekeyboard){ if(e.kbdc == Kup) pcur--; else if(e.kbdc == Kpgup) pcur -= scrollsz; else if(e.kbdc == Kdown) pcur++; else if(e.kbdc == Kpgdown) pcur += scrollsz; else if(e.kbdc == Kend) pcur = plen-1; else if(e.kbdc == Khome) pcur = 0; else if(e.kbdc == 0x0a) play(); else if(e.kbdc == 'q' || e.kbdc == Kesc) break; else if(e.kbdc == 'o') pcur = pcurplaying; else if(e.kbdc == '>' && pcurplaying >= 0){ pcur = pcurplaying; if(++pcur >= plen) pcur = 0; play(); } else if(e.kbdc == '<' && pcurplaying >= 0){ pcur = pcurplaying; if(--pcur < 0) pcur = plen-1; play(); } else if(e.kbdc == 's' && pid > 0){ pcur = -1; play(); } } if(pcur != oldpcur || oldpcurplaying != pcurplaying){ if(pcur < 0) pcur = 0; else if(pcur >= plen) pcur = plen - 1; if(pcur < scroll) scroll = pcur; else if(pcur > scroll + scrollsz) scroll = pcur - scrollsz; if(scroll > plen - scrollsz) scroll = plen - scrollsz; else if(scroll < 0) scroll = 0; if(pcur != oldpcur || oldpcurplaying != pcurplaying) redraw(screen, 1); } } pcur = -1; play(); threadexitsall(nil); }