You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.1 KiB
175 lines
4.1 KiB
#define _POSIX_C_SOURCE 200809L
|
|
#define _DEFAULT_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <X11/Xlib.h>
|
|
|
|
#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;
|
|
}
|
|
|
|
#if defined( __linux__ )
|
|
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;
|
|
}
|
|
#elif defined( __OpenBSD__ )
|
|
static const char * get_battery (void) {
|
|
return "not supported";
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
|