summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorauric <104602845+ihateamongus@users.noreply.github.com>2025-09-07 22:03:03 -0500
committerauric <104602845+ihateamongus@users.noreply.github.com>2025-09-07 22:03:03 -0500
commit3511421d9b79201e129ef2a110115b81c4216333 (patch)
tree8637dae4adb83fbdfce6e9de930a13736cb6a5d2
parent54ab8df8c1c37d45d55a32385f9dac3a5fb01932 (diff)
Keep status bar terminals open
-rw-r--r--dwm/config.h16
-rw-r--r--dwm/dwm.c204
2 files changed, 196 insertions, 24 deletions
diff --git a/dwm/config.h b/dwm/config.h
index c94f430..497dc66 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 sh -c 'cal -3 | less -+F'", NULL };
+static const char *dunstlogcmd[] = { "/bin/sh", "-c", "st -e sh -c 'less -+F \"$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} },
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 <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