[wiki] [sites] Changes to dwm mmnametags patch || A-Larsen

From: <git_AT_suckless.org>
Date: Thu, 18 Dec 2025 06:51:36 +0100

commit 8350820566a1bd3129e1fdb8fc115a3a2d2e6161
Author: A-Larsen <austin.larsen_AT_mailfence.com>
Date: Thu Dec 18 00:48:59 2025 -0500

    Changes to dwm mmnametags patch
    
    Better memory management for tagnames in createmon function

diff --git a/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-20251218-7c3abae.diff b/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-20251218-7c3abae.diff
new file mode 100644
index 00000000..685ed1f3
--- /dev/null
+++ b/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-20251218-7c3abae.diff
_AT_@ -0,0 +1,155 @@
+diff --git a/config.def.h b/config.def.h
+index 81c3fc0..28daa84 100644
+--- a/config.def.h
++++ b/config.def.h
+_AT_@ -19,7 +19,8 @@ static const char *colors[][3] = {
+ };
+
+ /* tagging */
+-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
++#define MAX_TAGLEN 16 /* altogether */
++static char tags[][MAX_TAGLEN] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ static const Rule rules[] = {
+ /* xprop(1):
+_AT_@ -86,6 +87,7 @@ static const Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY, XK_n, nametag, {0} },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+diff --git a/dwm.c b/dwm.c
+index 4f345ee..1a014be 100644
+--- a/dwm.c
++++ b/dwm.c
+_AT_@ -47,6 +47,7 @@
+ /* macros */
+ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
++#define SETDMENUMON(m) m[0] = '0' + selmon->num
+ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+ #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+_AT_@ -129,6 +130,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ char **tags;
+ };
+
+ typedef struct {
+_AT_@ -183,6 +185,7 @@ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
++static void nametag(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *c);
+ static void propertynotify(XEvent *e);
+_AT_@ -433,7 +436,7 @@ buttonpress(XEvent *e)
+ if (ev->window == selmon->barwin) {
+ i = x = 0;
+ do
+- x += TEXTW(tags[i]);
++ x += TEXTW(m->tags[i]);
+ while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+_AT_@ -499,6 +502,7 @@ void
+ cleanupmon(Monitor *mon)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ if (mon == mons)
+ mons = mons->next;
+_AT_@ -508,6 +512,10 @@ cleanupmon(Monitor *mon)
+ }
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
++ for (i = 0; i <= LENGTH(tags); i++) {
++ free(mon->tags[i]);
++ }
++ free(mon->tags);
+ free(mon);
+ }
+
+_AT_@ -633,6 +641,7 @@ Monitor *
+ createmon(void)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+_AT_@ -643,6 +652,16 @@ createmon(void)
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
++
++ m->tags = ecalloc(LENGTH(tags), sizeof(char) * (MAX_TAGLEN + 1));
++
++ for (i = 0; i <= LENGTH(tags); i++) {
++ m->tags[i] = ecalloc(1, sizeof(char) * (MAX_TAGLEN + 1));
++ memset(m->tags[i], 0, MAX_TAGLEN);
++ unsigned char slen = strlen(tags[i]);
++ unsigned char len = slen >= MAX_TAGLEN ? MAX_TAGLEN : slen;
++ memcpy(m->tags[i], tags[i], sizeof(char) * len);
++ }
+ return m;
+ }
+
+_AT_@ -720,9 +739,9 @@ drawbar(Monitor *m)
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+- w = TEXTW(tags[i]);
++ w = TEXTW(m->tags[i]);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, m->tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+_AT_@ -1201,6 +1220,39 @@ movemouse(const Arg *arg)
+ }
+ }
+
++void
++nametag(const Arg *arg) {
++ char *p, name[MAX_TAGLEN];
++ FILE *f;
++ int i;
++ char dmenumon[2];
++ char cmd[25];
++
++ SETDMENUMON(dmenumon);
++ memset(cmd, 0, 25);
++ sprintf(cmd, "dmenu -m %s < /dev/null", dmenumon);
++ errno = 0; // popen(3p) says on failure it "may" set errno
++
++ if(!(f = popen(cmd, "r"))) {
++ fprintf(stderr, "dwm: popen 'dmenu < /dev/null' failed%s%s
", errno ? ": " : "", errno ? strerror(errno) : "");
++ return;
++ }
++ if (!(p = fgets(name, MAX_TAGLEN, f)) && (i = errno) && ferror(f))
++ fprintf(stderr, "dwm: fgets failed: %s
", strerror(i));
++ if (pclose(f) < 0)
++ fprintf(stderr, "dwm: pclose failed: %s
", strerror(errno));
++ if(!p)
++ return;
++ if((p = strchr(name, '
')))
++ *p = '++
++ for(i = 0; i < LENGTH(tags); i++)
++ if(selmon->tagset[selmon->seltags] & (1 << i)) {
++ strcpy(selmon->tags[i], name);
++ }
++ drawbars();
++}
++
+ Client *
+ nexttiled(Client *c)
+ {
diff --git a/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-prepend-20251218-7c3abae.diff b/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-prepend-20251218-7c3abae.diff
new file mode 100644
index 00000000..e1b96a45
--- /dev/null
+++ b/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-prepend-20251218-7c3abae.diff
_AT_@ -0,0 +1,157 @@
+diff --git a/config.def.h b/config.def.h
+index 81c3fc0..7492c0f 100644
+--- a/config.def.h
++++ b/config.def.h
+_AT_@ -19,7 +19,9 @@ static const char *colors[][3] = {
+ };
+
+ /* tagging */
+-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
++#define MAX_TAGLEN 16 /* altogether */
++#define TAG_PREPEND "%1i:" /* formatted as 2 chars */
++static char tags[][MAX_TAGLEN] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ static const Rule rules[] = {
+ /* xprop(1):
+_AT_@ -86,6 +88,7 @@ static const Key keys[] = {
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
++ { MODKEY, XK_n, nametag, {0} },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+diff --git a/dwm.c b/dwm.c
+index 4f345ee..3c33b17 100644
+--- a/dwm.c
++++ b/dwm.c
+_AT_@ -47,6 +47,7 @@
+ /* macros */
+ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+ #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
++#define SETDMENUMON(m) m[0] = '0' + selmon->num
+ #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+ #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+_AT_@ -129,6 +130,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ char **tags;
+ };
+
+ typedef struct {
+_AT_@ -183,6 +185,7 @@ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+ static void motionnotify(XEvent *e);
+ static void movemouse(const Arg *arg);
++static void nametag(const Arg *arg);
+ static Client *nexttiled(Client *c);
+ static void pop(Client *c);
+ static void propertynotify(XEvent *e);
+_AT_@ -433,7 +436,7 @@ buttonpress(XEvent *e)
+ if (ev->window == selmon->barwin) {
+ i = x = 0;
+ do
+- x += TEXTW(tags[i]);
++ x += TEXTW(m->tags[i]);
+ while (ev->x >= x && ++i < LENGTH(tags));
+ if (i < LENGTH(tags)) {
+ click = ClkTagBar;
+_AT_@ -499,6 +502,7 @@ void
+ cleanupmon(Monitor *mon)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ if (mon == mons)
+ mons = mons->next;
+_AT_@ -508,6 +512,10 @@ cleanupmon(Monitor *mon)
+ }
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
++ for (i = 0; i <= LENGTH(tags); i++) {
++ free(mon->tags[i]);
++ }
++ free(mon->tags);
+ free(mon);
+ }
+
+_AT_@ -633,6 +641,7 @@ Monitor *
+ createmon(void)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+_AT_@ -643,6 +652,16 @@ createmon(void)
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
++
++ m->tags = ecalloc(LENGTH(tags), sizeof(char) * (MAX_TAGLEN + 1));
++
++ for (i = 0; i <= LENGTH(tags); i++) {
++ m->tags[i] = ecalloc(1, sizeof(char) * (MAX_TAGLEN + 1));
++ memset(m->tags[i], 0, MAX_TAGLEN);
++ unsigned char slen = strlen(tags[i]);
++ unsigned char len = slen >= MAX_TAGLEN ? MAX_TAGLEN : slen;
++ memcpy(m->tags[i], tags[i], sizeof(char) * len);
++ }
+ return m;
+ }
+
+_AT_@ -720,9 +739,9 @@ drawbar(Monitor *m)
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+- w = TEXTW(tags[i]);
++ w = TEXTW(m->tags[i]);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, m->tags[i], urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+_AT_@ -1201,6 +1220,40 @@ movemouse(const Arg *arg)
+ }
+ }
+
++void
++nametag(const Arg *arg) {
++ char *p, name[MAX_TAGLEN];
++ FILE *f;
++ int i;
++ char dmenumon[2];
++ char cmd[25];
++
++ SETDMENUMON(dmenumon);
++ memset(cmd, 0, 25);
++ sprintf(cmd, "dmenu -m %s < /dev/null", dmenumon);
++ errno = 0; // popen(3p) says on failure it "may" set errno
++
++ if(!(f = popen(cmd, "r"))) {
++ fprintf(stderr, "dwm: popen 'dmenu < /dev/null' failed%s%s
", errno ? ": " : "", errno ? strerror(errno) : "");
++ return;
++ }
++ if (!(p = fgets(name, MAX_TAGLEN, f)) && (i = errno) && ferror(f))
++ fprintf(stderr, "dwm: fgets failed: %s
", strerror(i));
++ if (pclose(f) < 0)
++ fprintf(stderr, "dwm: pclose failed: %s
", strerror(errno));
++ if(!p)
++ return;
++ if((p = strchr(name, '
')))
++ *p = '++
++ for(i = 0; i < LENGTH(tags); i++)
++ if(selmon->tagset[selmon->seltags] & (1 << i)) {
++ sprintf(selmon->tags[i], TAG_PREPEND, i+1);
++ strcat(selmon->tags[i], name);
++ }
++ drawbars();
++}
++
+ Client *
+ nexttiled(Client *c)
+ {
diff --git a/dwm.suckless.org/patches/mmnametags/index.md b/dwm.suckless.org/patches/mmnametags/index.md
index a439cf43..21089970 100644
--- a/dwm.suckless.org/patches/mmnametags/index.md
+++ b/dwm.suckless.org/patches/mmnametags/index.md
_AT_@ -3,12 +3,17 @@ mmnametags
 
 Description
 -----------
-This patch builds upon the [nametag](https://dwm.suckless.org/patches/nametag/) patch,
-but allows each monitor to have its own unique set of nametags. You don’t need
-to install the original nametag patch beforehand.
+This patch builds upon the [nametag](https://dwm.suckless.org/patches/nametag/)
+patch, but allows each monitor to have its own unique set of nametags. You don’t
+need to install the original nametag patch beforehand.
+
+The latest update fixes memory management issues, it has the shorthash of
+7c3abae. It is recommended to use this version.
 
 Download
 --------
+* [dwm-mmnametags-20251218-7c3abae.diff](dwm-mmnametags-20251218-7c3abae.diff)
+* [dwm-mmnametags-prepend-20251218-7c3abae.diff](dwm-mmnametags-prepend-20251218-7c3abae.diff)
 * [dwm-mmnametags-6.6.diff](dwm-mmnametags-6.6.diff)
 * [dwm-mmnametags-prepend-6.6.diff](dwm-mmnametags-prepend-6.6.diff)
 
Received on Thu Dec 18 2025 - 06:51:36 CET

This archive was generated by hypermail 2.3.0 : Thu Dec 18 2025 - 07:00:45 CET