Compare commits
2 Commits
f009fcb92b
...
cc78fe00af
Author | SHA1 | Date | |
---|---|---|---|
cc78fe00af | |||
26b304eeb3 |
18
Makefile
18
Makefile
@ -3,13 +3,18 @@ CC := cc
|
|||||||
CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os
|
CFLAGS := -pedantic -Wall -Wno-deprecated-declarations -Os
|
||||||
LDFLAGS := -lX11
|
LDFLAGS := -lX11
|
||||||
PULSEFLAGS := -lpulse
|
PULSEFLAGS := -lpulse
|
||||||
|
NO_X := 0
|
||||||
|
|
||||||
|
ifeq ($(NO_X), 1)
|
||||||
|
CFLAGS := $(CFLAGS) -DNO_X
|
||||||
|
endif
|
||||||
|
|
||||||
# FreeBSD (uncomment)
|
# FreeBSD (uncomment)
|
||||||
#LDFLAGS += -L/usr/local/lib -I/usr/local/include
|
#LDFLAGS += -L/usr/local/lib -I/usr/local/include
|
||||||
# # OpenBSD (uncomment)
|
# # OpenBSD (uncomment)
|
||||||
#LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include
|
#LDFLAGS += -L/usr/X11R6/lib -I/usr/X11R6/include
|
||||||
|
|
||||||
all: options dwmblocks dwmblocks-pulse-listener
|
all: options dwmblocks
|
||||||
|
|
||||||
options:
|
options:
|
||||||
@echo dwmblocks build options:
|
@echo dwmblocks build options:
|
||||||
@ -18,28 +23,23 @@ options:
|
|||||||
@echo "CC = ${CC}"
|
@echo "CC = ${CC}"
|
||||||
@echo "PULSEFLAGS = ${PULSEFLAGS}"
|
@echo "PULSEFLAGS = ${PULSEFLAGS}"
|
||||||
|
|
||||||
dwmblocks: dwmblocks.c blocks.def.h blocks.h
|
dwmblocks: dwmblocks.c pulse-listener.c blocks.def.h blocks.h
|
||||||
${CC} -o dwmblocks dwmblocks.c ${CFLAGS} ${LDFLAGS}
|
${CC} -o dwmblocks dwmblocks.c pulse-listener.c ${CFLAGS} ${PULSEFLAGS} ${LDFLAGS}
|
||||||
|
|
||||||
dwmblocks-pulse-listener: dwmblocks-pulse-listener.c
|
|
||||||
${CC} -o dwmblocks-pulse-listener dwmblocks-pulse-listener.c ${CFLAGS} ${PULSEFLAGS}
|
|
||||||
|
|
||||||
blocks.h:
|
blocks.h:
|
||||||
cp blocks.def.h $@
|
cp blocks.def.h $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.gch dwmblocks dwmblocks-pulse-listener
|
rm -f *.o *.gch dwmblocks
|
||||||
|
|
||||||
install: dwmblocks
|
install: dwmblocks
|
||||||
mkdir -p ${DESTDIR}${PREFIX}/bin
|
mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||||
cp -f dwmblocks ${DESTDIR}${PREFIX}/bin
|
cp -f dwmblocks ${DESTDIR}${PREFIX}/bin
|
||||||
cp -f dwmblocks-pulse-listener ${DESTDIR}${PREFIX}/bin
|
|
||||||
chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks
|
chmod 755 ${DESTDIR}${PREFIX}/bin/dwmblocks
|
||||||
install -m0755 scripts/* ${DESTDIR}${PREFIX}/bin
|
install -m0755 scripts/* ${DESTDIR}${PREFIX}/bin
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks \
|
rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks \
|
||||||
${DESTDIR}${PREFIX}/bin/dwmblocks-pulse-listener \
|
|
||||||
${DESTDIR}${PREFIX}/bin/dwmblocks-battery \
|
${DESTDIR}${PREFIX}/bin/dwmblocks-battery \
|
||||||
${DESTDIR}${PREFIX}/bin/dwmblocks-network \
|
${DESTDIR}${PREFIX}/bin/dwmblocks-network \
|
||||||
${DESTDIR}${PREFIX}/bin/dwmblocks-volume \
|
${DESTDIR}${PREFIX}/bin/dwmblocks-volume \
|
||||||
|
42
dwmblocks.c
42
dwmblocks.c
@ -5,6 +5,7 @@
|
|||||||
#include<signal.h>
|
#include<signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <pthread.h>
|
||||||
#ifndef NO_X
|
#ifndef NO_X
|
||||||
#include<X11/Xlib.h>
|
#include<X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
@ -27,6 +28,7 @@ typedef struct {
|
|||||||
unsigned int interval;
|
unsigned int interval;
|
||||||
unsigned int signal;
|
unsigned int signal;
|
||||||
} Block;
|
} Block;
|
||||||
|
typedef void(*ThreadCallback)(pthread_t *);
|
||||||
void getcmd(const Block *block, char *output);
|
void getcmd(const Block *block, char *output);
|
||||||
void getcmds(int time);
|
void getcmds(int time);
|
||||||
void getsigcmds(unsigned int signal);
|
void getsigcmds(unsigned int signal);
|
||||||
@ -38,7 +40,9 @@ void setupsignals(void);
|
|||||||
int getstatus(char *str, char *last);
|
int getstatus(char *str, char *last);
|
||||||
void pstdout(void);
|
void pstdout(void);
|
||||||
int gcd(int n1, int n2);
|
int gcd(int n1, int n2);
|
||||||
|
void startthreads(void);
|
||||||
void statusloop(void);
|
void statusloop(void);
|
||||||
|
void stopthreads(void);
|
||||||
void termhandler(void);
|
void termhandler(void);
|
||||||
#ifndef NO_X
|
#ifndef NO_X
|
||||||
void setroot(void);
|
void setroot(void);
|
||||||
@ -57,6 +61,10 @@ static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
|
|||||||
static char statusstr[2][STATUSLENGTH];
|
static char statusstr[2][STATUSLENGTH];
|
||||||
static int statuscontinue = 1;
|
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
|
//opens process *cmd and stores output in *output
|
||||||
void getcmd(const Block *block, char *output) {
|
void getcmd(const Block *block, char *output) {
|
||||||
strcpy(output, block->icon);
|
strcpy(output, block->icon);
|
||||||
@ -141,13 +149,21 @@ int getstatus(char *str, char *last) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void pstdout() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
printf("%s\n", statusstr[0]);
|
printf("%s\n", statusstr[0]);
|
||||||
fflush(stdout);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
int gcd(int n1, int n2) {
|
int gcd(int n1, int n2) {
|
||||||
int temp;
|
int temp;
|
||||||
while (n2 > 0){
|
while (n2 > 0){
|
||||||
@ -158,6 +174,16 @@ int gcd(int n1, int n2) {
|
|||||||
return n1;
|
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() {
|
void statusloop() {
|
||||||
setupsignals();
|
setupsignals();
|
||||||
unsigned int interval = -1;
|
unsigned int interval = -1;
|
||||||
@ -166,6 +192,7 @@ void statusloop() {
|
|||||||
interval = gcd(blocks[i].interval, interval);
|
interval = gcd(blocks[i].interval, interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
startthreads();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
getcmds(-1);
|
getcmds(-1);
|
||||||
long nsec_part = interval * 1000000;
|
long nsec_part = interval * 1000000;
|
||||||
@ -174,6 +201,7 @@ void statusloop() {
|
|||||||
const struct timespec sleeptime = { sec_part, nsec_part };
|
const struct timespec sleeptime = { sec_part, nsec_part };
|
||||||
struct timespec tosleep = sleeptime;
|
struct timespec tosleep = sleeptime;
|
||||||
while (statuscontinue) {
|
while (statuscontinue) {
|
||||||
|
initdone = 1;
|
||||||
if (nanosleep(&tosleep, &tosleep) < 0) {
|
if (nanosleep(&tosleep, &tosleep) < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -183,13 +211,20 @@ void statusloop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stopthreads() {
|
||||||
|
for (int i = 0; i < LENGTH(thread_callbacks); ++i) {
|
||||||
|
pthread_cancel(threads[i]);
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void termhandler() {
|
void termhandler() {
|
||||||
statuscontinue = 0;
|
statuscontinue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_X
|
#ifndef NO_X
|
||||||
void setroot() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
XStoreName(dpy, root, statusstr[0]);
|
XStoreName(dpy, root, statusstr[0]);
|
||||||
@ -214,6 +249,8 @@ int main(int argc, char** argv) {
|
|||||||
strncpy(delim, argv[++i], delimLen);
|
strncpy(delim, argv[++i], delimLen);
|
||||||
} else if (strcmp("-p", argv[i]) == 0) {
|
} else if (strcmp("-p", argv[i]) == 0) {
|
||||||
writestatus = pstdout;
|
writestatus = pstdout;
|
||||||
|
} else if (strcmp("-s", argv[i]) == 0) {
|
||||||
|
writestatus = somebar_pstdout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef NO_X
|
#ifndef NO_X
|
||||||
@ -229,5 +266,6 @@ int main(int argc, char** argv) {
|
|||||||
#ifndef NO_X
|
#ifndef NO_X
|
||||||
XCloseDisplay(dpy);
|
XCloseDisplay(dpy);
|
||||||
#endif
|
#endif
|
||||||
|
stopthreads();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
#include "pulse-listener.h"
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/signal.h>
|
#include <signal.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__)
|
#define ERROR(...) fprintf(stderr, "error: " __VA_ARGS__)
|
||||||
@ -15,113 +17,85 @@
|
|||||||
#define SIGMIN SIGRTMIN
|
#define SIGMIN SIGRTMIN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t pid;
|
|
||||||
unsigned int signum;
|
|
||||||
} TargetData;
|
|
||||||
|
|
||||||
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
|
static void sink_info_callback(pa_context *ctx, const pa_sink_info *info,
|
||||||
int eol, TargetData *target) {
|
int eol, pthread_t *main_thread) {
|
||||||
if (info && kill(target->pid, target->signum) < 0) {
|
pthread_kill(*main_thread, SIGMIN + 1);
|
||||||
ERROR("terget process died\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_info_callback(pa_context *ctx, const pa_server_info *info,
|
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(
|
pa_operation *op = pa_context_get_sink_info_by_name(
|
||||||
ctx,
|
ctx,
|
||||||
info->default_sink_name,
|
info->default_sink_name,
|
||||||
(pa_sink_info_cb_t) sink_info_callback,
|
(pa_sink_info_cb_t) sink_info_callback,
|
||||||
target);
|
main_thread);
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subscribe_callback(pa_context *ctx,
|
static void subscribe_callback(pa_context *ctx,
|
||||||
pa_subscription_event_type_t type, uint32_t idx,
|
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) {
|
if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
|
||||||
pa_operation *op = pa_context_get_sink_info_by_index(ctx,
|
pa_operation *op = pa_context_get_sink_info_by_index(ctx,
|
||||||
idx,
|
idx,
|
||||||
(pa_sink_info_cb_t) sink_info_callback,
|
(pa_sink_info_cb_t) sink_info_callback,
|
||||||
target);
|
main_thread);
|
||||||
pa_operation_unref(op);
|
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;
|
pa_operation *op;
|
||||||
switch (pa_context_get_state(ctx)) {
|
switch (pa_context_get_state(ctx)) {
|
||||||
case PA_CONTEXT_READY:
|
case PA_CONTEXT_READY:
|
||||||
op = pa_context_get_server_info(ctx,
|
op = pa_context_get_server_info(ctx,
|
||||||
(pa_server_info_cb_t) server_info_callback,
|
(pa_server_info_cb_t) server_info_callback,
|
||||||
target);
|
main_thread);
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
pa_context_set_subscribe_callback(ctx,
|
pa_context_set_subscribe_callback(ctx,
|
||||||
(pa_context_subscribe_cb_t) subscribe_callback,
|
(pa_context_subscribe_cb_t) subscribe_callback,
|
||||||
target);
|
main_thread);
|
||||||
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
|
op = pa_context_subscribe(ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, NULL);
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
break;
|
break;
|
||||||
case PA_CONTEXT_FAILED:
|
case PA_CONTEXT_FAILED:
|
||||||
if (kill(target->pid, target->signum) < 0) {
|
pthread_kill(*main_thread, SIGMIN + 1);
|
||||||
ERROR("terget process died\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
static void cleanup(void *data_to_free[2]) {
|
||||||
if (argc < 2) {
|
pa_context_unref(data_to_free[1]);
|
||||||
ERROR("no pid\n");
|
pa_mainloop_free(data_to_free[0]);
|
||||||
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();
|
pa_mainloop *mainloop = pa_mainloop_new();
|
||||||
if (!mainloop) {
|
if (!mainloop) {
|
||||||
ERROR("could not create pulse mainloop\n");
|
ERROR("could not create pulse mainloop\n");
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
pa_mainloop_api *api = pa_mainloop_get_api(mainloop);
|
pa_mainloop_api *api = pa_mainloop_get_api(mainloop);
|
||||||
if (!api) {
|
if (!api) {
|
||||||
ERROR("could not create pulse mainloop api\n");
|
ERROR("could not create pulse mainloop api\n");
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
pa_context *context = pa_context_new(api, "dwmblocks-listener");
|
pa_context *context = pa_context_new(api, "dwmblocks-listener");
|
||||||
if (!context) {
|
if (!context) {
|
||||||
ERROR("could not create pulse context\n");
|
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,
|
(pa_context_notify_cb_t)&state_callback,
|
||||||
&target);
|
main_thread);
|
||||||
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
|
if (pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
|
||||||
ERROR("could not connect to pulse");
|
ERROR("could not connect to pulse");
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
void *data_to_free[2] = { mainloop, context };
|
||||||
|
pthread_cleanup_push((void(*)(void *)) cleanup, data_to_free);
|
||||||
pa_mainloop_run(mainloop, NULL);
|
pa_mainloop_run(mainloop, NULL);
|
||||||
return 0;
|
pthread_cleanup_pop(1);
|
||||||
}
|
}
|
8
pulse-listener.h
Normal file
8
pulse-listener.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef INCLUDED_PULSE_LISTENER_H
|
||||||
|
#define INCLUDED_PULSE_LISTENER_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void pulse_listener_main(pthread_t *main_thread);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user