From 2d2fd29361c1e521fb74ef825d75135ad5da8482 Mon Sep 17 00:00:00 2001 From: elbachir-one Date: Thu, 18 Sep 2025 12:32:15 +0100 Subject: [PATCH] Dynamically switches between predefined color schemes depending on whether the AC is plugged in or unplugged --- config.def.h | 19 ++++---- dwm.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 136 insertions(+), 16 deletions(-) diff --git a/config.def.h b/config.def.h index 3836510..8075450 100644 --- a/config.def.h +++ b/config.def.h @@ -6,18 +6,17 @@ static const unsigned int snap = 32; /* snap pixel */ static const int showbar = 1; /* 0 means no bar */ static const int topbar = 1; /* 0 means bottom bar */ static const char *fonts[] = { "monospace:size=10" }; -static const char dmenufont[] = "monospace:size=10"; -static const char col_gray1[] = "#222222"; -static const char col_gray2[] = "#444444"; -static const char col_gray3[] = "#bbbbbb"; -static const char col_gray4[] = "#eeeeee"; -static const char col_cyan[] = "#005577"; -static const char *colors[][3] = { + +char *colors[][3] = { /* fg bg border */ - [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, - [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + [SchemeNorm] = { "#ffffff", "#222222", "#444444" }, + [SchemeSel] = { "#ffffff", "#005577", "#005577" }, }; +static const char **current_theme = NULL; +static const char *blue[] = { "#ffffff", "#0E1C4A", "#3E54BD" }; +static const char *red[] = { "#ffffff", "#430B07", "#73493D" }; + /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; @@ -58,7 +57,7 @@ static const Layout layouts[] = { /* commands */ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ -static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL }; +static const char *dmenucmd[] = { "dmenu_run", NULL }; static const char *termcmd[] = { "st", NULL }; static const Key keys[] = { diff --git a/dwm.c b/dwm.c index 4cf07eb..87c3ae0 100644 --- a/dwm.c +++ b/dwm.c @@ -22,14 +22,17 @@ */ #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -175,6 +178,7 @@ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); static void incnmaster(const Arg *arg); +static int ischarging(void); static void keypress(XEvent *e); static void killclient(const Arg *arg); static void manage(Window w, XWindowAttributes *wa); @@ -215,6 +219,7 @@ static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); static void unmapnotify(XEvent *e); +static void updatecolors(void); static void updatebarpos(Monitor *m); static void updatebars(void); static void updateclientlist(void); @@ -240,6 +245,7 @@ static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh; /* bar height */ static int lrpad; /* sum of left and right padding for text */ +static int colorpipe[2]; /* pipe for notifying main thread about color changes */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; static void (*handler[LASTEvent]) (XEvent *) = { @@ -493,6 +499,8 @@ cleanup(void) XSync(dpy, False); XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + close(colorpipe[0]); + close(colorpipe[1]); } void @@ -983,6 +991,43 @@ incnmaster(const Arg *arg) arrange(selmon); } +int ischarging(void) { + const char *base = "/sys/class/power_supply/"; + DIR *dir = opendir(base); + if (!dir) return 0; + + struct dirent *entry; + char path[PATH_MAX]; + FILE *f; + int status = 0; + + while ((entry = readdir(dir))) { + if (entry->d_type != DT_DIR && entry->d_type != DT_LNK) + continue; + + snprintf(path, sizeof(path), "%s%s/type", base, entry->d_name); + f = fopen(path, "r"); + if (!f) continue; + + char type[32]; + if (fgets(type, sizeof(type), f)) { + if (strncmp(type, "Mains", 5) == 0) { + fclose(f); + snprintf(path, sizeof(path), "%s%s/online", base, entry->d_name); + f = fopen(path, "r"); + if (!f) break; + fscanf(f, "%d", &status); + fclose(f); + break; + } + } + fclose(f); + } + + closedir(dir); + return status; +} + #ifdef XINERAMA static int isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) @@ -1382,11 +1427,36 @@ void run(void) { XEvent ev; - /* main event loop */ - XSync(dpy, False); - while (running && !XNextEvent(dpy, &ev)) - if (handler[ev.type]) - handler[ev.type](&ev); /* call handler */ + int x11_fd = ConnectionNumber(dpy); + int maxfd = (colorpipe[0] > x11_fd) ? colorpipe[0] : x11_fd; + + fd_set rfds; + + while (running) { + FD_ZERO(&rfds); + FD_SET(x11_fd, &rfds); + FD_SET(colorpipe[0], &rfds); + + if (select(maxfd + 1, &rfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed"); + } + + if (FD_ISSET(colorpipe[0], &rfds)) { + char buf[1]; + read(colorpipe[0], buf, 1); /* clear pipe */ + updatecolors(); /* safe update in main thread */ + } + + if (FD_ISSET(x11_fd, &rfds)) { + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + if (handler[ev.type]) + handler[ev.type](&ev); + } + } + } } void @@ -1582,10 +1652,13 @@ setup(void) cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); cursor[CurResize] = drw_cur_create(drw, XC_sizing); cursor[CurMove] = drw_cur_create(drw, XC_fleur); + if (pipe(colorpipe) == -1) { + die("Failed to create pipe"); + } /* init appearance */ scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) - scheme[i] = drw_scm_create(drw, colors[i], 3); + scheme[i] = drw_scm_create(drw, (const char **)colors[i], 3); /* init bars */ updatebars(); updatestatus(); @@ -1711,6 +1784,21 @@ tile(Monitor *m) } } +void * +themechecker(void *arg) { + int last_status = -1; + for (;;) { + int charging = ischarging(); + if (charging != last_status) { + current_theme = charging ? blue : red; + updatecolors(); + last_status = charging; + } + usleep(1000000); + } + return NULL; +} + void togglebar(const Arg *arg) { @@ -1814,6 +1902,34 @@ unmapnotify(XEvent *e) } } +void +updatecolors(void) { + colors[SchemeNorm][0] = (char *)current_theme[0]; + colors[SchemeNorm][1] = (char *)current_theme[1]; + colors[SchemeNorm][2] = (char *)current_theme[1]; + + colors[SchemeSel][0] = (char *)current_theme[0]; + colors[SchemeSel][1] = (char *)current_theme[2]; + colors[SchemeSel][2] = (char *)current_theme[2]; + + for (int i = 0; i < LENGTH(colors); i++) { + if (scheme[i]) + free(scheme[i]); + scheme[i] = drw_scm_create(drw, (const char **)colors[i], 3); + } + + for (Monitor *m = mons; m; m = m->next) { + drawbar(m); + arrange(m); + + /* Update borders of all clients on this monitor */ + for (Client *c = m->clients; c; c = c->next) { + XSetWindowBorder(dpy, c->win, + scheme[c == m->sel ? SchemeSel : SchemeNorm][2].pixel); + } + } +} + void updatebars(void) { @@ -2152,12 +2268,17 @@ main(int argc, char *argv[]) die("dwm: cannot open display"); checkotherwm(); setup(); + + pthread_t theme_thread; + pthread_create(&theme_thread, NULL, themechecker, NULL); + #ifdef __OpenBSD__ if (pledge("stdio rpath proc exec", NULL) == -1) die("pledge"); #endif /* __OpenBSD__ */ scan(); run(); + pthread_join(theme_thread, NULL); cleanup(); XCloseDisplay(dpy); return EXIT_SUCCESS; -- 2.50.1