-
Notifications
You must be signed in to change notification settings - Fork 30
tagicons
This patch aims to combine and expand on the following patches:
Depending on your needs some configuration of tags will be required after patching. As such keybindings for related functions are commented out by default in the patch. It is up to you what you want out of this.
Because of the above the patch does produce compilation warnings due to unused code.
In a traditional dwm the number of tags in use can be changed by changing the number of strings in the tags array.
With this patch the number of tags is controlled with the NUMTAGS
macro in dwm.c, which is
primarily used to differentiate between different icons per monitor.
By default the patch comes with this setup which simply replicates the 1 through 9 tags that what comes with a bare dwm 6.3 build.
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
[IconsVacant] = { NULL },
[IconsOccupied] = { NULL },
};
Let's have a closer look at the different icon sets and features.
Tag icons can be defined on a per monitor basis and the position of the icons is derived based on
the number of tags (NUMTAGS
) and the monitor number (index). If the derived tag index is greater
than the available icons then a modulus between the two is further applied.
Let's have look at a practical example:
static char *tagicons[][NUMTAGS*2] = {
[IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I" },
[IconsVacant] = { NULL },
[IconsOccupied] = { NULL },
};
In this case icons 1 through 9 is being used for monitor 0 while icons A through I are used for monitor 1.
How does that work exactly? Note the NUMTAGS*2
which doubles the number of icons. The icon for
a tag is derived as tag index + monitor index * NUMTAGS. So for the third tag on the second monitor
we end up with 2 + 1 * 9 which gives the icon of "C".
If a third monitor is used then that gives 2 + 2 * 9 (index 20). As that is greater than the number of icons (NUMTAGS*2) a modulus is applied: 20 % 18 = 2, giving the icon of "3". In other words the icons wraps around. A fourth monitor would then use icons A through I.
This mechanism comes into play again in the example below.
Having identical tags can also make for an elegant look and feel. For example having all tags shown as bullet points gives a certain aesthetic.
In a normal dwm build that would be configured like this:
static const char *tags[] = { "•", "•", "•", "•", "•", "•", "•", "•", "•" };
With the tagicons patch this can be simplified to a single bullet point thanks to how icon indexes are derived and reduced:
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "•" },
[IconsVacant] = { NULL },
[IconsOccupied] = { NULL },
};
Similarly if you choose two tags A
and B
then tags will alternate between them.
If you want identical tags for all tags, but different tags per monitor, then you will have to explicitly define them all though.
The IconsOccupied tag set will replace the default icons if there are clients occupating the given tag. This is a practical representation of the alttagsdecoration patch.
If IconsOccupied is NULL
then that means that the feature is not to be used.
A practical example:
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
[IconsVacant] = { NULL },
[IconsOccupied] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
};
When dwm starts up tags 1 through 9 will be displayed. As soon as a client is opened on a tag then the occupied tag icon is being used instead. E.g. opening a client on tag 5 means that "<5>" will be shown instead of "5".
To hide vacant (as in empty) tags simply set the icon text to be an empty string.
Taking advantage of the repeating icons logic we can set a single empty string to replicate the behavour of the hide vacant tags patch.
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "" },
[IconsVacant] = { NULL },
[IconsOccupied] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
};
One benefit of doing it this way (using empty strings) is that you could choose to hide all tags except for special ones that you want to always display. Here is an example that hides all but the seventh, eight and ninth tag:
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "", "", "", "", "", "", "7", "8", "9" },
[IconsVacant] = { NULL },
[IconsOccupied] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
};
If a client exists on tag 3 then "<3>" will be shown as per the occupied tags feature.
This brings us to an exception; vacant tags.
The IconsVacant tag set is a bit of an exception and is only used when:
- the default icon is hidden (i.e. being an empty string) and
- the selected tag is not occupied
In other words this is only used when you explicitly view a tag that has no clients on it.
An example configuration may look like:
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "" },
[IconsVacant] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
[IconsOccupied] = { "<1>", "<2>", "<3>", "<4>", "<5>", "<6>", "<7>", "<8>", "<9>" },
};
Here all tags are hidden by default, but show "1", "2", etc. when selected unless they have clients on them.
Icon sets are defined by an enum in dwm.c:
enum {
IconsDefault,
IconsVacant,
IconsOccupied,
IconsLast
}; /* icon sets */
As with colour schemes you can add your own sets here and as many as you want. Here is an example setup:
static char *tagicons[][NUMTAGS] = {
[IconsDefault] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" },
[IconsBullets] = { "•" },
[IconsLetters] = { "A", "B", "C", "D", "E", "F", "G", "H", "I" },
[IconsText] = { "mail", "chat", "office", "gimp", "prog", "misc", "play", "mon", "web" },
[IconsSubscript] = { " ₁", " ₂", " ₃", " ₄", " ₅", " ₆", " ₇", " ₈", " ₉"
[IconsVacant] = { "•₁", "•₂", "•₃", "•₄", "•₅", "•₆", "•₇", "•₈", "•₉" },
[IconsOccupied] = { "◉₁", "☢₂", "❖₃", "⚉₄", "♻₅", "⌬₆", "♹₇", "✇₈", "☉₉" },
};
You can then cycle through the various icon sets with the cycleiconset
function by using the mouse
scroll wheel on the tags (provided that the button binding is set of course). Alternatively you can
add keybindings to set specific icon sets if you prefer.
This extends the alternativetags patch by allowing you to have multiple alternative tags rather than just the one.
It should be noted though that with the implementation as-is the IconsOccupied icon set will always override the selected icon set if the tag is occupied by clients. Being able to define occupied and vacant icon sets on a per icon set basis was considered, but was deemed to add too much complexity for a feature that most people would likey not want. One likely solution could be to use variables that point to the sets that defines vacant and occupied icons, and allow these to be changed during runtime.
Given the way tag masks work it doesn't make much sense to try to configure a different number of
tags per monitor - at best one will end up just blocking the use of certain tags in the view
,
toggleview
, tag
and toggletag
functions.
The easiest solution here is to just hide the tags that you do not want shown.
To do this properly one should probably look into implementing actual workspaces (a monumental task) or fall back to using the single tagset patch which has a few issues on its own.
The original tags
array has been left in the code for compatibility reasons because many other
patches rely on LENGTH(tags)
without necessarily using the tag text.
For all intensive purposes LENGTH(tags)
can be safely replaced with NUMTAGS
in such cases.
There are a few patches that need additional integration steps:
ewmhtags - the setdesktopnames
function explicitly
passes the tags array to Xutf8TextListToTextProperty
, you may want to replace it with something
like this:
void
setdesktopnames(void)
{
int i;
XTextProperty text;
char *tags[NUMTAGS];
for (i = 0; i < NUMTAGS; i++)
tags[i] = tagicon(selmon, i);
Xutf8TextListToTextProperty(dpy, tags, NUMTAGS, XUTF8StringStyle, &text);
XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
}
ipc - in the run
function of dwm.c you may want to replace
} else if (ipc_is_client_registered(event_fd)){
if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon,
tags, LENGTH(tags), layouts, LENGTH(layouts)) < 0) {
fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd);
}
} else {
with
} else if (ipc_is_client_registered(event_fd)){
char *tags[NUMTAGS];
for (int t = 0; t < NUMTAGS; t++)
tags[t] = tagicon(selmon, t);
if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon,
tags, NUMTAGS, layouts, LENGTH(layouts)) < 0) {
fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd);
}
} else {
-
dwm
- banish
- barmodules
- dragmfact
- dragcfact
- fakefullscreenclient
- flextile-deluxe
- floatpos
- focusdir
- focusedontop
- focusfollowmouse
- fullscreen-compilation
- lock masks
- losefullscreen
- mark
- masterstacker
- monitorrules
- netclientliststacking
- placedir
- placemouse
- renamedscratchpads
- resizepoint
- riodraw
- sendmon keepfocus
- shiftviewclients
- steam
- swallow
- switchtag
- tagallmon
- tagicons
- tagmonfixfs
- tagswapmon
- togglefullscreen
- togglelayout
- toggletag
- unmanaged
- vanitygaps
- windowrolerule