dwm-appicons-6.5.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dwm-appicons-6.5.diff (8715B)
       ---
            1 From dbae98a1cf614908ff0075c5f4a3d4ad619f0519 Mon Sep 17 00:00:00 2001
            2 From: Rumen <rumenmitov@protonmail.com>
            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 name.
            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", "9" };
           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 the min */
           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   monitor */
           34 -        { "Gimp",     NULL,       NULL,       0,            1,           -1 },
           35 -        { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1 },
           36 +        /* class      instance    title       tags mask     isfloating   monitor   appicon*/
           37 +        { "Gimp",     NULL,       NULL,       0,            1,           -1,         NULL },
           38 +        { "Firefox",  NULL,       NULL,       1 << 8,       0,           -1,         "󰈹"  },
           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_size);
           76 +static void applyappicon(char *tag_icons[], int *icons_per_tag, const Client *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_after : 1;
           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->next);
          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) + 1);
          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 << i ? SchemeSel : SchemeNorm]);
          266 -                drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
          267 -                if (occ & 1 << i)
          268 +                drw_text(drw, x, 0, w, bh, lrpad / 2, m->tag_icons[i], urg & 1 << 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->sel->tags & 1 << i,
          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