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