ref: 4973be1f0bfec6883eda0a794a3d43f42a91fdf7
dir: /mpl.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <keyboard.h>
#include <cursor.h>
#include <mouse.h>
#include "dat.h"
#include "fncs.h"
enum {
MOUSEC,
RESIZEC,
KEYC,
NONE
};
enum volmsg{
UP,
DOWN,
MUTE,
UNMUTE,
};
Mousectl *mctl;
Keyboardctl *kctl;
Channel *ctl, *lout;
Channel *vctl, *vlevel;
int decpid;
Image *black;
Image *red;
Image *background;
int
cleanup(void*,char*)
{
killgrp(decpid);
closedisplay(display);
closemouse(mctl);
closekeyboard(kctl);
return 0;
}
void
quit(char *err)
{
closedisplay(display);
closemouse(mctl);
closekeyboard(kctl);
threadexitsall(err);
}
void
eresized(int isnew)
{
int level;
Lib lib;
if(isnew && getwindow(display, Refnone) < 0)
quit("eresized: Can't reattach to window");
draw(screen, screen->r, background, nil, ZP);
recv(lout, &lib);
drawlibrary(lib.cur, lib.stop, lib.cur, black, red, lib.cursong);
recv(vlevel, &level);
drawvolume(level, black);
flushimage(display, Refnone);
}
void
handleaction(Rune kbd)
{
enum volmsg vmsg;
enum cmsg msg;
switch(kbd){
case Kbs:
case Kdel:
killgrp(decpid);
quit(nil);
return;
case 'w':
break;
case 'p':
msg = PAUSE;
send(ctl, &msg);
return;
case 'l':
msg = START;
send(ctl, &msg);
return;
case 'n':
msg = NEXT;
send(ctl, &msg);
break;
case 'm':
msg = PREV;
send(ctl, &msg);
break;
case '9':
vmsg = DOWN;
send(vctl, &vmsg);
break;
case '0':
vmsg = UP;
send(vctl, &vmsg);
break;
}
eresized(0);
}
void
readvol(int fd, int *level)
{
int n;
char *dot;
char buf[512];
n = pread(fd, buf, (sizeof buf) - 1, 0);
buf[n] = '\0';
dot = strchr(buf, '\n');
if(dot == nil)
goto error;
*dot = '\0';
dot = strstr(buf, "left");
if(dot != nil){
*level = atoi(dot+4+1);
return;
}
dot = strstr(buf, "out");
if(dot == nil)
goto error;
*level = atoi(dot+3);
return;
error:
*level = -1;
}
void
writevol(int fd, int level)
{
char buf[16];
int n = snprint(buf, sizeof buf, "%d", level);
write(fd, buf, n);
}
void
volthread(void *arg)
{
Channel **chans = arg;
Channel *ctl = chans[0];
Channel *out = chans[1];
int fd;
int level;
int muted = 0;
enum volmsg vmsg;
if((fd = open("/dev/volume", ORDWR))<0){
/* Make volume controls NOP */
chanclose(ctl);
chanclose(out);
return;
}
Alt alts[] = {
{ctl, &vmsg, CHANRCV},
{out, &level, CHANSND},
{nil, nil, CHANEND},
};
readvol(fd, &level);
for(;;){
if(alt(alts) != 0)
continue;
readvol(fd, &level);
switch(vmsg){
case UP:
level+=5;
writevol(fd, muted == 0 ? level : 0);
break;
case DOWN:
level-=5;
writevol(fd, muted == 0 ? level : 0);
break;
case MUTE:
muted = 1;
writevol(fd, 0);
break;
case UNMUTE:
muted = 0;
writevol(fd, level);
break;
}
}
}
void
usage(void)
{
fprint(2, "Usage: %s file", argv0);
sysfatal("usage");
}
void
threadmain(int argc, char *argv[])
{
Mouse mouse;
Rune kbd;
int resize[2];
Channel *vchans[2];
ctl = vctl = vlevel = nil;
//TODO: Use ARGBEGIN
argv0 = argv[0];
threadnotify(cleanup, 1);
if(argc != 2)
usage();
if(initdraw(nil, nil, "mpl") < 0)
sysfatal("%s: Failed to init screen %r", argv0);
if((mctl = initmouse(nil, screen)) == nil)
sysfatal("initmouse: %r");
if((kctl = initkeyboard(nil)) == nil)
sysfatal("initkeyboard: %r");
ctl = chancreate(sizeof(enum cmsg), 0);
lout = chancreate(sizeof(Lib), 0);
spawnlib(ctl, lout, argv[1]);
vctl = chancreate(sizeof(enum volmsg), 0);
vlevel = chancreate(sizeof(int), 0);
vchans[0] = vctl;
vchans[1] = vlevel;
threadcreate(volthread, vchans, 8192);
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlue);
black = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlack);
background = allocimagemix(display, DPaleyellow, DPalegreen);
eresized(0);
Alt alts[] = {
{mctl->c, &mouse, CHANRCV},
{mctl->resizec, resize, CHANRCV},
{kctl->c, &kbd, CHANRCV},
{nil, nil, CHANEND},
};
for(;;){
switch(alt(alts)){
case KEYC:
handleaction(kbd);
break;
case RESIZEC:
eresized(1);
break;
}
}
}