Changes to dwm mmnametags patch - sites - public wiki contents of suckless.org
HTML git clone git://git.suckless.org/sites
DIR Log
DIR Files
DIR Refs
---
DIR commit 8350820566a1bd3129e1fdb8fc115a3a2d2e6161
DIR parent 962561aa3fc9a8b0fb6c40df8e1e0b82a25013cb
HTML Author: A-Larsen <austin.larsen@mailfence.com>
Date: Thu, 18 Dec 2025 00:48:59 -0500
Changes to dwm mmnametags patch
Better memory management for tagnames in createmon function
Diffstat:
A dwm.suckless.org/patches/mmnametag… | 155 +++++++++++++++++++++++++++++++
A dwm.suckless.org/patches/mmnametag… | 157 +++++++++++++++++++++++++++++++
M dwm.suckless.org/patches/mmnametag… | 11 ++++++++---
3 files changed, 320 insertions(+), 3 deletions(-)
---
DIR diff --git a/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-20251218-7c3abae.diff b/dwm.suckless.org/patches/mmnametags/dwm-mmnametags-20251218-7c3abae.diff
@@ -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
+@@ -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):
+@@ -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
+@@ -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]))
+@@ -129,6 +130,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ char **tags;
+ };
+
+ typedef struct {
+@@ -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);
+@@ -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;
+@@ -499,6 +502,7 @@ void
+ cleanupmon(Monitor *mon)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ if (mon == mons)
+ mons = mons->next;
+@@ -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);
+ }
+
+@@ -633,6 +641,7 @@ Monitor *
+ createmon(void)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+@@ -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;
+ }
+
+@@ -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,
+@@ -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\n", errno ? ": " : "", errno ? strerror(errno) : "");
++ return;
++ }
++ if (!(p = fgets(name, MAX_TAGLEN, f)) && (i = errno) && ferror(f))
++ fprintf(stderr, "dwm: fgets failed: %s\n", strerror(i));
++ if (pclose(f) < 0)
++ fprintf(stderr, "dwm: pclose failed: %s\n", strerror(errno));
++ if(!p)
++ return;
++ if((p = strchr(name, '\n')))
++ *p = '\0';
++
++ for(i = 0; i < LENGTH(tags); i++)
++ if(selmon->tagset[selmon->seltags] & (1 << i)) {
++ strcpy(selmon->tags[i], name);
++ }
++ drawbars();
++}
++
+ Client *
+ nexttiled(Client *c)
+ {
DIR 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
@@ -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
+@@ -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):
+@@ -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
+@@ -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]))
+@@ -129,6 +130,7 @@ struct Monitor {
+ Monitor *next;
+ Window barwin;
+ const Layout *lt[2];
++ char **tags;
+ };
+
+ typedef struct {
+@@ -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);
+@@ -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;
+@@ -499,6 +502,7 @@ void
+ cleanupmon(Monitor *mon)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ if (mon == mons)
+ mons = mons->next;
+@@ -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);
+ }
+
+@@ -633,6 +641,7 @@ Monitor *
+ createmon(void)
+ {
+ Monitor *m;
++ unsigned int i;
+
+ m = ecalloc(1, sizeof(Monitor));
+ m->tagset[0] = m->tagset[1] = 1;
+@@ -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;
+ }
+
+@@ -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,
+@@ -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\n", errno ? ": " : "", errno ? strerror(errno) : "");
++ return;
++ }
++ if (!(p = fgets(name, MAX_TAGLEN, f)) && (i = errno) && ferror(f))
++ fprintf(stderr, "dwm: fgets failed: %s\n", strerror(i));
++ if (pclose(f) < 0)
++ fprintf(stderr, "dwm: pclose failed: %s\n", strerror(errno));
++ if(!p)
++ return;
++ if((p = strchr(name, '\n')))
++ *p = '\0';
++
++ 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)
+ {
DIR diff --git a/dwm.suckless.org/patches/mmnametags/index.md b/dwm.suckless.org/patches/mmnametags/index.md
@@ -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)