Configure herbstluftwm to behave like i3 on tag switching
May 20, 2021
I recently switched from i3 to herbstluftwm, motivated by the promise,
that herbstluftwm really does decline to try to guess what is the
correct behaviour for me, but really just does what I tell it to.
herbstluftwm is fast, lightweight, renders everything I throw at it
correctly: Want a second, autohiding panel at the bottom? Sure thing;
switching resolutions when accessing the desktop session from remote
via nomachine's nx? Just tell me to detect monitors, I’ll adept.
The standard behaviour of the i3 window manager when switching tags is
a toggling behaviour on multiple keypresses to activate a specific
tag, that is it will toggle between the activated and the previously
active tab. This is something that really grew on me - switching
between documentation and shell or editor, etc. without extranious
finger movement.
herbstluftwm suggests the following keybindings in it’s default
autostart file, at least on ubuntu as well as manjaro linux:
for i in "${!tag_names[@]}" ; do hc add "${tag_names[$i]}" key="${tag_keys[$i]}" if ! [ -z "$key" ] ; then hc keybind "$Mod-$key" use_index "$i" hc keybind "$Mod-Shift-$key" move_index "$i" fi done
At the moment of writing this text, there is no other aspect of using
i3 that I miss – they both are minimalistic, tiling window managers,
i.e. not that different. My first thought was to somehow imitate i3’s behaviour with a shellscript, and use the spawn command instead of use_index:
hc keybind "$Mod-$key" spawn ${HOME}/.config/herbstluftwm/switch "${tag_names[$i]}"
The switch command is simple enough - compare the argument given with
the currently active tag and use_previous if they are the same, or
switch to the given tag if not:
#!/bin/bash hc() { herbstclient "$@" } if [ "${1}" == "$(hc attr monitors.focus.tag)" ]; then hc use_previous else hc use "${1}" fi
This worked like a charm. But it bothered me a little, that there were a lot of processes spawned that I felt shouldn’t be necessary. On further digging into the possibilities, I discovered the compare command. In combination with and and or the simple script switch can be translated into a single herbstclient call:
hc keybind "$Mod-$key" or / and + compare monitors.focus.tag "=" "${tag_names[$i]}" + use_previous / use "${tag_names[$i]}"
Feels more responsive too - the brain is a magical place :-)
The complete loop for all the copy ’n paste needs you (or I) might have:
for i in "${!tag_names[@]}" ; do hc add "${tag_names[$i]}" key="${tag_keys[$i]}" if ! [ -z "$key" ] ; then hc keybind "$Mod-$key" or / and + compare monitors.focus.tag "=" "${tag_names[$i]}" + use_previous / use "${tag_names[$i]}" hc keybind "$Mod-Shift-$key" move_index "$i" fi done