commit f026a2d0c180b65c27efafd9aec689291267c820 Author: Alessandro Mauri Date: Wed Dec 30 18:52:31 2020 +0100 initial commitment diff --git a/makefile b/makefile new file mode 100644 index 0000000..37ba9a7 --- /dev/null +++ b/makefile @@ -0,0 +1,21 @@ +CFLAGS = -Wall -Werror -pedantic -Ofast -std=c99 +LDFLAGS = -L/usr/X11R6/lib -lX11 +CC = gcc +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +status: status.c + +debug: status.c + ${CC} ${LDFLAGS} -O0 -g -o stat_debug $? + +install: status + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f status ${DESTDIR}${PREFIX}/bin/status + chmod 755 ${DESTDIR}${PREFIX}/bin/status + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/status + +clean: + rm -f status stat_debug diff --git a/status.c b/status.c new file mode 100644 index 0000000..86b83d5 --- /dev/null +++ b/status.c @@ -0,0 +1,169 @@ +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ELEMENT_NUMBER 2 +#define CHARS 64 +#define SEPARATOR " | " +#define BAR_LENGTH (CHARS - (ELEMENT_NUMBER - 1) * sizeof(SEPARATOR)) +#define ELEMENT_SIZE (BAR_LENGTH / ELEMENT_NUMBER) +/* ANSI colors escape codes */ +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_RESET "\x1b[0m" + +const char bat_base_dir[] = "/sys/class/power_supply/"; + +struct battery_descriptor { + int f_cap; /* Capacity file pointer */ + int f_stat; /* Status file pointer */ +}; + +static const char * get_date (void); +static const char * get_battery (void); +static void die (const char *, ...); + +int main (void) +{ + static int screen; + static Display *dpy = NULL; + static Window root; + static char bar[BAR_LENGTH] = {0}; + + dpy = XOpenDisplay(NULL); + if (!dpy) + die("cannot open default display"); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + + // TODO: do not use sleep instead poll file desciptors for a change + for (;;sleep(10)) { + if (snprintf(bar, BAR_LENGTH, "%s" SEPARATOR "%s", get_battery(), get_date()) > BAR_LENGTH) + bar[BAR_LENGTH - 1] = '\0'; + + XStoreName(dpy, root, bar); + XSync(dpy, False); + } + + XCloseDisplay(dpy); + return 0; +} + +static const char * get_date (void) +{ + static char str[ELEMENT_SIZE] = {0}; + static time_t rawtime; + time(&rawtime); + strftime(str, ELEMENT_SIZE, "%a %d %b %H:%M", localtime(&rawtime)); + return str; +} + +static const char * get_battery (void) { + static char str[ELEMENT_SIZE] = {0}; + static int init = 1; + static struct battery_descriptor *bat_arr = NULL; + static int bat_num = 0; + static char buf[sizeof(bat_base_dir) + 256 + 64]; + + if (init) { + DIR *bdir; + struct dirent *dent = NULL; + int tmpf; + + if (!(bdir = opendir(bat_base_dir))) + die("error opening %s", bat_base_dir); + while (1) { + errno = 0; + if (!(dent = readdir(bdir))) { + if (errno) + die("error reading %s", bat_base_dir); + else + break; + } + /* if (dent->d_type != DT_DIR) + continue;*/ + if (!strstr(dent->d_name, "BAT")) + continue; + + bat_arr = realloc(bat_arr, sizeof(struct battery_descriptor) * ++bat_num); + if(!bat_arr) + die("bad realloc in get_battery"); + + strcpy(buf, bat_base_dir); + strcat(buf, dent->d_name); + strcat(buf, "/capacity"); + if ((tmpf = open(buf, O_RDONLY | O_NONBLOCK)) < 0) + die("error opening %s", buf); + bat_arr[bat_num - 1].f_cap = tmpf; + + strcpy(buf, bat_base_dir); + strcat(buf, dent->d_name); + strcat(buf, "/status"); + if ((tmpf = open(buf, O_RDONLY | O_NONBLOCK)) < 0) + die("error opening %s", buf); + bat_arr[bat_num - 1].f_stat = tmpf; + } + closedir(bdir); + if (!bat_arr) + die("no batteries were found"); + init = 0; + } + memset(str, 0, ELEMENT_SIZE); + int cap = 0; + int level = 0; + int barsize = 0; + int charging = 0; + for (int i = 0; i < bat_num; i++) { + memset(buf, 0, sizeof(bat_base_dir) + 256 + 64); + pread(bat_arr[i].f_cap, buf, 64, 0); + cap = atoi(buf); + barsize = (ELEMENT_SIZE / bat_num) - 5 - strlen(buf); + level = (cap / 100.0) * barsize; + pread(bat_arr[i].f_stat, buf, 64, 0); + charging = strstr(buf, "Dis") ? 0 : 1; + + strcat(str, "["); + for (int i = 0; i < level; i++) + strcat(str, charging ? "+" : "="); + for (int i = 0; i < barsize - level; i++) + strcat(str, " "); + snprintf(buf, 64, "] %d%%", cap); + strcat(str, buf); + } + return str; +} + +void die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + fputs(ANSI_COLOR_RED, stderr); + vfprintf(stderr, fmt, ap); + + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + fputs(ANSI_COLOR_RESET, stderr); + + va_end(ap); + exit(errno ? errno : 1); +}