From 15a27bdd175b678b5ddbb34d8f5ed587388c590c Mon Sep 17 00:00:00 2001 From: auric <104602845+ihateamongus@users.noreply.github.com> Date: Sun, 7 Sep 2025 21:54:48 -0500 Subject: Integrate built-in status bar --- dwm/dwm.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 186 insertions(+), 18 deletions(-) (limited to 'dwm/dwm.c') diff --git a/dwm/dwm.c b/dwm/dwm.c index 7a95f93..4adbf21 100644 --- a/dwm/dwm.c +++ b/dwm/dwm.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -244,6 +246,11 @@ static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +static void clickstatus(const Arg *arg); +static void getcpu(char *buf, size_t len); +static void getram(char *buf, size_t len); +static void gettime(char *buf, size_t len); +static void getdunst(char *buf, size_t len); /* variables */ static const char broken[] = "broken"; @@ -279,6 +286,18 @@ static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; +enum { SNoti, SCPU, SRAM, STime, SPower, StatusLast }; + +typedef struct { + char text[64]; + int width; +} StatusItem; + +static StatusItem statusitems[StatusLast]; +static int statusw; +static unsigned long long lasttotal, lastidle; +static time_t laststatus; + /* configuration, allows nested code to access above variables */ #include "config.h" #ifndef BAROPACITY @@ -463,10 +482,18 @@ buttonpress(XEvent *e) arg.ui = 1 << i; } else if (ev->x < x + TEXTW(selmon->ltsymbol)) click = ClkLtSymbol; - else if (ev->x > selmon->ww - (int)TEXTW(stext)) - click = ClkStatusText; - else - click = ClkWinTitle; + else if (ev->x > selmon->ww - statusw) { + click = ClkStatusText; + x = selmon->ww - ev->x; + for (i = StatusLast; i-- > 0; ) { + if (x < statusitems[i].width) { + arg.i = i; + break; + } + x -= statusitems[i].width; + } + } else + click = ClkWinTitle; } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -746,12 +773,22 @@ drawbar(Monitor *m) if (!m->showbar) return; - /* draw status first so it can be overdrawn by tags later */ - if (m == selmon) { /* status is only drawn on selected monitor */ - drw_setscheme(drw, scheme[SchemeNorm]); - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); - } + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + updatestatus(); + drw_setscheme(drw, scheme[SchemeNorm]); + tw = 0; + for (i = StatusLast; i-- > 0; ) { + if (!statusitems[i].text[0]) + continue; + w = TEXTW(statusitems[i].text); + statusitems[i].width = w; + drw_text(drw, m->ww - tw - w, 0, w, bh, 0, + statusitems[i].text, 0); + tw += w; + } + statusw = tw; + } for (c = m->clients; c; c = c->next) { occ |= c->tags; @@ -1275,11 +1312,9 @@ propertynotify(XEvent *e) Window trans; XPropertyEvent *ev = &e->xproperty; - if ((ev->window == root) && (ev->atom == XA_WM_NAME)) - updatestatus(); - else if (ev->state == PropertyDelete) - return; /* ignore */ - else if ((c = wintoclient(ev->window))) { + if (ev->state == PropertyDelete) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { switch(ev->atom) { default: break; case XA_WM_TRANSIENT_FOR: @@ -2111,12 +2146,145 @@ updatesizehints(Client *c) c->hintsvalid = 1; } +static void +getcpu(char *buf, size_t len) +{ + unsigned long long user, nice, system, idle, iowait, irq, softirq, steal; + FILE *fp = fopen("/proc/stat", "r"); + if (!fp) { + snprintf(buf, len, "CPU ?"); + return; + } + if (fscanf(fp, "cpu %llu %llu %llu %llu %llu %llu %llu %llu", + &user, &nice, &system, &idle, &iowait, &irq, &softirq, + &steal) != 8) { + fclose(fp); + snprintf(buf, len, "CPU ?"); + return; + } + fclose(fp); + unsigned long long idleall = idle + iowait; + unsigned long long nonidle = user + nice + system + irq + softirq + steal; + unsigned long long total = idleall + nonidle; + unsigned long long totald = total - lasttotal; + unsigned long long idled = idleall - lastidle; + lasttotal = total; + lastidle = idleall; + int usage = totald ? (int)((totald - idled) * 100 / totald) : 0; + snprintf(buf, len, "CPU %d%%", usage); +} + +static void +getram(char *buf, size_t len) +{ + FILE *fp = fopen("/proc/meminfo", "r"); + if (!fp) { + snprintf(buf, len, "RAM ?"); + return; + } + unsigned long total = 0, avail = 0; + char line[256]; + while (fgets(line, sizeof line, fp)) { + if (sscanf(line, "MemTotal: %lu kB", &total) == 1) + continue; + if (sscanf(line, "MemAvailable: %lu kB", &avail) == 1) + break; + } + fclose(fp); + if (!total) { + snprintf(buf, len, "RAM ?"); + return; + } + unsigned long used = total - avail; + int percent = (int)(used * 100 / total); + snprintf(buf, len, "RAM %d%%", percent); +} + +static void +gettime(char *buf, size_t len) +{ + time_t now = time(NULL); + struct tm *tm = localtime(&now); + if (!tm) { + buf[0] = '\0'; + return; + } + strftime(buf, len, "%F %R", tm); +} + +static void +getdunst(char *buf, size_t len) +{ + const char *home = getenv("HOME"); + if (!home) { + buf[0] = '\0'; + return; + } + char path[PATH_MAX]; + snprintf(path, sizeof path, "%s/.cache/dunst/dunst.log", home); + FILE *fp = fopen(path, "r"); + if (!fp) { + buf[0] = '\0'; + return; + } + if (fseek(fp, 0, SEEK_END) < 0) { + fclose(fp); + buf[0] = '\0'; + return; + } + long pos = ftell(fp); + long start = pos > 512 ? pos - 512 : 0; + fseek(fp, start, SEEK_SET); + char line[512]; + while (fgets(line, sizeof line, fp)) + ; + fclose(fp); + line[strcspn(line, "\n")] = '\0'; + snprintf(buf, len, "%s", line); +} + void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) - strcpy(stext, "dwm-"VERSION); - drawbar(selmon); + time_t now = time(NULL); + if (now == laststatus) + return; + laststatus = now; + + getdunst(statusitems[SNoti].text, sizeof statusitems[SNoti].text); + getcpu(statusitems[SCPU].text, sizeof statusitems[SCPU].text); + getram(statusitems[SRAM].text, sizeof statusitems[SRAM].text); + gettime(statusitems[STime].text, sizeof statusitems[STime].text); + strncpy(statusitems[SPower].text, "⏻", sizeof statusitems[SPower].text); + + /* build combined status string for width fallback */ + stext[0] = '\0'; + for (int i = 0; i < StatusLast; i++) { + if (!statusitems[i].text[0]) + continue; + size_t l = strlen(stext); + snprintf(stext + l, sizeof stext - l, "%s%s", + l ? " " : "", statusitems[i].text); + } + +} + +static void +clickstatus(const Arg *arg) +{ + switch (arg->i) { + case SNoti: + spawn(&(Arg){ .v = dunstlogcmd }); + break; + case STime: + spawn(&(Arg){ .v = calendarcmd }); + break; + case SPower: + spawn(&(Arg){ .v = powermenucmd }); + break; + default: + break; + } } void -- cgit v1.2.3