diff --git a/.gitignore b/.gitignore index b6605b4..295d7ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,56 +1,3 @@ -# Custom blocks file blocks.h - -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex dwmblocks - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf +dwmblocks-pulse-listener diff --git a/Makefile b/Makefile index d601b71..898dbe8 100644 --- a/Makefile +++ b/Makefile @@ -2,32 +2,38 @@ PREFIX := /usr/local CC := cc CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os LDFLAGS := -lX11 +PULSEFLAGS := -lpulse # FreeBSD (uncomment) #LDFLAGS += -L/usr/local/lib -I/usr/local/include # # OpenBSD (uncomment) #LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include -all: options dwmblocks +all: options dwmblocks dwmblocks-pulse-listener options: @echo dwmblocks build options: @echo "CFLAGS = ${CFLAGS}" @echo "LDFLAGS = ${LDFLAGS}" @echo "CC = ${CC}" + @echo "PULSEFLAGS = ${PULSEFLAGS}" dwmblocks: dwmblocks.c blocks.def.h blocks.h ${CC} -o dwmblocks dwmblocks.c ${CFLAGS} ${LDFLAGS} +dwmblocks-pulse-listener: dwmblocks-pulse-listener.c + ${CC} -o dwmblocks-pulse-listener dwmblocks-pulse-listener.c ${CFLAGS} ${PULSEFLAGS} + blocks.h: cp blocks.def.h $@ clean: - rm -f *.o *.gch dwmblocks + rm -f *.o *.gch dwmblocks dwmblocks-pulse-listener install: dwmblocks mkdir -p ${DESTDIR}${PREFIX}/bin cp -f dwmblocks ${DESTDIR}${PREFIX}/bin + cp -f dwmblocks-pulse-listener ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks install -m0755 scripts/* ${DESTDIR}${PREFIX}/bin diff --git a/blocks.def.h b/blocks.def.h index 80ea283..4fd26f3 100644 --- a/blocks.def.h +++ b/blocks.def.h @@ -4,7 +4,7 @@ static const Block blocks[] = { /*Icon*/ /*Command*/ /*Update Interval*/ /*Update Signal*/ {"", "dwmblocks-battery", SECONDS(10), 0}, - {"", "dwmblocks-volume", 125, 0}, + {"", "dwmblocks-volume", 0, 1}, {" ", "date +'%a %b %d'", SECONDS(30), 0}, {" ", "date +'%R'", SECONDS(2), 0}, {"", "dwmblocks-network", SECONDS(5), 0}, diff --git a/dwmblocks-pulse-listener.c b/dwmblocks-pulse-listener.c new file mode 100644 index 0000000..da6a0e7 --- /dev/null +++ b/dwmblocks-pulse-listener.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +#define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__) + +typedef struct { + size_t pid; + unsigned int signum; +} TargetData; + +static void sink_info_callback(pa_context *ctx, const pa_sink_info *info, + int eol, TargetData *target) { + if (info) { + kill(target->pid, target->signum); + } +} + +static void server_info_callback(pa_context *ctx, const pa_server_info *info, + TargetData *target) { + pa_operation *op = pa_context_get_sink_info_by_name( + ctx, + info->default_sink_name, + (pa_sink_info_cb_t) sink_info_callback, + target); + pa_operation_unref(op); +} + +static void subscribe_callback(pa_context *ctx, + pa_subscription_event_type_t type, uint32_t idx, + TargetData *target) { + unsigned int facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK; + pa_operation *op = NULL; + switch (facility) { + case PA_SUBSCRIPTION_EVENT_SINK: + op = pa_context_get_sink_info_by_index(ctx, + idx, + (pa_sink_info_cb_t) sink_info_callback, + target); + break; + } + if (op) { + pa_operation_unref(op); + } +} + +static void state_callback(pa_context *ctx, TargetData *target) { + pa_operation *op; + switch (pa_context_get_state(ctx)) { + case PA_CONTEXT_READY: + op = pa_context_get_server_info(ctx, + (pa_server_info_cb_t) server_info_callback, + target); + pa_operation_unref(op); + pa_context_set_subscribe_callback(ctx, + (pa_context_subscribe_cb_t) subscribe_callback, + target); + op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL); + pa_operation_unref(op); + break; + case PA_CONTEXT_FAILED: + kill(target->pid, target->signum); + break; + default: + break; + } +} + +int main(int argc, const char **argv) { + if (argc < 2) { + ERROR("no pid\n"); + return 1; + } + char *endptr = NULL; + unsigned int signum = SIGRTMIN + 1; + if (argc >= 3 && argv[1][0] == '-') { + const char *signumstr = argv[1] + 1; + unsigned long num = strtoul(signumstr, &endptr, 10); + if (num > (SIGRTMAX - SIGRTMIN) + 1) { + ERROR("signal out of range: %lu\n", num); + return 1; + } + signum = SIGRTMIN + num; + ++argv; + } + endptr = NULL; + errno = 0; + unsigned long pid = strtoul(argv[1], &endptr, 10); + if (argv[1][0] == '-' || errno == ERANGE) { + ERROR("pid out of range: \"%s\"\n", argv[1]); + return 1; + } + pa_mainloop *mainloop = pa_mainloop_new(); + if (!mainloop) { + ERROR("could not create pulse mainloop\n"); + return 1; + } + pa_mainloop_api *api = pa_mainloop_get_api(mainloop); + if (!api) { + ERROR("could not create pulse mainloop api\n"); + return 1; + } + pa_context *context = pa_context_new(api, "dwmblocks-listener"); + if (!context) { + ERROR("could not create pulse context\n"); + return 1; + } + TargetData target = { pid, signum }; + pa_context_set_state_callback( context, + (pa_context_notify_cb_t)&state_callback, + &target); + if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { + ERROR("could not connect to pulse"); + return 1; + } + pa_mainloop_run(mainloop, NULL); + return 0; +} diff --git a/dwmblocks.c b/dwmblocks.c index 70fdaae..ce68340 100644 --- a/dwmblocks.c +++ b/dwmblocks.c @@ -64,7 +64,7 @@ void getcmd(const Block *block, char *output) { return; } int i = strlen(block->icon); - fgets(output+i, CMDLENGTH-i-delimLen, cmdf); + fgets(output + i, CMDLENGTH - i - delimLen, cmdf); i = strlen(output); if (i == 0) { //return if block and command output are both empty @@ -72,9 +72,9 @@ void getcmd(const Block *block, char *output) { return; } //only chop off newline if one is present at the end - i = output[i-1] == '\n' ? i-1 : i; + i = output[i - 1] == '\n' ? i - 1 : i; if (delim[0] != '\0') { - strncpy(output+i, delim, delimLen); + strncpy(output + i, delim, delimLen); } else { output[i++] = '\0'; } @@ -83,7 +83,7 @@ void getcmd(const Block *block, char *output) { void getcmds(int time) { const Block* current; - for (unsigned int i = 0; i < LENGTH(blocks); i++) { + for (unsigned int i = 0; i < LENGTH(blocks); ++i) { current = blocks + i; if ((current->interval != 0 && time % current->interval == 0) || time == -1) { getcmd(current,statusbar[i]); @@ -93,7 +93,7 @@ void getcmds(int time) { void getsigcmds(unsigned int signal) { const Block *current; - for (unsigned int i = 0; i < LENGTH(blocks); i++) { + for (unsigned int i = 0; i < LENGTH(blocks); ++i) { current = blocks + i; if (current->signal == signal) { getcmd(current,statusbar[i]); @@ -116,14 +116,14 @@ void sighandler(int signum) { void setupsignals() { #ifndef __OpenBSD__ /* initialize all real time signals with dummy handler */ - for (int i = SIGRTMIN; i <= SIGRTMAX; i++) { + for (int i = SIGRTMIN; i <= SIGRTMAX; ++i) { signal(i, dummysighandler); } #endif - for (unsigned int i = 0; i < LENGTH(blocks); i++) { + for (unsigned int i = 0; i < LENGTH(blocks); ++i) { if (blocks[i].signal > 0) { - signal(SIGMINUS+blocks[i].signal, sighandler); + signal(SIGMINUS + blocks[i].signal, sighandler); } } @@ -132,7 +132,7 @@ void setupsignals() { int getstatus(char *str, char *last) { strcpy(last, str); str[0] = '\0'; - for (unsigned int i = 0; i < LENGTH(blocks); i++) { + for (unsigned int i = 0; i < LENGTH(blocks); ++i) { strcat(str, statusbar[i]); } str[strlen(str)-strlen(delim)] = '\0'; @@ -160,7 +160,7 @@ int gcd(int n1, int n2) { void statusloop() { setupsignals(); unsigned int interval = -1; - for (int i = 0; i < LENGTH(blocks); i++){ + for (int i = 0; i < LENGTH(blocks); ++i){ if (blocks[i].interval){ interval = gcd(blocks[i].interval, interval); }