diff --git a/Makefile b/Makefile index 4347d03..52b8e2d 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,18 @@ CC := cc CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os LDFLAGS := -lX11 PULSEFLAGS := -lpulse +NO_X := 0 + +ifeq ($(NO_X), 1) + CFLAGS := $(CFLAGS) -DNO_X +endif # 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 dwmblocks-pulse-listener +all: options dwmblocks options: @echo dwmblocks build options: @@ -18,28 +23,23 @@ options: @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} +dwmblocks: dwmblocks.c pulse-listener.c blocks.def.h blocks.h + ${CC} -o dwmblocks dwmblocks.c pulse-listener.c ${CFLAGS} ${PULSEFLAGS} ${LDFLAGS} blocks.h: cp blocks.def.h $@ clean: - rm -f *.o *.gch dwmblocks dwmblocks-pulse-listener + rm -f *.o *.gch dwmblocks 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 uninstall: rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks \ - ${DESTDIR}${PREFIX}/bin/dwmblocks-pulse-listener \ ${DESTDIR}${PREFIX}/bin/dwmblocks-battery \ ${DESTDIR}${PREFIX}/bin/dwmblocks-network \ ${DESTDIR}${PREFIX}/bin/dwmblocks-volume \ diff --git a/dwmblocks.c b/dwmblocks.c index cd05dca..c987dbe 100644 --- a/dwmblocks.c +++ b/dwmblocks.c @@ -5,6 +5,7 @@ #include #include #include +#include #ifndef NO_X #include #endif @@ -27,6 +28,7 @@ typedef struct { unsigned int interval; unsigned int signal; } Block; +typedef void(*ThreadCallback)(pthread_t *); void getcmd(const Block *block, char *output); void getcmds(int time); void getsigcmds(unsigned int signal); @@ -38,7 +40,9 @@ void setupsignals(void); int getstatus(char *str, char *last); void pstdout(void); int gcd(int n1, int n2); +void startthreads(void); void statusloop(void); +void stopthreads(void); void termhandler(void); #ifndef NO_X void setroot(void); @@ -57,6 +61,10 @@ static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0}; static char statusstr[2][STATUSLENGTH]; static int statuscontinue = 1; +static pthread_t main_thread; +static pthread_t threads[LENGTH(thread_callbacks)]; +static int initdone = 0; + //opens process *cmd and stores output in *output void getcmd(const Block *block, char *output) { strcpy(output, block->icon); @@ -87,7 +95,7 @@ void getcmds(int time) { 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]); + getcmd(current, statusbar[i]); } } } @@ -97,7 +105,7 @@ void getsigcmds(unsigned int signal) { for (unsigned int i = 0; i < LENGTH(blocks); ++i) { current = blocks + i; if (current->signal == signal) { - getcmd(current,statusbar[i]); + getcmd(current, statusbar[i]); } } } @@ -141,10 +149,18 @@ int getstatus(char *str, char *last) { } void pstdout() { - if (!getstatus(statusstr[0], statusstr[1])) { //Only write out if text has changed. + if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only write out if text has changed. return; } - printf("%s\n",statusstr[0]); + printf("%s\n", statusstr[0]); + fflush(stdout); +} + +void somebar_pstdout() { + if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only write out if text has changed. + return; + } + printf("status %s\n", statusstr[0]); fflush(stdout); } @@ -158,6 +174,16 @@ int gcd(int n1, int n2) { return n1; } +void startthreads() { + main_thread = pthread_self(); + for (int i = 0; i < LENGTH(thread_callbacks); ++i) { + pthread_create(&threads[i], + NULL, + (void *(*)(void *)) thread_callbacks[i], + &main_thread); + } +} + void statusloop() { setupsignals(); unsigned int interval = -1; @@ -166,6 +192,7 @@ void statusloop() { interval = gcd(blocks[i].interval, interval); } } + startthreads(); int i = 0; getcmds(-1); long nsec_part = interval * 1000000; @@ -174,6 +201,7 @@ void statusloop() { const struct timespec sleeptime = { sec_part, nsec_part }; struct timespec tosleep = sleeptime; while (statuscontinue) { + initdone = 1; if (nanosleep(&tosleep, &tosleep) < 0) { continue; } @@ -183,13 +211,19 @@ void statusloop() { } } +void stopthreads() { + for (int i = 0; i < LENGTH(thread_callbacks); ++i) { + pthread_kill(threads[i], SIGTERM); + } +} + void termhandler() { statuscontinue = 0; } #ifndef NO_X void setroot() { - if (!getstatus(statusstr[0], statusstr[1])) { //Only set root if text has changed. + if (!initdone || !getstatus(statusstr[0], statusstr[1])) { //Only set root if text has changed. return; } XStoreName(dpy, root, statusstr[0]); @@ -214,6 +248,8 @@ int main(int argc, char** argv) { strncpy(delim, argv[++i], delimLen); } else if (strcmp("-p", argv[i]) == 0) { writestatus = pstdout; + } else if (strcmp("-s", argv[i]) == 0) { + writestatus = somebar_pstdout; } } #ifndef NO_X @@ -229,5 +265,6 @@ int main(int argc, char** argv) { #ifndef NO_X XCloseDisplay(dpy); #endif + stopthreads(); return 0; } diff --git a/dwmblocks-pulse-listener.c b/pulse-listener.c similarity index 58% rename from dwmblocks-pulse-listener.c rename to pulse-listener.c index 032d1b1..b4cb769 100644 --- a/dwmblocks-pulse-listener.c +++ b/pulse-listener.c @@ -1,8 +1,10 @@ +#include "pulse-listener.h" + #include #include #include #include -#include +#include #include #define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__) @@ -15,113 +17,77 @@ #define SIGMIN SIGRTMIN #endif -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) < 0) { - ERROR("terget process died\n"); - exit(1); - } + int eol, pthread_t *main_thread) { + pthread_kill(*main_thread, SIGMIN + 1); } static void server_info_callback(pa_context *ctx, const pa_server_info *info, - TargetData *target) { + pthread_t *main_thread) { pa_operation *op = pa_context_get_sink_info_by_name( ctx, info->default_sink_name, (pa_sink_info_cb_t) sink_info_callback, - target); + main_thread); pa_operation_unref(op); } static void subscribe_callback(pa_context *ctx, pa_subscription_event_type_t type, uint32_t idx, - TargetData *target) { + pthread_t *main_thread) { if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) { pa_operation *op = pa_context_get_sink_info_by_index(ctx, idx, (pa_sink_info_cb_t) sink_info_callback, - target); + main_thread); pa_operation_unref(op); } } -static void state_callback(pa_context *ctx, TargetData *target) { +static void state_callback(pa_context *ctx, pthread_t *main_thread) { 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); + main_thread); pa_operation_unref(op); pa_context_set_subscribe_callback(ctx, (pa_context_subscribe_cb_t) subscribe_callback, - target); + main_thread); op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL); pa_operation_unref(op); break; case PA_CONTEXT_FAILED: - if (kill(target->pid, target->signum) < 0) { - ERROR("terget process died\n"); - exit(1); - } + pthread_kill(*main_thread, SIGMIN + 1); 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 = SIGMIN + 1; - if (argc >= 3 && argv[1][0] == '-') { - const char *signumstr = argv[1] + 1; - unsigned long num = strtoul(signumstr, &endptr, 10); - if (num > SIGMAX - SIGMIN) { - ERROR("signal out of range: %lu\n", num); - return 1; - } - signum = SIGMIN + 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; - } +void pulse_listener_main(pthread_t *main_thread) { pa_mainloop *mainloop = pa_mainloop_new(); if (!mainloop) { ERROR("could not create pulse mainloop\n"); - return 1; + return; } pa_mainloop_api *api = pa_mainloop_get_api(mainloop); if (!api) { ERROR("could not create pulse mainloop api\n"); - return 1; + return; } pa_context *context = pa_context_new(api, "dwmblocks-listener"); if (!context) { ERROR("could not create pulse context\n"); - return 1; + return; } - TargetData target = { pid, signum }; - pa_context_set_state_callback( context, + pa_context_set_state_callback(context, (pa_context_notify_cb_t)&state_callback, - &target); + main_thread); if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { ERROR("could not connect to pulse"); - return 1; + return; } pa_mainloop_run(mainloop, NULL); - return 0; } diff --git a/pulse-listener.h b/pulse-listener.h new file mode 100644 index 0000000..8a1a993 --- /dev/null +++ b/pulse-listener.h @@ -0,0 +1,8 @@ +#ifndef INCLUDED_PULSE_LISTENER_H +#define INCLUDED_PULSE_LISTENER_H + +#include + +void pulse_listener_main(pthread_t *main_thread); + +#endif