sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | 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