dwm-appicons-6.5.diff - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
dwm-appicons-6.5.diff (8715B) | |
--- | |
1 From dbae98a1cf614908ff0075c5f4a3d4ad619f0519 Mon Sep 17 00:00:00 2001 | |
2 From: Rumen <[email protected]> | |
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 na… | |
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", "… | |
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… | |
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 … | |
34 - { "Gimp", NULL, NULL, 0, 1, … | |
35 - { "Firefox", NULL, NULL, 1 << 8, 0, … | |
36 + /* class instance title tags mask isfloating … | |
37 + { "Gimp", NULL, NULL, 0, 1, … | |
38 + { "Firefox", NULL, NULL, 1 << 8, 0, … | |
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_… | |
76 +static void applyappicon(char *tag_icons[], int *icons_per_tag, const 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_af… | |
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… | |
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) + … | |
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 << … | |
266 - drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 … | |
267 - if (occ & 1 << i) | |
268 + drw_text(drw, x, 0, w, bh, lrpad / 2, m->tag_icons[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->s… | |
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 |