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