@@ -0,0 +1,16 @@ | |||
PREFIX=/usr/local | |||
all: dwmstatus dwmstatus-pulse | |||
clean: | |||
rm -f dwmstatus dwmstatus-pulse | |||
install: | |||
cp dwmstatus $(PREFIX)/bin | |||
cp dwmstatus-pulse $(PREFIX)/bin | |||
dwmstatus-pulse: dwmstatus-pulse.c | |||
$(CC) $< `pkg-config --libs libpulse-mainloop-glib` -o $@ | |||
%: %.c | |||
$(CC) $< -o $@ |
@@ -0,0 +1,94 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <pulse/pulseaudio.h> | |||
#include <unistd.h> | |||
static char *default_label = ""; | |||
static char *label = NULL; | |||
static char *device_name = NULL; | |||
static void | |||
sinkcbk(pa_context *ctx, const pa_sink_info *i, int eol, void *userdata) | |||
{ | |||
if(!i) | |||
return; | |||
float volume = (float)pa_cvolume_avg(&i->volume) / (float)PA_VOLUME_NORM; | |||
if(i->mute) | |||
printf("MUTE\n"); | |||
else | |||
printf("%s%0.0f\n", label, volume * 100); | |||
fflush(stdout); | |||
} | |||
static void | |||
eventcbk(pa_context *ctx, pa_subscription_event_type_t t, uint32_t idx, void *data) | |||
{ | |||
pa_operation *op = NULL; | |||
if((t & (PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE))) | |||
op = pa_context_get_sink_info_by_name(ctx, device_name, sinkcbk, data); | |||
if(op) | |||
pa_operation_unref(op); | |||
} | |||
static void | |||
servercbk(pa_context *ctx, const pa_server_info *i, void *user) | |||
{ | |||
device_name = strdup(i->default_sink_name); | |||
} | |||
int | |||
main(int argc, char *argv[]) | |||
{ | |||
int c; | |||
pa_mainloop *mloop; | |||
pa_mainloop_api *mloopapi; | |||
pa_context *ctx; | |||
pa_context_state_t state; | |||
pa_operation *op; | |||
label = default_label; | |||
while((c = getopt(argc, argv, "d:l:")) > 0) { | |||
switch(c) { | |||
case 'd': | |||
device_name = strdup(optarg); | |||
break; | |||
case 'l': | |||
label = strdup(optarg); | |||
break; | |||
} | |||
} | |||
mloop = pa_mainloop_new(); | |||
mloopapi = pa_mainloop_get_api(mloop); | |||
ctx = pa_context_new(mloopapi, "DWMstatus audio"); | |||
pa_context_connect(ctx, NULL, 0, NULL); | |||
/* wait until ready */ | |||
while((state = pa_context_get_state(ctx)) != PA_CONTEXT_READY) { | |||
switch(state) { | |||
case PA_CONTEXT_FAILED: | |||
case PA_CONTEXT_TERMINATED: | |||
goto end; | |||
default: ;/* do nothing */ | |||
} | |||
pa_mainloop_iterate(mloop, 1, NULL); | |||
} | |||
op = pa_context_get_server_info(ctx, servercbk, NULL); | |||
pa_operation_unref(op); | |||
pa_context_set_subscribe_callback(ctx, eventcbk, NULL); | |||
pa_context_subscribe(ctx, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, NULL, NULL); | |||
eventcbk(ctx, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, 0, NULL); | |||
pa_mainloop_run(mloop, NULL); | |||
end: | |||
pa_context_disconnect(ctx); | |||
pa_context_unref(ctx); | |||
pa_mainloop_free(mloop); | |||
return 0; | |||
} |
@@ -0,0 +1,10 @@ | |||
#!/bin/sh | |||
TIME=$1 | |||
shift | |||
while true | |||
do | |||
$@ | |||
sleep $TIME | |||
done |
@@ -0,0 +1,163 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <time.h> | |||
#include <signal.h> | |||
#include <errno.h> | |||
#include <unistd.h> | |||
#include <sys/select.h> | |||
#include <sys/fcntl.h> | |||
#include <sys/wait.h> | |||
typedef struct Process Process; | |||
struct Process { | |||
pid_t pid; | |||
int fd; | |||
char str[64]; | |||
Process *next; | |||
}; | |||
static Process *list = NULL; | |||
int | |||
max(int a, int b) | |||
{ | |||
return (a > b ? a : b); | |||
} | |||
Process * | |||
newproc(const char *command) | |||
{ | |||
Process *p; | |||
int pipes[2]; | |||
pid_t pid; | |||
if(pipe(pipes) < 0) { | |||
perror("pipe()"); | |||
exit(EXIT_FAILURE); | |||
} | |||
switch((pid = fork())) { | |||
case -1: | |||
perror("fork()"); | |||
exit(EXIT_FAILURE); | |||
case 0: | |||
close(0); | |||
close(1); | |||
dup2(pipes[1], 1); | |||
close(pipes[0]); | |||
close(pipes[1]); | |||
execl("/bin/sh", "/bin/sh", "-c", command, NULL); | |||
exit(EXIT_SUCCESS); | |||
return NULL; | |||
default: | |||
close(pipes[1]); | |||
p = malloc(sizeof *p); | |||
if(!p) { | |||
perror("malloc()"); | |||
exit(EXIT_FAILURE); | |||
} | |||
memset(p, 0, sizeof *p); | |||
p->pid = pid; | |||
p->fd = pipes[0]; | |||
return p; | |||
} | |||
} | |||
static void | |||
sigtrap(int sig) | |||
{ | |||
if(sig != SIGINT) | |||
return; | |||
for(Process *p = list; p; p = p->next) { | |||
killpg(p->pid, sig); | |||
} | |||
while(wait(NULL) != -1 || errno == EINTR); | |||
/* let the operating take care of the memory leak, fuck it */ | |||
exit(EXIT_SUCCESS); | |||
} | |||
int | |||
linerd(int fd, char *line, int linesize) | |||
{ | |||
int i; | |||
for(i = 0; i < linesize; i++) { | |||
char c; | |||
if(read(fd, &c, sizeof c) <= 0) { | |||
break; | |||
} | |||
if(c == '\n') { | |||
line[i] = 0; | |||
break; | |||
} | |||
line[i] = c; | |||
} | |||
line[linesize - 1] = 0; | |||
return i; | |||
} | |||
int | |||
main(int argc, char *argv[]) | |||
{ | |||
int maxfd = 0, i, c; | |||
fd_set rdset; | |||
Process *p; | |||
signal(SIGINT, sigtrap); | |||
signal(SIGTERM, sigtrap); | |||
signal(SIGKILL, sigtrap); | |||
FD_ZERO(&rdset); | |||
while((c = getopt(argc, argv, "c:")) > 0) { | |||
switch(c) { | |||
case 'c': | |||
p = newproc(optarg); | |||
FD_SET(p->fd, &rdset); | |||
maxfd = max(maxfd, p->fd); | |||
p->next = list; | |||
list = p; | |||
break; | |||
default: | |||
fprintf(stderr, "Unknown option: %c\n", c); | |||
exit(EXIT_FAILURE); | |||
} | |||
} | |||
if(!list) { | |||
fprintf(stderr, "usage: %s -c command [-c command2 ]...\n", argv[0]); | |||
exit(EXIT_FAILURE); | |||
} | |||
for(;;) { | |||
int n; | |||
fd_set copy; | |||
FD_ZERO(©); | |||
memcpy(©, &rdset, sizeof rdset); | |||
n = select(maxfd + 1, ©, NULL, NULL, NULL); | |||
if(n < 0) { | |||
perror("select()"); | |||
continue; | |||
} | |||
for(Process *p = list; p; p = p->next) | |||
if(FD_ISSET(p->fd, ©)) { | |||
if(linerd(p->fd, p->str, sizeof p->str) <= 0) { | |||
FD_CLR(p->fd, &rdset); | |||
close(p->fd); | |||
} | |||
} | |||
for(Process *p = list; p; p = p->next) | |||
printf("%s%s", p->str, p->next ? " | " : ""); | |||
printf("\n"); | |||
fflush(stdout); | |||
} | |||
return 0; | |||
} |