#!/usr/bin/env zsh ## Helper functions: # This simple function saves a lot of keystrokes when editing this # configuration. Instead of typing "herbstluftwm" everywhere, I can # just type "hc". This is part of the default configuration. function hc() { herbstclient "$@"; } # This function picks a random wallpaper from a list collection. function random-wallpaper() { find ~/pictures/wallpapers -type f \ -wholename '*/3840x1080/*' -o -wholename '*/patterns/*' \ | shuf -n 1 } # This function adds an attribute to a herbstluftwm tag that tells it # which monitor it should appear on, in case I care. Usually I want # Emacs and my terminal to always appear on my primary monitor, and # Conkeror/Firefox on my secondary, I don't like it when they get # switched. function lock-tag-to-monitor() { herbstclient chain \ , new_attr string tags.by-name."$1".my_monitor \ , set_attr tags.by-name."$1".my_monitor "$2" } ## Reload hook: # According to the herbstluftwm man page this hook is emitted so that # daemons will know to quit and it should be emitted first thing. hc emit_hook reload ## Background image: # Set a random image as the desktop wallpaper. feh --bg-tile "${HOME}/pictures/wallpapers/Relic_20Anni_Homeworld_1920x1080.png" ## Keybindings: # Remove all existing keybindings so that when herbstluftwm is # restarted, no keybindings get accidentally left active if they've # been removed. hc keyunbind --all # Use the super key as the main modifier, Alt (Mod1) is used by too # many other applications (Emacs and Zsh for example) to really be # useful. Mod=Mod4 # These are dangerous keybindings, they could be very annoying if # they're accidentally pressed, so using Shift here to make it a # little less easy to do this is a good idea. hc keybind $Mod-Shift-q quit hc keybind $Mod-Shift-r reload # Usually I close the applications I use through a menu or keybinding # inside the application, but not all applications offer # this. Sometimes need to tell the window manager to do so. hc keybind $Mod-k close # Normally I try to have frames set-up the way I like them # programmatically, not manually, but sometimes I need to do it # manually anyway and remove them afterwards. hc keybind $Mod-Mod1-k remove # Always spawn an instance of Rxvt Unicode. hc keybind $Mod-Return spawn urxvt # Switch to a running instance of URxvt or Hyper, or start one. hc keybind $Mod-c spawn hlwm-run-or-raise '\(URxvt\|Hyper\)' urxvt # Switch to a running instance of Conkeror, or start one. hc keybind $Mod-b spawn hlwm-run-or-raise '\(Conkeror\|Firefox\|Chromium\)' conkeror # Switch to a running instance of Emacs, or create an Emacs client # frame. Start an Emacs daemon if necessary. hc keybind $Mod-t spawn hlwm-run-or-raise Emacs \ emacsclient --create-frame --alternate-editor='' # Lock the screen with C-M-l. hc keybind Control-Mod1-l spawn i3lock --color 000000 # Swap visible tags hc keybind $Mod-x spawn hlwm-switch-tags # Since I use the colemak keyboard layout, hjkl doesn't make much # sense. I use neio instead since that is almost in the same place # (though one place to the right). I try to use my run-or-raise script # as much as I can, and have the layouts set-up correctly already, but # sometimes I still need to move around, resize and move clients. resizestep=0.05 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 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 # I usually try to have my layouts set-up programmatically, but this # isn't always possible or practical. hc keybind $Mod-s split bottom 0.5 hc keybind $Mod-Shift-s split right 0.5 # Switching tags by number (key) isn't always practical, sometimes # switching to next/previous tag is easiest. hc keybind $Mod-period use_index +1 --skip-visible hc keybind $Mod-comma use_index -1 --skip-visible # Games and sometimes other applications don't always like being # forced into a strangely sized box, floating mode helps. hc keybind $Mod-Control-f floating toggle # Playing games in fullscreen mode can end badly by having the game # spread across both monitors. Also watching a twitch stream with lots # of text is best in fullscreen. hc keybind $Mod-f cycle_layout 1 vertical max hc keybind $Mod-Shift-f fullscreen toggle hc keybind $Mod-p 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 $Mod-space \ or , and . compare tags.focus.curframe_wcount = 2 \ . cycle_layout +1 vertical horizontal max vertical grid \ , cycle_layout +1 # mouse hc mouseunbind --all hc mousebind $Mod-Button1 move hc mousebind $Mod-Button2 zoom hc mousebind $Mod-Button3 resize # focus hc keybind $Mod-BackSpace cycle_monitor # Use u because i is already used by by navigation commands. hc keybind $Mod-u jumpto urgent # Add some media key bindings for MPD. hc keybind XF86AudioPlay spawn mpc toggle hc keybind XF86AudioNext spawn mpc next hc keybind XF86AudioPrev spawn mpc prev # Add a screenshot button. hc keybind Print spawn scrot \ "${HOME}/pictures/screenshots/desktop/%Y%m%d_\$wx\$h_scrot.png" if which lumeus >/dev/null 2>&1; then hc keybind XF86MonBrightnessUp spawn lumeus +10% hc keybind XF86MonBrightnessDown spawn lumeus -10% fi if which ponymix >/dev/null 2>&1; then hc keybind XF86AudioMute spawn ponymix toggle hc keybind XF86AudioLowerVolume spawn ponymix decrease 10 hc keybind XF86AudioRaiseVolume spawn ponymix increase 10 fi # Change the default layout to fullscreen. hc set default_frame_layout 2 ## Tags: tag_names=( dev web {3..10} ) tag_indexes=( {1..${#tag_names}} ) tag_keys=( bracketleft braceleft braceright parenleft equal asterisk parenright plus bracketright exclam ) hc rename default "${tag_names[1]}" || true for i in $tag_indexes; do hc add "${tag_names[$i]}" key="${tag_keys[$i]}" if ! [ -z "$key" ] ; then # ZSH array indexes start at 1, herbstluftwm tag indexes start # at zero, so subtract one to match them. j=$(( $i - 1 )) # first check if the tag is locked to some monitor. # if so, first focus the monitor hc keybind "$Mod-$key" chain \ , silent substitute M tags."$j".my-monitor focus_monitor M \ , use_index "$j" hc keybind "$Mod-Shift-$key" move_index "$j" fi done # theme hc attr theme.tiling.reset 1 hc attr theme.floating.reset 1 hc set frame_border_active_color '#3d3d3d' hc set frame_border_normal_color '#222222' hc set frame_bg_normal_color '#111111' hc set frame_bg_active_color '#263f1f' hc set frame_border_width 0 hc set window_border_width 2 hc set window_border_inner_width 0 hc set window_border_normal_color '#222222' hc set window_border_active_color '#1f3f3f' hc set window_border_inner_color '#111111' hc set always_show_frame 0 hc set frame_gap 30 # Add overlapping window borders hc set window_gap 30 hc set frame_padding -30 hc set frame_bg_transparent 1 hc set smart_window_surroundings 0 hc set smart_frame_surroundings 0 hc set mouse_recenter_gap 0 hc set swap_monitors_to_get_tag 0 hc set update_dragged_clients 1 # rules hc unrule -F hc rule focus=on # normally focus new clients hc rule class=Emacs tag=dev index=0 switchtag=on hook=emacs hc rule class=URxvt tag=dev index=1 switchtag=on hook=urxvt hc rule class~'Conkeror|Firefox|Chromium' tag=web index=0 switchtag=on hc rule class=Pinentry pseudotile=on hc rule class=Alsaplayer pseudotile=on hc rule class=Gcr-prompter pseudotile=on 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 # unlock, just to be sure hc unlock herbstclient set tree_style '╾│ ├└╼─┐' ## Monitors # I have two monitors, each with a resolution of 1920x1080. hc set_monitors 1920x1080+0+0 # Pad the first monitor to make room for mowedline and trayer. hc pad 0 0 0 16 16 # Load layouts for the dev and web tags. hc load dev '(split horizontal:0.580:1 (clients max:0) (clients vertical:0))' hc load web '(clients max:0)' # Make sure the "Emacs" frame is selected. hc focus_edge left # Lock each tag to its specific monitor. lock-tag-to-monitor dev 0 lock-tag-to-monitor web 1 ## Other configurations # Load any other configuration files in # $HOME/.config/herbstluftwm/autostart.d so other programs can # configure parts of herbstluftwm to their needs (such as keybindings # for Rofi). if [ -d "${HOME}/.config/herbstluftwm/autostart.d" ]; then for f in ${HOME}/.config/herbstluftwm/autostart.d/?*.sh; do [ -x "$f" ] && source "$f" done unset f fi