diff options
| author | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-07 21:54:48 -0500 |
|---|---|---|
| committer | auric <104602845+ihateamongus@users.noreply.github.com> | 2025-09-07 21:54:48 -0500 |
| commit | 15a27bdd175b678b5ddbb34d8f5ed587388c590c (patch) | |
| tree | 55d338bd83a449c163acb0a7c23a2dc34ca8c1d0 | |
| parent | 54ab8df8c1c37d45d55a32385f9dac3a5fb01932 (diff) | |
Integrate built-in status bar
| -rw-r--r-- | dwm/config.h | 16 | ||||
| -rw-r--r-- | dwm/dwm.c | 204 |
2 files changed, 196 insertions, 24 deletions
diff --git a/dwm/config.h b/dwm/config.h index c94f430..f24f70b 100644 --- a/dwm/config.h +++ b/dwm/config.h @@ -71,6 +71,9 @@ static const char *screenshotcmd[] = { "flameshot", "gui", NULL }; static const char *mediaplaypause[] = { "playerctl", "play-pause", NULL }; static const char *medianext[] = { "playerctl", "next", NULL }; static const char *mediaprev[] = { "playerctl", "previous", NULL }; +static const char *calendarcmd[] = { "/bin/sh", "-c", "st -e cal -3", NULL }; +static const char *dunstlogcmd[] = { "/bin/sh", "-c", "st -e less \"$HOME/.cache/dunst/dunst.log\"", NULL }; +static const char *powermenucmd[] = { "/bin/sh", "-c", "printf 'lock\\nreboot\\nshutdown' | dmenu | xargs -r -I{} sh -c 'case \"{}\" in lock) slock ;; reboot) loginctl reboot ;; shutdown) loginctl poweroff ;; esac'", NULL }; static const Key keys[] = { /* modifier key function argument */ @@ -123,12 +126,13 @@ static const Key keys[] = { static const Button buttons[] = { /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, - { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, - { ClkWinTitle, 0, Button2, zoom, {0} }, - { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, - { ClkClientWin, MODKEY, Button1, movemouse, {0} }, - { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, - { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, +{ ClkWinTitle, 0, Button2, zoom, {0} }, +{ ClkStatusText, 0, Button1, clickstatus, {0} }, +{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, +{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, +{ ClkClientWin, MODKEY, Button2, togglefloating, {0} }, +{ ClkClientWin, MODKEY, Button3, resizemouse, {0} }, { ClkTagBar, 0, Button1, view, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, @@ -35,6 +35,8 @@ #include <sys/stat.h> #include <fcntl.h> #include <sys/select.h> +#include <time.h> +#include <limits.h> #include <X11/cursorfont.h> #include <X11/keysym.h> #include <X11/Xatom.h> @@ -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 |
