commit 7ecaabe2191759e776f4f27bac2a3a28613cdb74
parent b5ccbe35e39163f944b05cc0c9237ff188117b5e
Author: elbachir-one <bachiralfa@gmail.com>
Date: Thu, 18 Sep 2025 13:03:36 +0100
[dwm][patches][chargecolor] Added patch Charge Color
Diffstat:
2 files changed, 303 insertions(+), 0 deletions(-)
diff --git a/dwm.suckless.org/patches/chargecolor/dwm-chargecolor-20250918-2d2fd29.diff b/dwm.suckless.org/patches/chargecolor/dwm-chargecolor-20250918-2d2fd29.diff
@@ -0,0 +1,285 @@
+From 2d2fd29361c1e521fb74ef825d75135ad5da8482 Mon Sep 17 00:00:00 2001
+From: elbachir-one <bachiralfa@gmail.com>
+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 <errno.h>
+ #include <locale.h>
++#include <limits.h>
+ #include <signal.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <dirent.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
++#include <pthread.h>
+ #include <X11/cursorfont.h>
+ #include <X11/keysym.h>
+ #include <X11/Xatom.h>
+@@ -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
+
diff --git a/dwm.suckless.org/patches/chargecolor/index.md b/dwm.suckless.org/patches/chargecolor/index.md
@@ -0,0 +1,18 @@
+Charge Color
+============
+
+Description
+-----------
+The **Charge Color** patch for DWM dynamically switches between predefined
+color schemes depending on whether the system is running on AC power or
+battery. When you plug in or unplug the charger, DWM automatically updates the
+bar, borders, and focused window colors to reflect the current power state.
+
+Download
+--------
+* [dwm-chargecolor-20250727-51f68f6.diff](dwm-chargecolor-20250727-51f68f6.diff)
+
+Authors
+-------
+* Nahyan Siddiqui - <nahyanl63@gmail.com>
+* El Bachir - <bachiralfa@gmail.com>