bakkeby / dwm-flexipatch

A dwm build with preprocessor directives to decide which patches to include during build time
MIT License
1.18k stars 238 forks source link

Feature request: Tag win icons patch #318

Open Vinschers opened 1 year ago

Vinschers commented 1 year ago

Hey, I don't know it this is OK or if this is the place to do something like that, but I was wondering if I could share a patch I did some time ago and maybe add it to the project.

I am no C programmer; I just put some stuff together and it worked. I would be happy to change anything if necessary.

The basic idea of the patch is showing the icon of the main window in its tag, dynamically. Something like this.

I coded it on top of the BAR_WINICON_PATCH and tagicons patches.

This is the basic diff file for it:

diff '--color=auto' -r dwm-d/config.def.h dwm/config.def.h
146,150c146,164
< static char *tagicons[][NUMTAGS] =
< {
<   [DEFAULT_TAGS]        = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
<   [ALTERNATIVE_TAGS]    = { "A", "B", "C", "D", "E", "F", "G", "H", "I" },
<   [ALT_TAGS_DECORATION] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
---
> static char *tagicons[][NUMTAGS] = {
>   [IconsDefault]              = { "" },
>   [IconsVacant]               = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
>   [IconsOccupied]             = { "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "⑨" },
> };
> 
> static char occupiedicons[][3][50] = {
>   { "vim",            "",    "#019833" },
>   { "neovim",         "",    "#019833" },
>     { "htop",           "",    "#BA9FD7" },
>     { "gtop",           "",    "#BA9FD7" },
>   { "pdf",            "",    "#DC1D00" },
>   { "zathura",        "",    "#DC1D00" },
>   { "okular",         "",    "#DC1D00" },
>   { "sxiv",           "",    "" },
>   { "ncspot",         "",    "#1DB954" },
>   { "spotify",        "",    "#1DB954" },
>   { "zotero",         "📚",   "" },
>   { "webcam",         "犯",   "" },
diff '--color=auto' -r dwm-d/patch/bar_tagicons.c dwm/patch/bar_tagicons.c
0a1,7
> #include <ctype.h>
> #include <string.h>
> #include <stdio.h>
> #include <stdlib.h>
> 
> static char currenticons[NUMTAGS][10];
> 
2c9
< tagicon(Monitor *m, int tag)
---
> geticon(Monitor *m, int tag, int iconset)
3a11
>   int i;
5,7c13,92
<   if (tagindex >= LENGTH(tagicons[DEFAULT_TAGS]))
<       tagindex = tagindex % LENGTH(tagicons[DEFAULT_TAGS]);
<   return tagicons[DEFAULT_TAGS][tagindex];
---
>   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];
> }
> 
> void
> tolowerstr(char *dest, const char *src)
> {
>   unsigned char *p = NULL;
> 
>   for (p = (unsigned char *)src; *p; ++p)
>       *(dest++) = tolower(*p);
>   *dest = 0;
> }
> 
> char *
> gettagsuperscript(int tag)
> {
>   switch (tag) {
>       case 0:
>           return "¹";
>       case 1:
>           return "²";
>       case 2:
>           return "³";
>       case 3:
>           return "⁴";
>       case 4:
>           return "⁵";
>       case 5:
>           return "⁶";
>       case 6:
>           return "⁷";
>       case 7:
>           return "⁸";
>       case 8:
>           return "⁹";
>   }
> 
>   return "";
> }
> 
> unsigned char
> hex_to_dec(const char *hex)
> {
>     unsigned char ret = 0;
> 
>     if (hex[0] >= 'a')
>         ret += hex[0] - 'a' + 10;
>     else
>         ret += hex[0] - '0';
>     ret <<= 4;
> 
>     if (hex[1] >= 'a')
>         ret += hex[1] - 'a' + 10;
>     else
>         ret += hex[1] - '0';
> 
>     return ret;
> }
> 
> void
> change_scheme(char *color, Clr *scheme)
> {
>     char lowercolor[10];
>     unsigned short red, green, blue;
> 
>     tolowerstr(lowercolor, color + 1); // Remove #
> 
>     red = hex_to_dec(lowercolor);
>     green = hex_to_dec(lowercolor + 2);
>     blue = hex_to_dec(lowercolor + 4);
> 
>     scheme->color.red = red << 8;
>     scheme->color.green = green << 8;
>     scheme->color.blue = blue << 8;
9a95,167
> unsigned char
> containsstr(char *str1, char *str2)
> {
>     char *ptr;
> 
>     for (ptr = str1; *ptr; ++ptr) {
>         if (ptr == str1 || *(ptr - 1) == ' ')
>             if (strncmp(ptr, str2, strlen(str2)) == 0)
>                 return 1;
>     }
> 
>     return 0;
> }
> 
> void
> setoccupiedicon(Monitor *m, int tag, Picture *img, int *imgw, int *imgh)
> {
>     Client *c;
>     unsigned short i = 0;
>   char *tagsuperscript = gettagsuperscript(tag), lowername[200], currentname[200];
>     char *icon = currenticons[tag];
> 
>     *imgw = 0;
>     *imgh = 0;
> 
>     for (c = m->clients; c && !(c->tags & 1 << tag); c = c->next) {}
>   if (!c) {
>         *icon = '\0';
>         return;
>     }
> 
>   tolowerstr(lowername, c->name);
> 
>   for (i = 0; i < LENGTH(occupiedicons); ++i) {
>       tolowerstr(currentname, occupiedicons[i][0]);
> 
>       if (containsstr(lowername, currentname)) {
>             sprintf(icon, "%s%s", occupiedicons[i][1], tagsuperscript);
> 
>             if (occupiedicons[i][2][0] != '\0') // if there is a new color for the icon
>                 change_scheme(occupiedicons[i][2], scheme[SchemeTagsNorm]);
> 
>             return;
>       }
>   }
> 
>     if (c->icon) {
>         *img = c->icon;
>         *imgw = c->icw;
>         *imgh = c->ich;
>         strcpy(icon, tagsuperscript);
>     } else {
>         strcpy(icon, geticon(m, tag, IconsOccupied));
>     }
> }
> 
> char *
> tagicon(Monitor *m, int tag, Picture *img, int *imgw, int *imgh)
> {
>     char *icon = currenticons[tag];
> 
>     change_scheme(colors[SchemeTagsNorm][0], scheme[SchemeTagsNorm]);
>   setoccupiedicon(m, tag, img, imgw, imgh);
> 
>   if (*icon == '\0') {
>         strcpy(icon, geticon(m, tag, IconsDefault));
> 
>       if (TEXTW(icon) <= lrpad && m->tagset[m->seltags] & 1 << tag)
>             strcpy(icon, geticon(m, tag, IconsVacant));
>   }
> 
>   return icon;
> }
diff '--color=auto' -r dwm-d/patch/bar_tagicons.h dwm/patch/bar_tagicons.h
2,5c2,6
<   DEFAULT_TAGS,
<   ALTERNATIVE_TAGS,
<   ALT_TAGS_DECORATION,
< };
---
>   IconsDefault,
>   IconsVacant,
>   IconsOccupied,
>   IconsLast
> }; /* icon sets */
7c8
< static char * tagicon(Monitor *m, int tag);
---
> static char * tagicon(Monitor *m, int tag, Picture *img, int *imgw, int *imgh);
diff '--color=auto' -r dwm-d/patch/bar_tags.c dwm/patch/bar_tags.c
0a1,22
> #define BAR_OFFSET 2
> 
> int
> width_tag(Bar *bar, int tag)
> {
>     Monitor *m = bar->mon;
>     int w = 0, tw, imgw, imgh;
>     Picture img;
> 
>     tw = TEXTW(tagicon(m, tag, &img, &imgw, &imgh));
> 
>     if (tw <= lrpad)
>         return 0;
> 
>     tw += imgw;
> 
>     if (tw > lrpad)
>         w += tw;
> 
>     return w;
> }
> 
7c29
<       w += TEXTW(tagicon(bar->mon, i));
---
>         w += width_tag(bar, i);
9c31,32
<   return w;
---
> 
>   return w + BAR_OFFSET;
19d41
<   Client *c;
20a43,46
>   Client *c;
>     Picture img;
>     int imgw, imgh;
>     int offset;
27d52
<   for (i = 0; i < NUMTAGS; i++) {
29c54,55
<       icon = tagicon(bar->mon, i);
---
>   for (i = 0; i < NUMTAGS; i++) {
>       icon = tagicon(bar->mon, i, &img, &imgw, &imgh);
31a58,64
> 
>         if (imgw > 0)
>             w += imgw;
> 
>         if (w <= lrpad)
>             continue;
> 
39c72,87
<       drw_text(drw, x, a->y, w, a->h, lrpad / 2, icon, invert, False);
---
> 
>         drw_text(drw, x, a->y, w, a->h, lrpad / 2, "", invert, False);
> 
>         if (i == 0)
>             offset = BAR_OFFSET;
>         else
>             offset = BAR_OFFSET / 2;
> 
>         if (imgw > 0) {
>             drw_text(drw, x + offset + imgw, a->y, TEXTW(icon), a->h, lrpad / 2, icon, invert, False);
>             drw_pic(drw, x + offset + lrpad / 2, a->y + (a->h - imgh)/2, imgw, imgh, img);
>         } else {
>             drw_text(drw, x + offset, a->y, w, a->h, lrpad / 2, icon, invert, False);
>             drw_text(drw, x + w, a->y, w, a->h, lrpad / 2, "", invert, False);
>         }
> 
41,42c89,94
<       if (ulineall || m->tagset[m->seltags] & 1 << i)
<           drw_rect(drw, x + ulinepad, bh - ulinestroke - ulinevoffset, w - (ulinepad * 2), ulinestroke, 1, 0);
---
>       if (ulineall || m->tagset[m->seltags] & 1 << i) {
>             if (i == 0)
>               drw_rect(drw, x + ulinepad + offset, bh - ulinestroke - ulinevoffset, w - (ulinepad * 2), ulinestroke, 1, 0);
>             else
>               drw_rect(drw, x + ulinepad + offset, bh - ulinestroke - ulinevoffset, w - (ulinepad * 2), ulinestroke, 1, 0);
>         }
55c107
<       x += TEXTW(tagicon(bar->mon, i));
---
>         x += width_tag(bar, i);
74c126
<       x += TEXTW(tagicon(bar->mon, i));
---
>         x += width_tag(bar, i);

What do you think?

bakkeby commented 1 year ago

Thanks for that. There are not a lot of novel ideas coming up for dwm these days so something new is always welcome.

To be honest I think this is likely going to be too specific to include in dwm-flexipatch, but I'll have a tinker in any case.

Some thoughts / feedback that you may consider for your personal build: