~andreafeletto/cstatus

1b9b3bc493adc4beb5875f5d3cd3c832cce5dd13 — Andrea Feletto 2 months ago f3d0119
major refactor

split blocks in separate compilation units
get volume via alsalib
better errors
fix: empty sig handler since it already stops sleep()
15 files changed, 301 insertions(+), 206 deletions(-)

M Makefile
A backlight.c
A backlight.h
A battery.c
A battery.h
D blocks.h
A clock.c
A clock.h
M config.h
M config.mk
M cstatus.c
A utils.c
M utils.h
A volume.c
A volume.h
M Makefile => Makefile +2 -2
@@ 3,7 3,7 @@

include config.mk

SRC = cstatus.c
SRC = cstatus.c utils.c backlight.c volume.c battery.c clock.c
OBJ = ${SRC:.c=.o}

all: cstatus


@@ 11,7 11,7 @@ all: cstatus
cstatus: ${OBJ}
	${CC} -o $@ ${OBJ} ${LDFLAGS}

${OBJ}: blocks.h config.h utils.h
${OBJ}: config.h utils.h backlight.c battery.c clock.c volume.c

install: cstatus
	install -Dm755 cstatus "${DESTDIR}${PREFIX}/bin/cstatus"

A backlight.c => backlight.c +39 -0
@@ 0,0 1,39 @@

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#include "backlight.h"
#include "utils.h"

#define BLBRIGH  "/sys/class/backlight/intel_backlight/brightness"
#define BLMAX    "/sys/class/backlight/intel_backlight/max_brightness"

int
backlight(char *buf) {
	assert(buf != NULL);

	FILE *fp;
	int b, mb, p;

	if ((fp = fopen(BLBRIGH, "r")) == NULL) {
		warn("cannot open file '%s'", BLBRIGH);
	}
	if (fscanf(fp, "%d", &b) != 1) {
		warn("cannot read brightness value");
	}
	fclose(fp);

	if ((fp = fopen(BLMAX, "r")) == NULL) {
		warn("cannot open file '%s'", BLBRIGH);
	}
	if (fscanf(fp, "%d", &mb) != 1) {
		warn("cannot read max brightness value");
	}
	fclose(fp);

	p = (int)round(100 * (double)b / (double)mb);
	sprintf(buf + strlen(buf), "\U0001f4a1 %4d%%", p);
	return 1;
}

A backlight.h => backlight.h +7 -0
@@ 0,0 1,7 @@

#ifndef CSTATUS_BACKLIGHT_H
#define CSTATUS_BACKLIGHT_H

int backlight(char *buf);

#endif

A battery.c => battery.c +47 -0
@@ 0,0 1,47 @@

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include "utils.h"

#define BATCAP   "/sys/class/power_supply/BAT1/capacity"
#define BATSTAT  "/sys/class/power_supply/BAT1/status"

int
battery(char *buf) {
	assert(buf != NULL);

	FILE *fp;
	char status[16], *icon;
	int capacity;

	if ((fp = fopen(BATCAP, "r")) == NULL) {
		warn("cannot open file '%s'", BATCAP);
	}
	if (fscanf(fp, "%d", &capacity) != 1) {
		warn("cannot read battery capacity");
	}
	fclose(fp);

	if ((fp = fopen(BATSTAT, "r")) == NULL) {
		warn("cannot open file '%s'", BATSTAT);
	}
	if (fscanf(fp, "%s", &status[0]) != 1) {
		warn("cannot read battery status");
	}
	fclose(fp);

	if (strcmp(status, "Discharging") == 0) {
		icon = "\U0001f50b";
	} else if (strcmp(status, "Charging") == 0) {
		icon = "\U0001f50c";
	} else if (strcmp(status, "Full") == 0) {
		icon = "\u26a1";
	} else {
		icon = "\u2753";
	}

	sprintf(buf + strlen(buf), "%s %4d%%", icon, capacity);
	return 1;
}

A battery.h => battery.h +7 -0
@@ 0,0 1,7 @@

#ifndef CSTATUS_BATTERY_H
#define CSTATUS_BATTERY_H

int battery(char *buf);

#endif

D blocks.h => blocks.h +0 -126
@@ 1,126 0,0 @@

#ifndef CSTATUS_BLOCKS_H
#define CSTATUS_BLOCKS_H

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include "utils.h"

#define BATCAP   "/sys/class/power_supply/BAT1/capacity"
#define BATSTAT  "/sys/class/power_supply/BAT1/status"
#define BLBRIGH  "/sys/class/backlight/intel_backlight/brightness"
#define BLMAX    "/sys/class/backlight/intel_backlight/max_brightness"

void backlight(char *buf);
void battery(char *buf);
void volume(char *buf);
void sclock(char *buf);

void
backlight(char *buf) {
	assert(buf != NULL);

	FILE *fp;
	int b, mb, p;

	if ((fp = fopen(BLBRIGH, "r")) == NULL) {
		die("cannot read brightness file '%s'", BLBRIGH);
	}
	if (fscanf(fp, "%d", &b) != 1) {
		die("cannot read brightness value:");
	}
	fclose(fp);

	if ((fp = fopen(BLMAX, "r")) == NULL) {
		die("cannot read max brightness file '%s'", BLBRIGH);
	}
	if (fscanf(fp, "%d", &mb) != 1) {
		die("cannot read max brightness value:");
	}
	fclose(fp);

	p = (int)round(100 * (double)b / (double)mb);
	sprintf(buf + strlen(buf), "\U0001f4a1 %4d%%", p);
}

void
volume(char *buf) {
	assert(buf != NULL);

	int mute, volume;

	if (system(NULL) == 0) {
		die("no command processors available:");
	}
	if (system("command -v pulsemixer > /dev/null") > 0) {
		die("missing dependency: pulsemixer");
	}

	if (pscanf("pulsemixer --get-mute", "%d", &mute) != 1) {
		die("pscanf");
	}
	if (mute) {
		strcat(buf, "   \U0001f507   ");
		return;
	}

	if (pscanf("pulsemixer --get-volume", "%d", &volume) != 1) {
		die("pscanf");
	}
	sprintf(buf + strlen(buf), "\U0001f50a %4d%%", volume);
}

void
battery(char *buf) {
	assert(buf != NULL);

	FILE *fp;
	char status[16], *icon;
	int capacity;

	if ((fp = fopen(BATCAP, "r")) == NULL) {
		die("fopen %s:" BATCAP);
	}
	if (fscanf(fp, "%d", &capacity) != 1) {
		die("fscanf:");
	}
	fclose(fp);

	if ((fp = fopen(BATSTAT, "r")) == NULL) {
		die("fopen %s:", BATSTAT);
	}
	if (fscanf(fp, "%s", status) != 1) {
		die("fscanf:");
	}
	fclose(fp);

	if (strcmp(status, "Discharging") == 0) {
		icon = "\U0001f50b";
	} else if (strcmp(status, "Charging") == 0) {
		icon = "\U0001f50c";
	} else if (strcmp(status, "Full") == 0) {
		icon = "\u26a1";
	} else {
		icon = "\u2753";
	}

	sprintf(buf + strlen(buf), "%s %4d%%", icon, capacity);
}

void
sclock(char *buf) {
	assert(buf != NULL);

	time_t now;

	if((now = time(NULL)) == ((time_t)-1)) {
		die("time:");
	}
	strftime(buf + strlen(buf), 16, "%R", localtime(&now));
}

#endif

A clock.c => clock.c +17 -0
@@ 0,0 1,17 @@

#include <assert.h>
#include <string.h>
#include <time.h>

#include "clock.h"

int
clock_hm(char *buf) {
	assert(buf != NULL);

	time_t now;

	now = time(NULL);
	strftime(buf + strlen(buf), 16, "%R", localtime(&now));
	return 1;
}

A clock.h => clock.h +7 -0
@@ 0,0 1,7 @@

#ifndef CSTATUS_CLOCK_H
#define CSTATUS_CLOCK_H

int clock_hm(char *buf);

#endif

M config.h => config.h +6 -1
@@ 1,10 1,15 @@

#include "backlight.h"
#include "battery.h"
#include "clock.h"
#include "volume.h"

#define SEP " | "

static Block blocks[] = {
	backlight,
	volume,
	battery,
	sclock,
	clock_hm,
	NULL
};

M config.mk => config.mk +1 -1
@@ 6,4 6,4 @@ CC = cc

CPPFLAGS = -D_POSIX_C_SOURCE=200112L
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${CPPFLAGS}
LDFLAGS = -lm -lX11
LDFLAGS = -lm -lX11 -lasound
\ No newline at end of file

M cstatus.c => cstatus.c +22 -20
@@ 8,25 8,20 @@

#include <X11/Xlib.h>

#include "utils.h"
typedef int (*Block)(char *);

#include "config.h"

static Display *dpy;
static int screen;
static Window root;

typedef void (*Block)(char *);

#include "blocks.h"

#include "config.h"

void
usage(void) {
	fprintf(stderr, "usage: cstatus\n\nstatusbar for dwm.\n");
	exit(EXIT_SUCCESS);
	fputs("usage: cstatus\n\nstatusbar for dwm.\n", stderr);
}

void
int
refresh(void) {
	Block *b;
	char name[256];


@@ 34,42 29,49 @@ refresh(void) {
	name[0] = '\0';
	for (b = blocks; *b != NULL; b++) {
		strcat(name, SEP);
		(*b)(name);
		if (!(*b)(name)) {
			return 0;
		}
	}
	XStoreName(dpy, root, name);
	XFlush(dpy);
	return 1;
}

void
signalhandler(int signum) {
	assert(signum == SIGUSR1);

	refresh();
signalhandler(int n) {
	assert(n == SIGUSR1);
}

int
main (int argc, char **argv) {
main(int argc, char **argv) {
	struct sigaction sa;

	if (argc > 1) {
		usage();
		return EXIT_SUCCESS;
	}

	dpy = XOpenDisplay(NULL);
	if (dpy == NULL) {
		die("cannot open display");
		fputs("x11: cannot open display\n", stderr);
		return EXIT_FAILURE;
	}
	screen = DefaultScreen(dpy);
	root = RootWindow(dpy, screen);

	sa.sa_handler = signalhandler;
	sa.sa_flags = 0;
	if (sigaction(SIGUSR1, &sa, NULL) == -1) {
		die("error: cannot listen to signal USR1");
		fputs("cannot listen to signal USR1\n", stderr);
		return EXIT_FAILURE;
	}

	while (1) {
		refresh();
		sleep(10);
		if (!refresh()) {
			return EXIT_FAILURE;
		}
		sleep(3);
	}

	XCloseDisplay(dpy);

A utils.c => utils.c +60 -0
@@ 0,0 1,60 @@

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utils.h"

void
verr(const char *fmt, va_list ap) {
	fprintf(stderr, "error: ");
	vfprintf(stderr, fmt, ap);

	if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
		fputc(' ', stderr);
		perror(NULL);
	} else {
		fputc('\n', stderr);
	}
}

void
warn(const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	verr(fmt, ap);
	va_end(ap);
}

void
die(const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	verr(fmt, ap);
	va_end(ap);
	exit(EXIT_FAILURE);
}

int
pscanf(const char *cmd, const char *fmt, ...) {
	va_list ap;
	FILE *pipe;
	int n;

	va_start(ap, fmt);
	if ((pipe = popen(cmd, "r")) == NULL) {
		die("popen '%s':", cmd);
	}
	if ((n = vfscanf(pipe, fmt, ap)) == EOF) {
		die("fscanf:");
	}
	if (pclose(pipe) == -1) {
		die("pclose:");
	}
	va_end(ap);

	return n;
}

M utils.h => utils.h +3 -56
@@ 3,68 3,15 @@
#define CSTATUS_UTILS_H

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LENGTH(X) (sizeof X / sizeof X[0])

void verr(const char *fmt, va_list ap);
void die(const char *fmt, ...);
void ward(const char *fmt, ...);
int pscanf(const char *cmd, const char *fmt, ...);

void
verr(const char *fmt, va_list ap) {
	fprintf(stderr, "error: ");
	vfprintf(stderr, fmt, ap);

	if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
		fputc(' ', stderr);
		perror(NULL);
	} else {
		fputc('\n', stderr);
	}
}

void
warn(const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	verr(fmt, ap);
	va_end(ap);
}

void
die(const char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	verr(fmt, ap);
	va_end(ap);
	exit(EXIT_FAILURE);
}

int
pscanf(const char *cmd, const char *fmt, ...) {
	va_list ap;
	FILE *pipe;
	int n;
void die(const char *fmt, ...);

	va_start(ap, fmt);
	if ((pipe = popen(cmd, "r")) == NULL) {
		die("popen '%s':", cmd);
	}
	if ((n = vfscanf(pipe, fmt, ap)) == EOF) {
		die("fscanf:");
	}
	if (pclose(pipe) == -1) {
		die("pclose:");
	}
	va_end(ap);
void warn(const char *fmt, ...);

	return n;
}
int pscanf(const char *cmd, const char *fmt, ...);

#endif

A volume.c => volume.c +76 -0
@@ 0,0 1,76 @@

#include <alloca.h>
#include <assert.h>
#include <math.h>
#include <stdio.h>

#include <alsa/asoundlib.h>

#include "volume.h"

#define SELEM_ID 0
#define SELEM_NAME "Master"
#define CHANNEL_ID SND_MIXER_SCHN_MONO

int
volume(char *buf) {
	assert(buf != NULL);

	snd_mixer_t *amix;
	snd_mixer_selem_id_t *asid;
	snd_mixer_elem_t *aele;
	long min, max, av, v;
	int s;

	if (snd_mixer_open(&amix, 0) < 0) {
		fputs("alsa: cannot open mixer\n", stderr);
		return 0;
	}
	if (snd_mixer_attach(amix, "default") < 0) {
		fputs("alsa: cannot attach high level control interface\n",
			stderr);
		return 0;
	}
	if (snd_mixer_selem_register(amix, NULL, NULL) < 0) {
		fputs("alsa: cannot register simple element class\n", stderr);
		return 0;
	}
	if (snd_mixer_load(amix) < 0) {
		fputs("alsa: cannot load mixer\n", stderr);
		return 0;
	}

	snd_mixer_selem_id_alloca(&asid);
	snd_mixer_selem_id_set_index(asid, SELEM_ID);
	snd_mixer_selem_id_set_name(asid, SELEM_NAME);
	aele = snd_mixer_find_selem(amix, asid);
	if (aele == NULL) {
		fputs("cannot find simple mixer element with:\n", stderr);
		fprintf(stderr, "  name: %s\n", SELEM_NAME);
		fprintf(stderr, "  id: %d\n", SELEM_ID);
		return 0;
	}

	if (snd_mixer_selem_get_playback_switch(aele, CHANNEL_ID, &s) < 0) {
		fputs("alsa: cannot get playback switch\n", stderr);
		return 0;
	}
	if (!s) {
	 	strcat(buf, "   \U0001f507   ");
	 	return 1;
	}

	if (snd_mixer_selem_get_playback_volume_range(aele, &min, &max) < 0) {
		fputs("alsa: cannot get playback volume\n", stderr);
		return 0;
	}
	if (snd_mixer_selem_get_playback_volume(aele, CHANNEL_ID, &av) < 0) {
		fputs("alsa: cannot get playback volume\n", stderr);
		return 0;
	}
	snd_mixer_close(amix);

	v = min + (long)round((double)av * 100 / (max - min));
	sprintf(buf + strlen(buf), "\U0001f50a %4ld%%", v);
	return 1;
}

A volume.h => volume.h +7 -0
@@ 0,0 1,7 @@

#ifndef CSTATUS_VOLUME_H
#define CSTATUS_VOLUME_H

int volume(char *buf);

#endif