diff --git a/Makefile b/Makefile index 9b58d7f..03014a0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = atoms.c datetime.c drw.c dwm.c settings.c status.c util.c +SRC = atoms.c datetime.c drw.c dwm.c settings.c status.c tags.c util.c OBJ = ${SRC:.c=.o} all: options dwm @@ -17,7 +17,7 @@ options: %.o: %.c ${CC} -c $< -o $@ ${CFLAGS} -${OBJ}: atoms.h datetime.h drw.h config.def.h config.mk settings.h status.h util.h +${OBJ}: atoms.h datetime.h drw.h config.def.h config.mk settings.h status.h tags.h util.h dwm: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} diff --git a/config.def.h b/config.def.h index 196d51f..4722b4c 100644 --- a/config.def.h +++ b/config.def.h @@ -23,12 +23,6 @@ static const unsigned int systrayspacing = 2; /* systray spacing */ static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ static const int showsystray = 1; /* 0 means no systray */ -/* tagging */ -#define MAX_TAGNAME_LEN 14 /* excludes TAG_PREPEND */ -#define TAG_PREPEND "%1i:" /* formatted as 2 chars */ -#define MAX_TAGLEN 16 /* altogether */ -static char tags[][MAX_TAGLEN] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - static const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class diff --git a/dwm.c b/dwm.c index 430e6bb..b3c8190 100644 --- a/dwm.c +++ b/dwm.c @@ -46,6 +46,7 @@ #include "drw.h" #include "settings.h" #include "status.h" +#include "tags.h" #include "util.h" /* macros */ @@ -58,7 +59,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 << TAGS_COUNT) - 1) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) #define SYSTEM_TRAY_REQUEST_DOCK 0 @@ -310,16 +311,13 @@ static Window root, wmcheckwin; struct Pertag { unsigned int curtag, prevtag; /* current and previous tag */ - int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ - float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ - unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ - const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ - int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ + int nmasters[TAGS_COUNT + 1]; /* number of windows in master area */ + float mfacts[TAGS_COUNT + 1]; /* mfacts per tag */ + unsigned int sellts[TAGS_COUNT + 1]; /* selected layouts */ + const Layout *ltidxs[TAGS_COUNT + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[TAGS_COUNT + 1]; /* display bar for the current tag */ }; -/* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; - /* function implementations */ void applyrules(Client *c) @@ -497,11 +495,11 @@ buttonpress(XEvent *e) occ |= c->tags == 255 ? 0 : c->tags; do { /* do not reserve space for vacant tags */ - if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i || tags[i][1] != '\0')) + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i || tags_get(i)->has_custom_name)) continue; - x += TEXTW(tags[i]); - } while (ev->x >= x && ++i < LENGTH(tags)); - if (i < LENGTH(tags)) { + x += TEXTW(tags_get(i)->name.cstr); + } while (ev->x >= x && ++i < TAGS_COUNT); + if (i < TAGS_COUNT) { click = ClkTagBar; arg.ui = 1 << i; } else if (ev->x < x + blw) @@ -836,7 +834,7 @@ createmon(void) m->pertag = ecalloc(1, sizeof(Pertag)); m->pertag->curtag = m->pertag->prevtag = 1; - for (i = 0; i <= LENGTH(tags); i++) { + for (i = 0; i <= TAGS_COUNT; i++) { m->pertag->nmasters[i] = m->nmaster; m->pertag->mfacts[i] = m->mfact; @@ -929,14 +927,14 @@ drawbar(Monitor *m) urg |= c->tags; } x = 0; - for (i = 0; i < LENGTH(tags); i++) { + for (i = 0; i < TAGS_COUNT; i++) { /* do not draw vacant tags */ - if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i || tags[i][1] != '\0')) + if (!(occ & 1 << i || m->tagset[m->seltags] & 1 << i || tags_get(i)->has_custom_name)) continue; - w = TEXTW(tags[i]); + w = TEXTW(tags_get(i)->name.cstr); 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, tags_get(i)->name.cstr, urg & 1 << i); x += w; } w = blw = TEXTW(m->ltsymbol); @@ -1485,7 +1483,7 @@ movemouse(const Arg *arg) // TODO: this function really needs to be refactored void nametag(const Arg *arg) { - char *p, name[MAX_TAGNAME_LEN]; + char *p, name[TAGS_CUSTOM_NAME_SIZE]; FILE *f; int i; @@ -1494,7 +1492,7 @@ nametag(const Arg *arg) { fprintf(stderr, "dwm: popen 'dmenu < /dev/null' failed%s%s\n", errno ? ": " : "", errno ? strerror(errno) : ""); return; } - if (!(p = fgets(name, MAX_TAGNAME_LEN, f)) && (i = errno) && ferror(f)) + if (!(p = fgets(name, TAGS_CUSTOM_NAME_SIZE, f)) && (i = errno) && ferror(f)) fprintf(stderr, "dwm: fgets failed: %s\n", strerror(i)); if (pclose(f) < 0) fprintf(stderr, "dwm: pclose failed: %s\n", strerror(errno)); @@ -1503,14 +1501,9 @@ nametag(const Arg *arg) { if((p = strchr(name, '\n'))) *p = '\0'; - for (i = 0; i < LENGTH(tags); ++i) { + for (i = 0; i < TAGS_COUNT; ++i) { if (selmon->tagset[selmon->seltags] & (1 << i)) { - if (name[0] == '\0') { - sprintf(tags[i], "%d", i + 1); - } else { - sprintf(tags[i], TAG_PREPEND, i + 1); - strcat(tags[i], name); - } + tags_rename(i, name); } } diff --git a/tags.c b/tags.c new file mode 100644 index 0000000..1c868f0 --- /dev/null +++ b/tags.c @@ -0,0 +1,65 @@ +#include "tags.h" + +#include +#include + +static struct Tag tags[TAGS_COUNT] = { + [0] = { + .has_custom_name = false, + .name = { .structured = { .number = '1', .colon_or_eol = '\0' } }, + }, + [1] = { + .has_custom_name = false, + .name = { .structured = { .number = '2', .colon_or_eol = '\0' } }, + }, + [2] = { + .has_custom_name = false, + .name = { .structured = { .number = '3', .colon_or_eol = '\0' } }, + }, + [3] = { + .has_custom_name = false, + .name = { .structured = { .number = '4', .colon_or_eol = '\0' } }, + }, + [4] = { + .has_custom_name = false, + .name = { .structured = { .number = '5', .colon_or_eol = '\0' } }, + }, + [5] = { + .has_custom_name = false, + .name = { .structured = { .number = '6', .colon_or_eol = '\0' } }, + }, + [6] = { + .has_custom_name = false, + .name = { .structured = { .number = '7', .colon_or_eol = '\0' } }, + }, + [7] = { + .has_custom_name = false, + .name = { .structured = { .number = '8', .colon_or_eol = '\0' } }, + }, + [8] = { + .has_custom_name = false, + .name = { .structured = { .number = '9', .colon_or_eol = '\0' } }, + }, +}; + +const struct Tag *tags_get(const unsigned int index) +{ + if (index >= TAGS_COUNT) return NULL; + + return &tags[index]; +} + +void tags_rename(const unsigned int index, const char *const new_custom_name) +{ + if (index >= TAGS_COUNT) return; + + if (new_custom_name == NULL || new_custom_name[0] == '\0') { + tags[index].has_custom_name = false; + tags[index].name.structured.colon_or_eol = '\0'; + } else { + tags[index].has_custom_name = true; + tags[index].name.structured.colon_or_eol = ':'; + strncpy(tags[index].name.structured.custom_name, new_custom_name, TAGS_CUSTOM_NAME_SIZE); + tags[index].name.structured.custom_name[TAGS_CUSTOM_NAME_SIZE - 1] = '\0'; + } +} diff --git a/tags.h b/tags.h new file mode 100644 index 0000000..5b1cbc4 --- /dev/null +++ b/tags.h @@ -0,0 +1,30 @@ +#ifndef _TAGS_H +#define _TAGS_H + +#include + +#define TAGS_COUNT (9) +#define TAGS_CUSTOM_NAME_SLEN (13) +#define TAGS_CUSTOM_NAME_SIZE ((TAGS_CUSTOM_NAME_SLEN) + 1) + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[TAGS_COUNT > 31 ? -1 : 1]; }; + +struct __attribute__((packed)) TagName { + char number; + char colon_or_eol; + char custom_name[TAGS_CUSTOM_NAME_SIZE]; +}; + +struct Tag { + bool has_custom_name; + union { + char cstr[sizeof(struct TagName) / sizeof(char)]; + struct TagName structured; + } name; +}; + +const struct Tag *tags_get(unsigned int index); +void tags_rename(unsigned int index, const char *new_custom_name); + +#endif // _TAGS_H