dwm patch: appicons - sites - public wiki contents of suckless.org | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
commit 1e25ed0926c75fac9aee86243a93bb627f139022 | |
parent 885eccfb082883973d02fe3962d89251ea11aff7 | |
Author: Rumen <[email protected]> | |
Date: Sat, 4 Jan 2025 23:25:02 +0100 | |
dwm patch: appicons | |
added patch to dwm's wiki. the patch allows for tag names to be | |
dynamically replaced by icons | |
Diffstat: | |
A dwm.suckless.org/patches/appicons/… | 240 +++++++++++++++++++++++++++… | |
A dwm.suckless.org/patches/appicons/… | 0 | |
A dwm.suckless.org/patches/appicons/… | 38 +++++++++++++++++++++++++++… | |
3 files changed, 278 insertions(+), 0 deletions(-) | |
--- | |
diff --git a/dwm.suckless.org/patches/appicons/dwm-appicons-6.5.diff b/dwm.suck… | |
@@ -0,0 +1,240 @@ | |
+From 5bd12261788064919c47ea35085bba6c9a1110ed Mon Sep 17 00:00:00 2001 | |
+From: Rumen <[email protected]> | |
+Date: Sat, 4 Jan 2025 22:28:14 +0100 | |
+Subject: [PATCH] appicons patch: | |
+ | |
+clients can now be assigned icons based on rules set by the user. | |
+these icons will be displayed insteas of the tag indicator and tag name. | |
+--- | |
+ config.def.h | 14 ++++-- | |
+ dwm.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++-- | |
+ 2 files changed, 136 insertions(+), 6 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 m… | |
++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 moni… | |
+- { "Gimp", NULL, NULL, 0, 1, -1 }, | |
+- { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, | |
++ /* class instance title tags mask isfloating moni… | |
++ { "Gimp", NULL, NULL, 0, 1, -1, … | |
++ { "Firefox", NULL, NULL, 1 << 8, 0, -1, … | |
+ }; | |
+ | |
+ /* layout(s) */ | |
+diff --git a/dwm.c b/dwm.c | |
+index 1443802..069ece9 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; | |
+@@ -138,6 +139,7 @@ typedef struct { | |
+ unsigned int tags; | |
+ int isfloating; | |
+ int monitor; | |
++ const char *appicon; | |
+ } Rule; | |
+ | |
+ /* function declarations */ | |
+@@ -160,6 +162,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 … | |
+ static void drawbar(Monitor *m); | |
+ static void drawbars(void); | |
+ static void enternotify(XEvent *e); | |
+@@ -283,7 +288,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 : … | |
++ | |
+ /* rule matching */ | |
++ c->appicon = NULL; | |
+ c->isfloating = 0; | |
+ c->tags = 0; | |
+ XGetClassHint(dpy, c->win, &ch); | |
+@@ -296,6 +307,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… | |
+@@ -694,6 +707,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); | |
++ | |
++ 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)); | |
++ | |
++ 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) | |
++ strncpy(tag_icons[i], c->appicon, strlen(c->appicon) + 1); | |
++ | |
++ 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 +816,41 @@ drawbar(Monitor *m) | |
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); | |
+ } | |
+ | |
++ char *tag_icons[LENGTH(tags)]; | |
++ 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 */ | |
++ 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(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(tag_icons[i]); | |
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? Sc… | |
+- 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, tag_icons[i], urg & 1 <… | |
++ if (occ & 1 << i && icons_per_tag[i] == 0) | |
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, | |
+ m == selmon && selmon->sel && selmon->sel->ta… | |
+ urg & 1 << i); | |
+ x += w; | |
+ } | |
++ | |
++ for (int i = 0; i < LENGTH(tags); i++) { | |
++ free(tag_icons[i]); | |
++ tag_icons[i] = NULL; | |
++ } | |
++ | |
+ w = TEXTW(m->ltsymbol); | |
+ drw_setscheme(drw, scheme[SchemeNorm]); | |
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | |
+-- | |
+2.47.1 | |
+ | |
diff --git a/dwm.suckless.org/patches/appicons/example.png b/dwm.suckless.org/p… | |
Binary files differ. | |
diff --git a/dwm.suckless.org/patches/appicons/index.md b/dwm.suckless.org/patc… | |
@@ -0,0 +1,38 @@ | |
+appicons | |
+======== | |
+ | |
+ | |
+ | |
+ | |
+Description | |
+----------- | |
+Adds support for app icons which can be used instead of the tag indicator | |
+and tag name. This is configurable through an extra option in `rules`. | |
+ | |
+Icons should work out of the box. Emojis require a special font like | |
+[Noto Color Emoji](https://fonts.google.com/noto/specimen/Noto+Color+Emoji). | |
+ | |
+When one or more app icons are present in a tag, the tag name will be | |
+encapsulated with the outer separators (`outer_separator_beg` and | |
+`outer_separator_end`). Additionally, the icons of the tag will be | |
+separated between themselves by `inner_separator`. | |
+ | |
+Each tag can have a maximum of `truncate_icons_after` icons. | |
+After which the `truncate_symbol` will be displayed. | |
+ | |
+ | |
+Download | |
+-------- | |
+* [dwm-appicons-6.5.diff](dwm-appicons-6.5.diff) (2025-01-04) | |
+ | |
+ | |
+ | |
+Author | |
+------ | |
+* Rumen Mitov - <[email protected]> | |
+ | |
+ | |
+ | |
+Inspiration | |
+----------- | |
+* [XMonad's DynamicIcons](https://hackage.haskell.org/package/xmonad-contrib-… |