sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 53a3bc9dec3cca309fb4a77d068e4281dcb15a61
parent 8242cafbdac3078762d860c0b75d439bf3331cff
Author: Rumen <rumenmitov@protonmail.com>
Date:   Sun,  1 Jun 2025 14:33:49 +0200

fix dwm-appicons

fixed segfault in dwm-appicons due to a double free

Diffstat:
Adwm.suckless.org/patches/appicons/dwm-appicons-20250601-c05f117.diff | 280+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdwm.suckless.org/patches/appicons/index.md | 3++-
2 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/dwm.suckless.org/patches/appicons/dwm-appicons-20250601-c05f117.diff b/dwm.suckless.org/patches/appicons/dwm-appicons-20250601-c05f117.diff @@ -0,0 +1,280 @@ +From c0fcc16b38f41a0ae7638c5ed5718f5aa9747913 Mon Sep 17 00:00:00 2001 +From: Rumen <rumenmitov@protonmail.com> +Date: Sun, 1 Jun 2025 12:23:04 +0200 +Subject: [PATCH] fix: segfault when rendering icons + +fixed a segfault due to a double free when copying appicons between +strings +--- + config.def.h | 14 ++++-- + dwm.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 147 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 9efa774..3045af6 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -21,14 +21,22 @@ static const char *colors[][3] = { + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* appicons */ ++/* NOTE: set to 0 to set to default (whitespace) */ ++static char outer_separator_beg = '['; ++static char outer_separator_end = ']'; ++static char inner_separator = ' '; ++static unsigned truncate_icons_after = 2; /* will default to 1, that is the min */ ++static char truncate_symbol[] = "..."; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ +- /* class instance title tags mask isfloating monitor */ +- { "Gimp", NULL, NULL, 0, 1, -1 }, +- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, ++ /* class instance title tags mask isfloating monitor appicon*/ ++ { "Gimp", NULL, NULL, 0, 1, -1, NULL }, ++ { "Firefox", NULL, NULL, 1 << 8, 0, -1, "󰈹" }, + }; + + /* layout(s) */ +diff --git a/dwm.c b/dwm.c +index 1443802..4fe7a6d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -85,6 +85,7 @@ typedef struct Monitor Monitor; + typedef struct Client Client; + struct Client { + char name[256]; ++ char *appicon; + float mina, maxa; + int x, y, w, h; + int oldx, oldy, oldw, oldh; +@@ -121,6 +122,7 @@ struct Monitor { + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; ++ char **tag_icons; + int showbar; + int topbar; + Client *clients; +@@ -138,6 +140,7 @@ typedef struct { + unsigned int tags; + int isfloating; + int monitor; ++ const char *appicon; + } Rule; + + /* function declarations */ +@@ -160,6 +163,9 @@ static void destroynotify(XEvent *e); + static void detach(Client *c); + static void detachstack(Client *c); + static Monitor *dirtomon(int dir); ++static void remove_outer_separators(char **str); ++static void appiconsappend(char **str, const char *appicon, size_t new_size); ++static void applyappicon(char *tag_icons[], int *icons_per_tag, const Client *c); + static void drawbar(Monitor *m); + static void drawbars(void); + static void enternotify(XEvent *e); +@@ -283,7 +289,13 @@ applyrules(Client *c) + Monitor *m; + XClassHint ch = { NULL, NULL }; + ++ outer_separator_beg = outer_separator_beg ? outer_separator_beg : ' '; ++ outer_separator_end = outer_separator_end ? outer_separator_end : ' '; ++ inner_separator = inner_separator ? inner_separator : ' '; ++ truncate_icons_after = truncate_icons_after > 0 ? truncate_icons_after : 1; ++ + /* rule matching */ ++ c->appicon = NULL; + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); +@@ -296,6 +308,8 @@ applyrules(Client *c) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { ++ /* r->appicon is static, so lifetime is sufficient */ ++ c->appicon = (char*) r->appicon; + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); +@@ -433,7 +447,7 @@ buttonpress(XEvent *e) + if (ev->window == selmon->barwin) { + i = x = 0; + do +- x += TEXTW(tags[i]); ++ x += TEXTW(m->tag_icons[i]); + while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; +@@ -508,6 +522,14 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ ++ for (int i = 0; i < LENGTH(tags); i++) { ++ if (mon->tag_icons[i]) free(mon->tag_icons[i]); ++ mon->tag_icons[i] = NULL; ++ } ++ ++ if (mon->tag_icons) free(mon->tag_icons); ++ + free(mon); + } + +@@ -643,6 +665,13 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ ++ m->tag_icons = (char**) malloc(LENGTH(tags) * sizeof(char*)); ++ if (m->tag_icons == NULL) perror("dwm: malloc()"); ++ for (int i = 0; i < LENGTH(tags); i++) { ++ m->tag_icons[i] = NULL; ++ } ++ + return m; + } + +@@ -694,6 +723,96 @@ dirtomon(int dir) + return m; + } + ++void ++remove_outer_separators(char **str) ++{ ++ size_t clean_tag_name_len = strlen(*str) - 2; ++ ++ char *temp_tag_name = (char*) ++ malloc(clean_tag_name_len + 1); ++ ++ if (temp_tag_name == NULL) perror("dwm: malloc()"); ++ ++ memset(temp_tag_name, 0, clean_tag_name_len + 1); ++ ++ char *clean_tag_name_beg = *str + 1; ++ strncpy(temp_tag_name, ++ clean_tag_name_beg, ++ clean_tag_name_len); ++ ++ if (*str) free(*str); ++ *str = temp_tag_name; ++} ++ ++void ++appiconsappend(char **str, const char *appicon, size_t new_size) ++{ ++ char *temp_tag_name = (char*) malloc(new_size); ++ if (temp_tag_name == NULL) perror("dwm: malloc()"); ++ ++ /* NOTE: Example format of temp_tag_name (with two appicons): ++ * <outer_sep_beg><appicon><inner_sep><appicon><outer_sep_end> ++ */ ++ temp_tag_name = memset(temp_tag_name, 0, new_size); ++ ++ temp_tag_name[0] = outer_separator_beg; ++ temp_tag_name[new_size - 2] = outer_separator_end; ++ ++ strncpy(temp_tag_name + 1, *str, strlen(*str)); ++ temp_tag_name[strlen(temp_tag_name)] = inner_separator; ++ ++ strncpy(temp_tag_name + strlen(temp_tag_name), ++ appicon, strlen(appicon)); ++ ++ if (*str) free(*str); ++ *str = temp_tag_name; ++} ++ ++void ++applyappicon(char *tag_icons[], int *icons_per_tag, const Client *c) ++{ ++ for (unsigned t = 1, i = 0; ++ i < LENGTH(tags); ++ t <<= 1, i++) ++ { ++ if (c->tags & t) { ++ if (icons_per_tag[i] == 0) { ++ if (tag_icons[i]) free(tag_icons[i]); ++ tag_icons[i] = strndup(c->appicon, strlen(c->appicon)); ++ } else { ++ char *icon = NULL; ++ if (icons_per_tag[i] < truncate_icons_after) ++ icon = c->appicon; ++ else if (icons_per_tag[i] == truncate_icons_after) ++ icon = truncate_symbol; ++ else { ++ icons_per_tag[i]++; ++ continue; ++ } ++ ++ /* remove outer separators from previous iterations ++ * otherwise they get applied recursively */ ++ if (icons_per_tag[i] > 1) { ++ remove_outer_separators(&tag_icons[i]); ++ } ++ ++ size_t outer_separators_size = 2; ++ size_t inner_separator_size = 1; ++ ++ size_t new_size = strlen(tag_icons[i]) ++ + outer_separators_size ++ + inner_separator_size ++ + strlen(icon) ++ + 1; ++ ++ appiconsappend(&tag_icons[i], icon, new_size); ++ } ++ ++ icons_per_tag[i]++; ++ } ++ } ++} ++ + void + drawbar(Monitor *m) + { +@@ -713,22 +832,35 @@ drawbar(Monitor *m) + drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); + } + ++ int icons_per_tag[LENGTH(tags)]; ++ memset(icons_per_tag, 0, LENGTH(tags) * sizeof(int)); ++ ++ for (int i = 0; i < LENGTH(tags); i++) { ++ /* set each tag to default value */ ++ m->tag_icons[i] = strndup(tags[i], strlen(tags[i])); ++ } ++ + for (c = m->clients; c; c = c->next) { ++ if (c->appicon && strlen(c->appicon) > 0) { ++ applyappicon(m->tag_icons, icons_per_tag, c); ++ } ++ + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { +- w = TEXTW(tags[i]); ++ w = TEXTW(m->tag_icons[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); +- if (occ & 1 << i) ++ drw_text(drw, x, 0, w, bh, lrpad / 2, m->tag_icons[i], urg & 1 << i); ++ if (occ & 1 << i && icons_per_tag[i] == 0) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } ++ + w = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); +-- +2.49.0 + diff --git a/dwm.suckless.org/patches/appicons/index.md b/dwm.suckless.org/patches/appicons/index.md @@ -22,7 +22,8 @@ Each tag can display a maximum of `truncate_icons_after` icons, after which the Download -------- -* [dwm-appicons-6.5.diff](dwm-appicons-6.5.diff) (2025-01-04) +* [dwm-appicons-6.5.diff](dwm-appicons-6.5.diff) (2025-01-04), *deprecated* +* [dwm-appicons-20250601-c05f117.diff](dwm-appicons-20250601-c05f117.diff) (2025-06-01) Author ------