dwm-appicons-20250601-c05f117.diff - sites - public wiki contents of suckless.org
(HTM) git clone git://git.suckless.org/sites
(DIR) Log
(DIR) Files
(DIR) Refs
---
dwm-appicons-20250601-c05f117.diff (8751B)
---
1 From c0fcc16b38f41a0ae7638c5ed5718f5aa9747913 Mon Sep 17 00:00:00 2001
2 From: Rumen <rumenmitov@protonmail.com>
3 Date: Sun, 1 Jun 2025 12:23:04 +0200
4 Subject: [PATCH] fix: segfault when rendering icons
5
6 fixed a segfault due to a double free when copying appicons between
7 strings
8 ---
9 config.def.h | 14 ++++--
10 dwm.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++--
11 2 files changed, 147 insertions(+), 7 deletions(-)
12
13 diff --git a/config.def.h b/config.def.h
14 index 9efa774..3045af6 100644
15 --- a/config.def.h
16 +++ b/config.def.h
17 @@ -21,14 +21,22 @@ static const char *colors[][3] = {
18 /* tagging */
19 static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
20
21 +/* appicons */
22 +/* NOTE: set to 0 to set to default (whitespace) */
23 +static char outer_separator_beg = '[';
24 +static char outer_separator_end = ']';
25 +static char inner_separator = ' ';
26 +static unsigned truncate_icons_after = 2; /* will default to 1, that is the min */
27 +static char truncate_symbol[] = "...";
28 +
29 static const Rule rules[] = {
30 /* xprop(1):
31 * WM_CLASS(STRING) = instance, class
32 * WM_NAME(STRING) = title
33 */
34 - /* class instance title tags mask isfloating monitor */
35 - { "Gimp", NULL, NULL, 0, 1, -1 },
36 - { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
37 + /* class instance title tags mask isfloating monitor appicon*/
38 + { "Gimp", NULL, NULL, 0, 1, -1, NULL },
39 + { "Firefox", NULL, NULL, 1 << 8, 0, -1, "" },
40 };
41
42 /* layout(s) */
43 diff --git a/dwm.c b/dwm.c
44 index 1443802..4fe7a6d 100644
45 --- a/dwm.c
46 +++ b/dwm.c
47 @@ -85,6 +85,7 @@ typedef struct Monitor Monitor;
48 typedef struct Client Client;
49 struct Client {
50 char name[256];
51 + char *appicon;
52 float mina, maxa;
53 int x, y, w, h;
54 int oldx, oldy, oldw, oldh;
55 @@ -121,6 +122,7 @@ struct Monitor {
56 unsigned int seltags;
57 unsigned int sellt;
58 unsigned int tagset[2];
59 + char **tag_icons;
60 int showbar;
61 int topbar;
62 Client *clients;
63 @@ -138,6 +140,7 @@ typedef struct {
64 unsigned int tags;
65 int isfloating;
66 int monitor;
67 + const char *appicon;
68 } Rule;
69
70 /* function declarations */
71 @@ -160,6 +163,9 @@ static void destroynotify(XEvent *e);
72 static void detach(Client *c);
73 static void detachstack(Client *c);
74 static Monitor *dirtomon(int dir);
75 +static void remove_outer_separators(char **str);
76 +static void appiconsappend(char **str, const char *appicon, size_t new_size);
77 +static void applyappicon(char *tag_icons[], int *icons_per_tag, const Client *c);
78 static void drawbar(Monitor *m);
79 static void drawbars(void);
80 static void enternotify(XEvent *e);
81 @@ -283,7 +289,13 @@ applyrules(Client *c)
82 Monitor *m;
83 XClassHint ch = { NULL, NULL };
84
85 + outer_separator_beg = outer_separator_beg ? outer_separator_beg : ' ';
86 + outer_separator_end = outer_separator_end ? outer_separator_end : ' ';
87 + inner_separator = inner_separator ? inner_separator : ' ';
88 + truncate_icons_after = truncate_icons_after > 0 ? truncate_icons_after : 1;
89 +
90 /* rule matching */
91 + c->appicon = NULL;
92 c->isfloating = 0;
93 c->tags = 0;
94 XGetClassHint(dpy, c->win, &ch);
95 @@ -296,6 +308,8 @@ applyrules(Client *c)
96 && (!r->class || strstr(class, r->class))
97 && (!r->instance || strstr(instance, r->instance)))
98 {
99 + /* r->appicon is static, so lifetime is sufficient */
100 + c->appicon = (char*) r->appicon;
101 c->isfloating = r->isfloating;
102 c->tags |= r->tags;
103 for (m = mons; m && m->num != r->monitor; m = m->next);
104 @@ -433,7 +447,7 @@ buttonpress(XEvent *e)
105 if (ev->window == selmon->barwin) {
106 i = x = 0;
107 do
108 - x += TEXTW(tags[i]);
109 + x += TEXTW(m->tag_icons[i]);
110 while (ev->x >= x && ++i < LENGTH(tags));
111 if (i < LENGTH(tags)) {
112 click = ClkTagBar;
113 @@ -508,6 +522,14 @@ cleanupmon(Monitor *mon)
114 }
115 XUnmapWindow(dpy, mon->barwin);
116 XDestroyWindow(dpy, mon->barwin);
117 +
118 + for (int i = 0; i < LENGTH(tags); i++) {
119 + if (mon->tag_icons[i]) free(mon->tag_icons[i]);
120 + mon->tag_icons[i] = NULL;
121 + }
122 +
123 + if (mon->tag_icons) free(mon->tag_icons);
124 +
125 free(mon);
126 }
127
128 @@ -643,6 +665,13 @@ createmon(void)
129 m->lt[0] = &layouts[0];
130 m->lt[1] = &layouts[1 % LENGTH(layouts)];
131 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
132 +
133 + m->tag_icons = (char**) malloc(LENGTH(tags) * sizeof(char*));
134 + if (m->tag_icons == NULL) perror("dwm: malloc()");
135 + for (int i = 0; i < LENGTH(tags); i++) {
136 + m->tag_icons[i] = NULL;
137 + }
138 +
139 return m;
140 }
141
142 @@ -694,6 +723,96 @@ dirtomon(int dir)
143 return m;
144 }
145
146 +void
147 +remove_outer_separators(char **str)
148 +{
149 + size_t clean_tag_name_len = strlen(*str) - 2;
150 +
151 + char *temp_tag_name = (char*)
152 + malloc(clean_tag_name_len + 1);
153 +
154 + if (temp_tag_name == NULL) perror("dwm: malloc()");
155 +
156 + memset(temp_tag_name, 0, clean_tag_name_len + 1);
157 +
158 + char *clean_tag_name_beg = *str + 1;
159 + strncpy(temp_tag_name,
160 + clean_tag_name_beg,
161 + clean_tag_name_len);
162 +
163 + if (*str) free(*str);
164 + *str = temp_tag_name;
165 +}
166 +
167 +void
168 +appiconsappend(char **str, const char *appicon, size_t new_size)
169 +{
170 + char *temp_tag_name = (char*) malloc(new_size);
171 + if (temp_tag_name == NULL) perror("dwm: malloc()");
172 +
173 + /* NOTE: Example format of temp_tag_name (with two appicons):
174 + * <outer_sep_beg><appicon><inner_sep><appicon><outer_sep_end>
175 + */
176 + temp_tag_name = memset(temp_tag_name, 0, new_size);
177 +
178 + temp_tag_name[0] = outer_separator_beg;
179 + temp_tag_name[new_size - 2] = outer_separator_end;
180 +
181 + strncpy(temp_tag_name + 1, *str, strlen(*str));
182 + temp_tag_name[strlen(temp_tag_name)] = inner_separator;
183 +
184 + strncpy(temp_tag_name + strlen(temp_tag_name),
185 + appicon, strlen(appicon));
186 +
187 + if (*str) free(*str);
188 + *str = temp_tag_name;
189 +}
190 +
191 +void
192 +applyappicon(char *tag_icons[], int *icons_per_tag, const Client *c)
193 +{
194 + for (unsigned t = 1, i = 0;
195 + i < LENGTH(tags);
196 + t <<= 1, i++)
197 + {
198 + if (c->tags & t) {
199 + if (icons_per_tag[i] == 0) {
200 + if (tag_icons[i]) free(tag_icons[i]);
201 + tag_icons[i] = strndup(c->appicon, strlen(c->appicon));
202 + } else {
203 + char *icon = NULL;
204 + if (icons_per_tag[i] < truncate_icons_after)
205 + icon = c->appicon;
206 + else if (icons_per_tag[i] == truncate_icons_after)
207 + icon = truncate_symbol;
208 + else {
209 + icons_per_tag[i]++;
210 + continue;
211 + }
212 +
213 + /* remove outer separators from previous iterations
214 + * otherwise they get applied recursively */
215 + if (icons_per_tag[i] > 1) {
216 + remove_outer_separators(&tag_icons[i]);
217 + }
218 +
219 + size_t outer_separators_size = 2;
220 + size_t inner_separator_size = 1;
221 +
222 + size_t new_size = strlen(tag_icons[i])
223 + + outer_separators_size
224 + + inner_separator_size
225 + + strlen(icon)
226 + + 1;
227 +
228 + appiconsappend(&tag_icons[i], icon, new_size);
229 + }
230 +
231 + icons_per_tag[i]++;
232 + }
233 + }
234 +}
235 +
236 void
237 drawbar(Monitor *m)
238 {
239 @@ -713,22 +832,35 @@ drawbar(Monitor *m)
240 drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
241 }
242
243 + int icons_per_tag[LENGTH(tags)];
244 + memset(icons_per_tag, 0, LENGTH(tags) * sizeof(int));
245 +
246 + for (int i = 0; i < LENGTH(tags); i++) {
247 + /* set each tag to default value */
248 + m->tag_icons[i] = strndup(tags[i], strlen(tags[i]));
249 + }
250 +
251 for (c = m->clients; c; c = c->next) {
252 + if (c->appicon && strlen(c->appicon) > 0) {
253 + applyappicon(m->tag_icons, icons_per_tag, c);
254 + }
255 +
256 occ |= c->tags;
257 if (c->isurgent)
258 urg |= c->tags;
259 }
260 x = 0;
261 for (i = 0; i < LENGTH(tags); i++) {
262 - w = TEXTW(tags[i]);
263 + w = TEXTW(m->tag_icons[i]);
264 drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
265 - drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
266 - if (occ & 1 << i)
267 + drw_text(drw, x, 0, w, bh, lrpad / 2, m->tag_icons[i], urg & 1 << i);
268 + if (occ & 1 << i && icons_per_tag[i] == 0)
269 drw_rect(drw, x + boxs, boxs, boxw, boxw,
270 m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
271 urg & 1 << i);
272 x += w;
273 }
274 +
275 w = TEXTW(m->ltsymbol);
276 drw_setscheme(drw, scheme[SchemeNorm]);
277 x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
278 --
279 2.49.0
280