herbstluftwm is a window manager. The following is my configuration, which is based on the default one (with tweaks to avoid depending on bash)


herbstclient is quite long to write, so abbreviate it

alias hc=herbstclient

hc emit_hook reload

remove all existing keybindings before adding the new ones

hc keyunbind --all

I prefer using mod4 (the super/windows/... key) to manage the window manger, with only few exceptions

#Mod=Mod1   # Use alt as the main modifier
Mod=Mod4    # Use the super key as the main modifier

hc keybind $Mod-Tab use_previous
hc keybind $Mod-Shift-q quit
hc keybind $Mod-Shift-r reload
hc keybind $Mod-Shift-c close
hc keybind $Mod-slash spawn menu
hc keybind $Mod-Control-Return spawn emacsclient -c
hc keybind Control-Mod1-Return spawn xterm

control amused (my music player)

hc keybind XF86AudioNext spawn amused next
hc keybind XF86AudioPlay spawn amused toggle
hc keybind XF86AudioPrev spawn amused prev
hc keybind XF86AudioStop spawn amused stop

I don't have a dedicated key for screenshot, but Scroll_Lock is not too awkward to press

hc keybind $Mod-Scroll_Lock spawn sshot -c
hc keybind $Mod-Shift-Scroll_Lock spawn sshot -cs

basic movement in tiling and floating mode focusing clients

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

moving clients in tiling and floating mode

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

splitting frames creates an empty frame at the specified direction

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

let the current frame explode into subframes

hc keybind $Mod-Control-space split explode

resizing frames and floating clients

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

add the tags

hc rename default "1" || true
addtag() {
	hc add $1
	if [ ! -z "$2" ]; then
		hc keybind "$Mod-$2" use $1
		hc keybind "$Mod-Shift-$2" move $1

addtag 1 ampersand
addtag 2 braceleft
addtag 3 bracketleft
addtag 4 parenleft
addtag 5 equal
addtag 6 plus
addtag 7 parenright
addtag 8 bracketright
addtag 9 braceright
addtag 0 exclam

cycle through tags

hc keybind $Mod-period use_index +1 --skip-visible
hc keybind $Mod-comma  use_index -1 --skip-visible

manage the layout

hc keybind $Mod-r remove
hc keybind $Mod-s floating toggle
hc keybind $Mod-f fullscreen toggle
hc keybind $Mod-Shift-f set_attr clients.focus.floating toggle
hc keybind $Mod-Shift-m set_attr clients.focus.minimized true
hc keybind $Mod-Control-m jumpto last-minimized
hc keybind $Mod-p pseudotile toggle

I prefer for the default layout to be `max' (only one window visible)

hc set default_frame_layout max

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 $Mod-space						\
	or , and . compare tags.focus.curframe_wcount = 2	\
		. cycle_layout +1				\
			vertical horizontal max vertical grid	\
		, cycle_layout +1

mouse bindings

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


hc keybind Mod1-Tab         cycle_all +1
hc keybind Mod1-Shift-Tab   cycle_all -1

hc keybind $Mod-BackSpace   cycle_monitor
hc keybind $Mod-c cycle
hc keybind $Mod-i jumpto urgent


hc attr theme.tiling.reset 1
hc attr theme.floating.reset 1
hc set frame_border_active_color '#222222cc'
hc set frame_border_normal_color '#ffffff'
hc set frame_bg_normal_color '#565656aa'
hc set frame_bg_active_color '#345F0Caa'
hc set frame_border_width 1
hc set always_show_frame on
hc set frame_bg_transparent on
hc set frame_transparent_width 5
hc set frame_gap 4

hc attr theme.title_height 0
#hc attr theme.title_font 'Dejavu Sans:pixelsize=12'  # example using Xft
hc attr theme.title_font '-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*'
hc attr theme.padding_top 2  # space below the title's baseline (i.e. text depth)
hc attr theme.active.color '#9AFAFF'
hc attr theme.title_color '#222222'
hc attr theme.normal.color '#ffffef'
hc attr theme.urgent.color '#7811A1dd'
hc attr theme.normal.title_color '#898989'
hc attr theme.inner_width 1
hc attr theme.inner_color black
hc attr theme.border_width 2
hc attr theme.floating.border_width 4
hc attr theme.floating.outer_width 1
hc attr theme.floating.outer_color black
hc attr theme.active.inner_color '#789161'
hc attr theme.urgent.inner_color '#9A65B0'
hc attr theme.normal.inner_color '#606060'
# copy inner color to outer_color
for state in active urgent normal ; do
	hc substitute C theme.${state}.inner_color \
		attr theme.${state}.outer_color C
hc attr theme.active.outer_width 1
hc attr theme.background_color '#141414'

hc set window_gap 0
hc set frame_padding 0
hc set smart_window_surroundings off
hc set smart_frame_surroundings on
hc set mouse_recenter_gap 0

hc set focus_follows_mouse 1
hc set raise_on_click false
hc set snap_gap 5


hc unrule -F
#hc rule class=XTerm tag=3 # move all xterms to tag 3
hc rule focus=on # normally focus new clients
hc rule floatplacement=smart
#hc rule focus=off # normally do not focus new clients
# give focus to most common terminals
#hc rule class~'(.*[Rr]xvt.*|.*[Tt]erm|Konsole)' focus=on
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' floating=on
hc rule windowtype='_NET_WM_WINDOW_TYPE_DIALOG' focus=on
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)' manage=off

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

A cool thing about herbstluftwm is that I can "dump" the layout and later reload it:

load_layout() {
	if [ -f "$2" ]; then
		hc load $1 "$(cat $2)"

load_layout 2 ~/herbst.ws.2
load_layout 3 ~/herbst.ws.3

unlock, just to be sure

hc unlock

I'd like to have some gaps around my only monitor, herbstluftwm makes it incredibly easy

herbstclient set_monitors $((1920-100))x$((1080-100))+50+50
# hc detect_monitors

Finally launche the panel on each screen. I rewrote the original script for the monitor in a mix of rc (the plan9 shell) and awk.

cd ~/.config/herbstluftwm
for monitor in $(hc list_monitors | cut -d: -f1) ; do
	./panel "$monitor" &