From 2e3edb3febae67c7325d1a1846934335403a62f4 Mon Sep 17 00:00:00 2001 From: bakkeby Date: Fri, 4 Dec 2020 12:32:40 +0100 Subject: [PATCH 1/2] tagicons patch Refer to: https://github.com/bakkeby/patches/wiki/tagicons --- config.def.h | 13 +++++-- dwm.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 12 deletions(-) diff --git a/config.def.h b/config.def.h index 1c0b587..d82e4df 100644 --- a/config.def.h +++ b/config.def.h @@ -18,8 +18,13 @@ static const char *colors[][3] = { [SchemeSel] = { col_gray4, col_cyan, col_cyan }, }; -/* tagging */ -static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; +/* tagging: refer to https://github.com/bakkeby/patches/wiki/tagicons */ +static const char *tags[NUMTAGS] = { NULL }; /* left for compatibility reasons, i.e. code that checks LENGTH(tags) */ +static char *tagicons[][NUMTAGS] = { + [IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, + [IconsVacant] = { NULL }, + [IconsOccupied] = { NULL }, +}; static const Rule rules[] = { /* xprop(1): @@ -84,6 +89,8 @@ static Key keys[] = { { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, +// { MODKEY|ShiftMask, XK_a, seticonset, {.i = 0 } }, +// { MODKEY|ShiftMask, XK_b, seticonset, {.i = 1 } }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) @@ -111,5 +118,7 @@ static Button buttons[] = { { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkTagBar, 0, Button4, cycleiconset, {.i = +1 } }, + { ClkTagBar, 0, Button5, cycleiconset, {.i = -1 } }, }; diff --git a/dwm.c b/dwm.c index 4465af1..614a9ef 100644 --- a/dwm.c +++ b/dwm.c @@ -45,6 +45,7 @@ #include "util.h" /* macros */ +#define NUMTAGS 9 /* the number of tags per monitor */ #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ @@ -54,7 +55,7 @@ #define MOUSEMASK (BUTTONMASK|PointerMotionMask) #define WIDTH(X) ((X)->w + 2 * (X)->bw) #define HEIGHT(X) ((X)->h + 2 * (X)->bw) -#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGMASK ((1 << NUMTAGS) - 1) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) /* enums */ @@ -66,6 +67,12 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +enum { + IconsDefault, + IconsVacant, + IconsOccupied, + IconsLast +}; /* icon sets */ typedef union { int i; @@ -124,6 +131,7 @@ struct Monitor { unsigned int tagset[2]; int showbar; int topbar; + int iconset; Client *clients; Client *sel; Client *stack; @@ -157,6 +165,7 @@ static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); static Monitor *createmon(void); +static void cycleiconset(const Arg *arg); static void destroynotify(XEvent *e); static void detach(Client *c); static void detachstack(Client *c); @@ -169,6 +178,7 @@ static void focus(Client *c); static void focusin(XEvent *e); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); +static char * geticon(Monitor *m, int tag, int iconset); static int getrootptr(int *x, int *y); static long getstate(Window w); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); @@ -199,6 +209,7 @@ static void sendmon(Client *c, Monitor *m); static void setclientstate(Client *c, long state); static void setfocus(Client *c); static void setfullscreen(Client *c, int fullscreen); +static void seticonset(const Arg *arg); static void setlayout(const Arg *arg); static void setmfact(const Arg *arg); static void setup(void); @@ -207,6 +218,7 @@ static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); static void tag(const Arg *arg); +static char * tagicon(Monitor *m, int tag); static void tagmon(const Arg *arg); static void tile(Monitor *); static void togglebar(const Arg *arg); @@ -272,7 +284,7 @@ static Window root, wmcheckwin; #include "config.h" /* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; +struct NumTags { char limitexceeded[NUMTAGS > 31 ? -1 : 1]; }; /* function implementations */ void @@ -416,7 +428,7 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; + unsigned int i, x, tw, click; Arg arg = {0}; Client *c; Monitor *m; @@ -431,10 +443,13 @@ buttonpress(XEvent *e) } if (ev->window == selmon->barwin) { i = x = 0; - do - x += TEXTW(tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); - if (i < LENGTH(tags)) { + do { + tw = TEXTW(tagicon(selmon, i)); + if (tw <= lrpad) + continue; + x += tw; + } while (ev->x >= x && ++i < NUMTAGS); + if (i < NUMTAGS) { click = ClkTagBar; arg.ui = 1 << i; } else if (ev->x < x + blw) @@ -644,6 +659,24 @@ createmon(void) return m; } +void +cycleiconset(const Arg *arg) +{ + Monitor *m = selmon; + if (arg->i == 0) + return; + if (arg->i > 0) { + for (++m->iconset; m->iconset < IconsLast && tagicons[m->iconset][0] == NULL; ++m->iconset); + if (m->iconset >= IconsLast) + m->iconset = 0; + } else if (arg->i < 0) { + for (--m->iconset; m->iconset > 0 && tagicons[m->iconset][0] == NULL; --m->iconset); + if (m->iconset < 0) + for (m->iconset = IconsLast - 1; m->iconset > 0 && tagicons[m->iconset][0] == NULL; --m->iconset); + } + drawbar(m); +} + void destroynotify(XEvent *e) { @@ -699,6 +732,7 @@ drawbar(Monitor *m) int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; + char *icon; Client *c; /* draw status first so it can be overdrawn by tags later */ @@ -714,10 +748,13 @@ drawbar(Monitor *m) urg |= c->tags; } x = 0; - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); + for (i = 0; i < NUMTAGS; i++) { + icon = tagicon(m, i); + w = TEXTW(icon); + if (w <= lrpad) + continue; 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); + drw_text(drw, x, 0, w, bh, lrpad / 2, icon, urg & 1 << i); if (occ & 1 << i) drw_rect(drw, x + boxs, boxs, boxw, boxw, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, @@ -871,6 +908,20 @@ getatomprop(Client *c, Atom prop) return atom; } +char * +geticon(Monitor *m, int tag, int iconset) +{ + int i; + int tagindex = tag + NUMTAGS * m->num; + for (i = 0; i < LENGTH(tagicons[iconset]) && tagicons[iconset][i] != NULL; ++i); + if (i == 0) + tagindex = 0; + else if (tagindex >= i) + tagindex = tagindex % i; + + return tagicons[iconset][tagindex]; +} + int getrootptr(int *x, int *y) { @@ -1497,6 +1548,15 @@ setfullscreen(Client *c, int fullscreen) } } +void +seticonset(const Arg *arg) +{ + if (arg->i >= 0 && arg->i < IconsLast) { + selmon->iconset = arg->i; + drawbar(selmon); + } +} + void setlayout(const Arg *arg) { @@ -1662,6 +1722,24 @@ tag(const Arg *arg) } } +char * +tagicon(Monitor *m, int tag) +{ + Client *c; + char *icon; + for (c = m->clients; c && (!(c->tags & 1 << tag)); c = c->next); + // for (c = m->clients; c && (!(c->tags & 1 << tag) || HIDDEN(c)); c = c->next); // awesomebar / wintitleactions compatibility + if (c && tagicons[IconsOccupied][0] != NULL) + icon = geticon(m, tag, IconsOccupied); + else { + icon = geticon(m, tag, m->iconset); + if (TEXTW(icon) <= lrpad && m->tagset[m->seltags] & 1 << tag) + icon = geticon(m, tag, IconsVacant); + } + + return icon; +} + void tagmon(const Arg *arg) { -- 2.19.1 From 4c57bc449e5e5ad4d1abde2776bef35c588f023f Mon Sep 17 00:00:00 2001 From: bakkeby Date: Fri, 19 Feb 2021 09:53:46 +0100 Subject: [PATCH 2/2] tagicons with separate icon for selected tags Example patch ref. https://www.reddit.com/r/suckless/comments/ln0t41/use_icon_instead_of_rectangle_as/ --- config.def.h | 5 +++-- dwm.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index d82e4df..7607155 100644 --- a/config.def.h +++ b/config.def.h @@ -21,9 +21,10 @@ static const char *colors[][3] = { /* tagging: refer to https://github.com/bakkeby/patches/wiki/tagicons */ static const char *tags[NUMTAGS] = { NULL }; /* left for compatibility reasons, i.e. code that checks LENGTH(tags) */ static char *tagicons[][NUMTAGS] = { - [IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, + [IconsDefault] = { "○" }, [IconsVacant] = { NULL }, - [IconsOccupied] = { NULL }, + [IconsOccupied] = { "☉" }, + [IconsSelected] = { "◉" }, }; static const Rule rules[] = { diff --git a/dwm.c b/dwm.c index 614a9ef..b28febd 100644 --- a/dwm.c +++ b/dwm.c @@ -71,6 +71,7 @@ enum { IconsDefault, IconsVacant, IconsOccupied, + IconsSelected, IconsLast }; /* icon sets */ @@ -1729,7 +1730,9 @@ tagicon(Monitor *m, int tag) char *icon; for (c = m->clients; c && (!(c->tags & 1 << tag)); c = c->next); // for (c = m->clients; c && (!(c->tags & 1 << tag) || HIDDEN(c)); c = c->next); // awesomebar / wintitleactions compatibility - if (c && tagicons[IconsOccupied][0] != NULL) + if (m->tagset[m->seltags] & 1 << tag && tagicons[IconsSelected][0] != NULL) + icon = geticon(m, tag, IconsSelected); + else if (c && tagicons[IconsOccupied][0] != NULL) icon = geticon(m, tag, IconsOccupied); else { icon = geticon(m, tag, m->iconset); -- 2.19.1