Herbstluftwm Tiling Window Manager

about | blog | config | notes | github


Herbstlufwm is a manual tiling window manager for the Xorg X11 Window System. Every workspace has a collection of frames and each of these frames contain a collection of windows. The frames can be manually tiled wheras the windows in the frames follow one of many tiling algorithms.

1. Configuration

1.1. Initial Configuration

Pretty straightforward stuff, setup logger, create a helper function,

. $HOME/org/config/lib/shell/logger
LOGGER=$(get_logger herbstluftwm)
$LOGGER "Initializing herbstluftwm window manager"

hc() {
    herbstclient "[email protected]"

hc emit_hook reload

1.2. WM Custom Rules

Remove any prexisting rules

hc unrule --all

Setup simple focus rules

  • Focus new windows as they appear
  • Move all Xterm Windows to Tag 3 (I added this here simply for example's sake)
hc rule focus=on
#hc rule class=XTerm tag=3 # move all xterms to tag 3

Okay so probably the rules for the terminal are pointless here. Discord one actually doesn't work the way I want it to, but everything else here is pretty important. It makes sure that panels appear where they are suppose to and also ensures that popups are floating.

hc rule class~'(.*[Rr]xvt.*|.*[Tt]erm|Konsole)' focus=on
hc rule class~'(Discord|DiscordCanary)' focus=off
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' pseudotile=on
hc rule windowtype='_NET_WM_WINDOW_TYPE_DIALOG' focus=on
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)' manage=off

This is an import rule. What I'm trying to do here is make my Surf Browser be floating and on the bottom of all windows.

hc rule class='Surf' manage=off hook=surfdesktop

1.3. Keybindings

You can use xev to identify X11 keys very easily.

1.3.1. Setup

Remove all existing keybinding; Use the super key as the main modifier.

hc keyunbind --all

1.3.2. Reload WM and Close Window

Define the reload and close window keybindings. We also want to make sure we are reloading the Xinitrc User-Level Configurations here througha keybinding as well.

hc keybind $Super-Ctrl-Alt-r chain , \
        spawn $HOME/.config/bin/refresh-xinitrc.sh
hc keybind $Super-Ctrl-r reload
hc keybind $Super-q close

1.3.3. Window Focus

Keybindings for changing the focused client

hc keybind $Super-Left  focus left
hc keybind $Super-Down  focus down
hc keybind $Super-Up    focus up
hc keybind $Super-Right focus right
hc keybind $Super-h     focus left
hc keybind $Super-j     focus down
hc keybind $Super-k     focus up
hc keybind $Super-l     focus right

Keybindings for cycling the focused client

hc keybind $Super-BackSpace   cycle_monitor
hc keybind $Super-Tab         cycle +1
hc keybind $Super-Shift-Tab   cycle_frame +1
hc keybind $Super-c           cycle_all +1
hc keybind $Super-i jumpto urgent

1.3.4. Window Movement

Keybindings for moving windows around.

hc keybind $Super-Shift-Left  shift left
hc keybind $Super-Shift-Down  shift down
hc keybind $Super-Shift-Up    shift up
hc keybind $Super-Shift-Right shift right
hc keybind $Super-Shift-h     shift left
hc keybind $Super-Shift-j     shift down
hc keybind $Super-Shift-k     shift up
hc keybind $Super-Shift-l     shift right

1.3.5. Splitting Frames

Split the current frame by creating an empty frame in the specified direction.

hc keybind $Super-u       split   bottom  0.5
hc keybind $Super-o       split   right   0.5

Split the current frame by exploding the current frame into multiple frames.

hc keybind $Super-Control-space split explode

1.3.6. Resizing Frames

Define the step size and the keybindings for resizing frames.

hc keybind $Super-Control-h       resize left +$resizestep
hc keybind $Super-Control-j       resize down +$resizestep
hc keybind $Super-Control-k       resize up +$resizestep
hc keybind $Super-Control-l       resize right +$resizestep
hc keybind $Super-Control-Left    resize left +$resizestep
hc keybind $Super-Control-Down    resize down +$resizestep
hc keybind $Super-Control-Up      resize up +$resizestep
hc keybind $Super-Control-Right   resize right +$resizestep

1.3.7. Workspace Definitions (tags)

tag_names=([1] [2] [3] [4] [5] [6] [7] [8] [9] [0])
tag_keys=( {1..9} 0 )

hc rename default "${tag_names[0]}" || true
for i in ${!tag_names[@]} ; do
    hc add "${tag_names[$i]}"
    if ! [ -z "$key" ] ; then
        hc keybind "$Super-$key" use_index "$i"
        hc keybind "$Super-Shift-$key" move_index "$i"

1.3.8. Workspace Movement

Jump to the previous workspace (tag).

hc keybind $Super-grave use_previous

Move the next/previous workspace (tag).

hc keybind $Super-bracketright use_index +1 --skip-visible
hc keybind $Super-bracketleft  use_index -1 --skip-visible

1.3.9. Layout Control

hc keybind $Super-r remove
hc keybind $Super-s floating toggle
hc keybind $Super-f fullscreen toggle
hc keybind $Super-t pseudotile toggle

The following cycles through the available layouts within a frame, but skips layouts, if the layout change wouldn't affect the actual window positions. (I.e. if there are two windows within a frame, the grid layout is skipped.)

hc keybind $Super-space                                                       \
            or , and . compare tags.focus.curframe_wcount = 2                 \
                     . cycle_layout +1 vertical horizontal max vertical grid  \
               , cycle_layout +1

1.3.10. Mouse Control

hc mouseunbind --all
hc mousebind $Super-Button1 move
hc mousebind $Super-Button2 zoom
hc mousebind $Super-Button3 resize

1.3.11. Colorscheme Cylcing

Just some nice keybindings to cycle through existing colorschemes.

hc keybind $Super-Ctrl-Alt-bracketright chain , \
        spawn $HOME/org/config/bin/xcolorscheme --next , reload

hc keybind $Super-Ctrl-Alt-bracketleft chain , \
        spawn $HOME/org/config/bin/xcolorscheme --prev , reload

1.4. Theme Configuration

1.4.1. Source Colorscheme

. $HOME/org/config/lib/shell/xrdb_colors

1.4.2. Reset Tiling and Floating states

hc attr theme.tiling.reset 1
hc attr theme.floating.reset 1

1.4.3. Frame Appearance

hc set frame_transparent_width 1
hc set frame_border_width 1
hc set frame_border_active_color $MAGENTA
hc set frame_border_normal_color $XBACKGROUND

hc set frame_bg_transparent 1
hc set frame_bg_normal_color $XBACKGROUND
hc set frame_bg_active_color $XCOLOR8

hc set always_show_frame 0
hc set frame_gap 0
hc set frame_padding 0

1.4.4. Window Appearance

hc attr theme.active.outer_color $XBACKGROUND
hc attr theme.active.inner_color $XBACKGROUND

hc attr theme.normal.color $BLACK
hc attr theme.active.color $WHITE
hc attr theme.urgent.color orange

hc attr theme.border_width 9
hc attr theme.inner_width 3
hc attr theme.outer_width 4

hc attr theme.inner_color $XBACKGROUND
hc attr theme.outer_color $XBACKGROUND

hc attr theme.floating.border_width 9
hc attr theme.floating.inner_width 3
hc attr theme.floating.outer_width 4

hc attr theme.floating.outer_color $XBACKGROUND
hc attr theme.background_color '#141414'

hc set window_gap 0
hc set smart_window_surroundings 0
hc set smart_frame_surroundings 1
hc set mouse_recenter_gap 0

1.4.5. Tree View

hc set tree_style '╾│ ├└╼─┐'

1.4.6. Montior Setup

Well monitor setup doesn't belong here really, but we're doing it here because we need to make space for the panels. (Run the unlock command, just to be sure)

hc unlock
hc detect_monitors

1.4.7. Configure Panel Height

for monitor in $(seq 0 2); do
    hc pad $monitor $PANEL_HEIGHT 0 $PANEL_HEIGHT 0

1.5. Event Hooks

This starts a couple FIFO hooks so that Lemonbar can update the information on it's panel as effeciently as possible.

1.5.1. Event Hooks Startup Verification

if [ $(pgrep -cx herbstclient) -gt 0 ]; then
    printf "The herbstluftwm event hooks for lemonbar are already running.\n" >&2
    $LOGGER "The herbstluftwm event hooks for lemonbar are already running."
    exit 1

1.5.2. Event Hooks Trigger Definition

WSP_TRIGGER="$HOME/.config/lemonbar/utils/trigger_fifos wsp"
WIN_TRIGGER="$HOME/.config/lemonbar/utils/trigger_fifos win"

1.5.3. Initialize Event Hooks

I don't remember why I commented one of the hooks out, oh thats rights, its because I'm not using the lemonbar xwindow module I made anymore.

(herbstclient --idle       | while read -r line; do $WSP_TRIGGER; done) &
#(herbstclient --idle $WARG | while read -r line; do $WIN_TRIGGER; done) &

$LOGGER "All hook have been started"

Created: 2021-11-13

Emacs 26.1 (Org mode 9.5)