summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--statusbar.c273
1 files changed, 273 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <X11/Xlib.h>
+
+#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);
+ }
+}