#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; } #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); }