From 0d4dafcd35e5b7ceb42fd98891f5aa9838ab84a5 Mon Sep 17 00:00:00 2001 From: Octavian Cerna Date: Tue, 30 Dec 2014 21:59:05 +0200 Subject: Initial revision. --- statusbar.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 statusbar.c diff --git a/statusbar.c b/statusbar.c new file mode 100644 index 0000000..42406a0 --- /dev/null +++ b/statusbar.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include +#include + +#define INTERVAL 2 + +#ifdef TTY +#define NORMAL "" +#define SELECTED "" +#define WARNING "" +#define ERROR "" +#define DELIM "" +#define HOT "" +#define MEDIUM "" +#define COOL "" +#else +#define NORMAL "\x01" +#define SELECTED "\x02" +#define WARNING "\x03" +#define ERROR "\x04" +#define DELIM "\x05" +#define HOT "\x06" +#define MEDIUM "\x07" +#define COOL "\x08" +#endif + +static Display *dpy; +static char statusline[2048]; + + +static void set_status(const char *str) +{ + XStoreName(dpy, DefaultRootWindow(dpy), str); + XSync(dpy, False); +} + +static void reset_status(void) +{ + statusline[0] = '\0'; +} + +static void add_status(const char *fmt, ...) +{ + va_list ap; + size_t len; + + va_start(ap, fmt); + if (statusline[0]) { + len = strlen(statusline); + snprintf(statusline + len, sizeof(statusline) - len, DELIM " | " NORMAL); + } + len = strlen(statusline); + vsnprintf(statusline + len, sizeof(statusline) - len, fmt, ap); + va_end(ap); +} + + +static int parse_file(const char *file, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + int ret = 0; + + if ((fp = fopen(file, "r")) != NULL) { + va_start(ap, fmt); + ret = vfscanf(fp, fmt, ap); + va_end(ap); + fclose(fp); + } + + return ret; +} + + +static void status_cpu(void) +{ + FILE *fp; + char line[256]; + char *tok; + unsigned long long ticks = 0, idle = 0; + static unsigned long long prev_ticks, prev_idle; + int i; + double usage = 0, freq = 0, temp = 0; + + if ((fp = fopen("/proc/stat", "r")) == NULL) + return; + + fgets(line, sizeof(line), fp); + fclose(fp); + + tok = strtok(line, " "); + if (strcmp(tok, "cpu") != 0) + return; + + for (i = 0; (tok = strtok(NULL, " ")) != NULL; i++) { + unsigned long long value = strtoull(tok, NULL, 10); + if (i == 3) + idle = value; + ticks += value; + } + + usage = 100.0 - ((idle - prev_idle) * 100.0 / (ticks - prev_ticks)); + prev_ticks = ticks; + prev_idle = idle; + + parse_file("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "%lf", &freq); + parse_file("/sys/devices/virtual/thermal/thermal_zone0/temp", "%lf", &temp); + + freq /= 1e6; + temp /= 1000; + + add_status("CPU %s%3.f%s%% @ %.1fGHz %s%.f%s\xc2\xb0", + usage >= 90 ? HOT : usage >= 80 ? MEDIUM : COOL, + usage, + NORMAL, + freq, + temp >= 98 ? ERROR : temp >= 85 ? HOT : temp >= 75 ? MEDIUM : COOL, + temp, + NORMAL); +} + + +static void status_mem(void) +{ + FILE *fp; + char line[256], field[128]; + unsigned long long value, total = 0, free = 0, cached = 0; + double used; + + if ((fp = fopen("/proc/meminfo", "r")) == NULL) { + return; + } + while (fgets(line, sizeof(line), fp)) { + if (sscanf(line, "%s %Lu", field, &value)) { + if (strcmp(field, "MemTotal:") == 0) + total = value; + else if (strcmp(field, "MemFree:") == 0) + free = value; + else if (strcmp(field, "Cached:") == 0) + cached = value; + } + } + fclose(fp); + + used = (total - free - cached) * 100.0 / total; + add_status("Mem %s%2.f%s%%", used > 90.0 ? HOT : COOL, used, NORMAL); +} + + +static void status_net(void) +{ + FILE *fp; + char line[256], iface[128], tmp[128], net[128], path[256]; + unsigned long long rx_bytes = 0, tx_bytes = 0; + static unsigned long long prev_rx_bytes = 0, prev_tx_bytes = 0; + double up = 0, down = 0; + char upstr[128], downstr[128]; + + if ((fp = fopen("/proc/net/route", "r")) == NULL) + return; + + strcpy(iface, "eth0"); + fgets(line, sizeof(line), fp); + while (fgets(line, sizeof(line), fp)) { + if (sscanf(line, "%s %s", tmp, net) && strcmp(net, "00000000") == 0) { + strcpy(iface, tmp); + break; + } + } + fclose(fp); + + snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/rx_bytes", iface); + parse_file(path, "%llu", &rx_bytes); + snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/tx_bytes", iface); + parse_file(path, "%llu", &tx_bytes); + + if (prev_rx_bytes > 0 || prev_tx_bytes > 0) { + up = tx_bytes > prev_tx_bytes ? (tx_bytes - prev_tx_bytes) * 8 / INTERVAL : 0; + down = rx_bytes > prev_rx_bytes ? (rx_bytes - prev_rx_bytes) * 8 / INTERVAL : 0; + } + prev_rx_bytes = rx_bytes; + prev_tx_bytes = tx_bytes; + + if (up >= 1e6) { + snprintf(upstr, sizeof(upstr), "%s%4.1f%sM", COOL, up / 1e6, NORMAL); + } else { + snprintf(upstr, sizeof(upstr), "%s%4.f%sk", COOL, up / 1000, NORMAL); + } + if (down >= 1e6) { + snprintf(downstr, sizeof(downstr), "%s%4.1f%sM", COOL, down / 1e6, NORMAL); + } else { + snprintf(downstr, sizeof(downstr), "%s%4.f%sk", COOL, down / 1000, NORMAL); + } + +// add_status("%s \xe2\x86\x91%s / \xe2\x86\x93%s", iface, upstr, downstr); + add_status("%s %s / %s", iface, upstr, downstr); +} + + +static void status_bat(void) +{ + char status[128]; + const char *ind = ""; + int online = 0; + double charge; + + if (parse_file("/sys/class/power_supply/BAT0/status", "%s", status)) { + parse_file("/sys/class/power_supply/BAT0/capacity", "%lf", &charge); + parse_file("/sys/class/power_supply/AC0/online", "%u", &online); + + if (!online && strcmp(status, "Discharging") == 0) + ind = "<"; + else if (strcmp(status, "Charging") == 0) + ind = ">"; + + if (online && charge > 99.9) { + // add_status("AC"); + } else { + add_status("Bat %s%s%.f%s%%", charge <= 5.0 ? ERROR : charge <= 10.0 ? HOT : COOL, ind, charge, NORMAL); + } + } +} + + +static void status_wifi(void) +{ +} + + +static void status_date(void) +{ + char date[128]; + time_t t; + struct tm tm; + + time(&t); + strftime(date, sizeof(date), "%a, %b %d %H:%M", localtime_r(&t, &tm)); + + add_status("%s", date); +} + + +int main() +{ +#ifndef TTY + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "statusbar: cannot open display.\n"); + return 1; + } +#endif + + for (;;) { + reset_status(); + + status_cpu(); + status_mem(); + status_net(); + status_bat(); + status_wifi(); + status_date(); + +#ifdef TTY + printf("%s\n", statusline); +#else + set_status(statusline); +#endif + sleep(INTERVAL); + } +} -- cgit v1.2.3