[wiki] [sites] dwm patch: appicons || Rumen

From: <git_AT_suckless.org>
Date: Sat, 04 Jan 2025 23:25:59 +0100

commit 1e25ed0926c75fac9aee86243a93bb627f139022
Author: Rumen <rumenmitov_AT_protonmail.com>
Date: Sat Jan 4 23:25:02 2025 +0100

    dwm patch: appicons
    
    added patch to dwm's wiki. the patch allows for tag names to be
    dynamically replaced by icons

diff --git a/dwm.suckless.org/patches/appicons/dwm-appicons-6.5.diff b/dwm.suckless.org/patches/appicons/dwm-appicons-6.5.diff
new file mode 100644
index 00000000..fb970cd9
--- /dev/null
+++ b/dwm.suckless.org/patches/appicons/dwm-appicons-6.5.diff
_AT_@ -0,0 +1,240 @@
+From 5bd12261788064919c47ea35085bba6c9a1110ed Mon Sep 17 00:00:00 2001
+From: Rumen <rumenmitov_AT_protonmail.com>
+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
+_AT_@ -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..069ece9 100644
+--- a/dwm.c
++++ b/dwm.c
+_AT_@ -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;
+_AT_@ -138,6 +139,7 @@ typedef struct {
+ unsigned int tags;
+ int isfloating;
+ int monitor;
++ const char *appicon;
+ } Rule;
+
+ /* function declarations */
+_AT_@ -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 *c);
+ static void drawbar(Monitor *m);
+ static void drawbars(void);
+ static void enternotify(XEvent *e);
+_AT_@ -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 : 1;
++
+ /* rule matching */
++ c->appicon = NULL;
+ c->isfloating = 0;
+ c->tags = 0;
+ XGetClassHint(dpy, c->win, &ch);
+_AT_@ -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);
+_AT_@ -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)
+ {
+_AT_@ -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 ? 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, 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;
+ }
++
++ 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/patches/appicons/example.png
new file mode 100644
index 00000000..313864cd
Binary files /dev/null and b/dwm.suckless.org/patches/appicons/example.png differ
diff --git a/dwm.suckless.org/patches/appicons/index.md b/dwm.suckless.org/patches/appicons/index.md
new file mode 100644
index 00000000..a4e66314
--- /dev/null
+++ b/dwm.suckless.org/patches/appicons/index.md
_AT_@ -0,0 +1,38 @@
+appicons
+========
+
+![App Icons Screenshot](example.png)
+
+
+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 - <rumen.valmitov_AT_gmail.com>
+
+
+
+Inspiration
+-----------
+* [XMonad's DynamicIcons](https://hackage.haskell.org/package/xmonad-contrib-0.18.1/docs/XMonad-Hooks-DynamicIcons.html)
Received on Sat Jan 04 2025 - 23:25:59 CET

This archive was generated by hypermail 2.3.0 : Sat Jan 04 2025 - 23:36:53 CET