#include #include #include #include #include #include #include #include #include #define ELEMENT_SEPERATOR " " #define STATUS_STRBUF_SZ 512 #define ELEMENT_STRBUF_SZ 64 typedef void (*element_function)(char*); struct element { const element_function f; const struct timeval fire_interval; struct timeval fire_previous; char buf[ELEMENT_STRBUF_SZ]; }; void date(char* buf) { time_t now = time(NULL); struct tm tm; localtime_r(&now, &tm); strftime(buf, ELEMENT_STRBUF_SZ, "%F %R", &tm); } enum battery_status_charge { bat_unknown, bat_not_charging, bat_charging, bat_discharging }; struct battery_status { enum battery_status_charge status; float charge; }; struct battery_status get_battery_status(const char* buf) { const char path_prefix[] = "/sys/class/power_supply/"; char charge_path[128]; char capacity_path[128]; memset(charge_path, 0, 128); memset(capacity_path, 0, 128); int charge = 0; int capacity = 0; char charge_str[512]; char capacity_str[512]; strcat(charge_path, path_prefix); strcat(charge_path, buf); strcat(charge_path, "/energy_now"); strcat(capacity_path, path_prefix); strcat(capacity_path, buf); strcat(capacity_path, "/energy_full"); FILE* bat_charge = fopen(charge_path, "r"); FILE* bat_capacity = fopen(capacity_path, "r"); if (!bat_charge) { printf("%d: \"%s\" %s\n", errno, charge_path, strerror(errno)); return (struct battery_status){.status = bat_unknown, .charge = -1}; } if (!bat_capacity) { printf("%d: \"%s\" %s\n", errno, capacity_path, strerror(errno)); return (struct battery_status){.status = bat_unknown, .charge = -1}; } fread(charge_str, sizeof(char), 512, bat_charge); fread(capacity_str, sizeof(char), 512, bat_capacity); fclose(bat_charge); fclose(bat_capacity); charge = atoi(charge_str); capacity = atoi(capacity_str); return (struct battery_status){.status = bat_unknown, .charge = (float)charge / capacity}; } void get_battery0_status(char* buf) { struct battery_status s = get_battery_status("BAT0"); snprintf(buf, ELEMENT_STRBUF_SZ, "\uf581 %.1f%%", 100.f * s.charge); } static struct element statusbar[] = { {get_battery0_status, {5,0}, 0}, {date, {1,500000}, 0}, }; int main() { const int num_elems = sizeof(statusbar)/sizeof(statusbar[0]); struct timeval now; const struct timeval one_minute = {.tv_sec = 60, .tv_usec = 0}; while (true) { gettimeofday(&now, NULL); // Stall updating for at most 1 minute struct timeval next_update; timeradd(&now, &one_minute, &next_update); for (unsigned i = 0; i < num_elems; i++) { struct timeval next_fire; timeradd(&statusbar[i].fire_previous, &statusbar[i].fire_interval, &next_fire); if (timercmp(&next_fire, &now, >)) { // Check if this is the next to-be-updated element if (timercmp(&next_fire, &next_update, <)) { next_update = next_fire; } continue; } memset(statusbar[i].buf, 0, ELEMENT_STRBUF_SZ); statusbar[i].f(statusbar[i].buf); statusbar[i].fire_previous = now; // Check if this element needs to be refreshed next, again timeradd(&statusbar[i].fire_previous, &statusbar[i].fire_interval, &next_fire); if (timercmp(&next_fire, &next_update, <)) { next_update = next_fire; } printf("[%ld.%ld] %s\n", statusbar[i].fire_interval.tv_sec, statusbar[i].fire_interval.tv_usec, (char*)statusbar[i].buf); } unsigned c = 0; char buf[STATUS_STRBUF_SZ]; memset(buf, 0, STATUS_STRBUF_SZ); for (unsigned i = 0; i < num_elems; i++) { strcat(buf, statusbar[i].buf); if (i != num_elems - 1) strcat(buf, ELEMENT_SEPERATOR); } strcat(buf, "%"); puts(buf); timersub(&next_update, &now, &next_update); usleep(next_update.tv_sec*1000*1000+next_update.tv_usec); } return 0; }