Lightweight and a delight: i3 tiling window manager

  Last modified on Sunday 16 July 2017

PROJECT: The Lifecycle of Debian Objects .: As a former Fluxbox and Openbox user I can understand the love for a lightweight, minimal window manager where I can "paint" my applications across the screen. I was curious about tiling window managers but never quite grokked the advantage from screenshots. Seeing consoles arranged in a grid made me think tmux a better choice for that task, and why would I want to watch a video in a reduced square in the corner of a screen?

But then I tried i3 and found my new desktop ...

Still want to use a mouse here and here? No problem! Provides a statusbar, but you can swap it out for an alternative or run none at all.

Install and configure on Debian ...

Let's go!

Starting out I find myself mostly happy with the default keybindings and behaviour; making only a few adjustments and additions to my configuration.


Download the i3 metapackage and a few desktop utilities ...

  • dunst - lightweight notification daemon
  • volnoti - volume notification (built separately)
  • rofi - dynamic application launcher + window selector
  • nm-applet - network monitor and control (provided by network-manager-gnome)
  • scrot - screenshots
  • lximage-qt - image viewer
  • urxvt - terminal
$ sudo apt install i3 dunst rofi network-manager-gnome scrot lximage-qt rxvt-unicode-256color

Countdown to launch

In my ~/.xinitrc I add a few tasks before launching the window manager.

Load config parameters for X client applications, disable screen blanking, and empty the trash ...

# Config parameters for X client applications
[ -f ~/.Xresources ] && xrdb -merge ~/.Xresources

# Disable DPMS and turn off screen blanking
xset s off -dpms

# Janitor
[ -d ~/.local/share/Trash ] && rm -rf ~/.local/share/Trash/*

Start applications ...

  • dldsply - detect and - if present - configure a second display
  • i3wm_conf - build a config at runtime for i3wm
  • keyboardconf - bind commands to keys and load key mappings
  • nm-applet - network-manager utility
  • volnoti - volume notification
  • urxvt - terminal
# Applications
~/bin/dldsply -r &
~/bin/i3wm_conf &
~/bin/keyboardconf &
sleep 2
[ -x /usr/bin/nm-applet ] && nm-applet &
volnoti -t 2 &
urxvt &

Launch i3!

# Start window manager
exec i3

Source for startup scripts: homebin/dldsply; homebin/i3wm_conf; and homebin/keyboardconf


Window manager configuration file is ~/.config/i3/config, which i3 offers to generate at first launch. A few changes that I make from the i3 defaults ...

Windows and Workspaces

Remove the default tabs from windows and replace them with thin coloured bars by reducing window title font size to zero ...

font pango:monospace 0

... and set colours for windows ...

# Colours
# * class                 border  backgrd text    indicator
client.focused            #3daee9 #3daee9 #ffffff #2e9ef4
client.focused_inactive   #1cdc9a #1cdc9a #ffffff #484e50
client.unfocused          #4d4d4d #4d4d4d #ffffff #292d2e
client.urgent             #2f343a #900000 #ffffff #900000

Workspace defaults to a tabbed layout for windows, with hotkeys for toggling between different layouts ...

# Layout mode
workspace_layout tabbed

# Change layout (stacked, tabbed, toggle split)
bindsym $mod+s layout stacking
bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split


Breeze is the default Qt style of KDE Plasma with good support for both Qt and GTK applications. More: It is a Breeze to make QT and GTK applications look good


Create a hotkey to open terminals ...

# Start a terminal
bindsym $mod+Return exec urxvt

Before running the dunst notification daemon for the first time, create a default config ...

$ zcat /usr/share/doc/dunst/dunstrc.example.gz > ~/.config/dunst/dunstrc

Start notifications and launcher in the background ...

# Start dunst - lightweight notification-daemon
exec --no-startup-id dunst -config ~/.config/dunst/dunstrc

# Start rofi - window switcher, run dialog, and dmenu replacement
bindsym $mod+F2 exec --no-startup-id rofi -monitor -1 -show run
bindsym $mod+Tab exec --no-startup-id rofi -monitor -1 -show window

Create hotkeys for screenshots ...

# Screenshots using scrot + lximage-qt
# * desktop image
bindsym --release Print exec --no-startup-id scrot \
'%Y-%m-%dT%H%M%S.png' -e 'mv $f ~/Downloads && lximage-qt ~/Downloads/$f'
bindsym --release $mod+F4 exec --no-startup-id scrot \
'%Y-%m-%dT%H%M%S.png' -e 'mv $f ~/Downloads && lximage-qt ~/Downloads/$f'
# * active window image
bindsym --release Shift+Print exec --no-startup-id scrot -d 4 -u -z \
'%Y-%m-%dT%H%M%S.png' -e 'mv $f ~/Downloads && lximage-qt ~/Downloads/$f'
bindsym --release Shift+F4 exec --no-startup-id scrot -d 4 -u -z \
'%Y-%m-%dT%H%M%S.png' -e 'mv $f ~/Downloads && lximage-qt ~/Downloads/$f'

Automatically put clients on specific workspaces ...

# Assign torrent client to workspace 10
assign [instance="transmission-qt"] 10
# Assign music player to workspace 10
assign [class="Rhythmbox"] 10

Volume control and notification is a combination of pavucontrol, volnoti, and xbindkeys linked together in a shell script.


Screen locks are handled by i3lock. Pick an image to serve as the lock splashscreen (example: ~/.i3lock.png). Command systemctl deals with system suspend/reboot/shutdown ...

set $Locker i3lock -i ~/.i3lock.png && sleep 1
set $mode_system System (l) lock, (e) logout, (s) suspend, (r) reboot, \
(Shift+s) shutdown
mode "$mode_system" {
bindsym l exec --no-startup-id $Locker, mode "default"
bindsym e exec --no-startup-id i3-msg exit, mode "default"
bindsym s exec --no-startup-id $Locker && sync && systemctl suspend, \
mode "default"
bindsym r exec --no-startup-id systemctl reboot, mode "default"
bindsym Shift+s exec --no-startup-id systemctl poweroff -i, mode "default"
# back to normal: Enter or Escape
bindsym Return mode "default"
bindsym Escape mode "default"
bindsym $mod+Pause mode "$mode_system"

Link: Shutdown, reboot, lock screen


The ~/.config/i3/config file has no provision for interpreting conditionals, so I put my default settings and conditions in separate files and generate an appropriate config at runtime using i3wm_conf.

a) If two displays are detected (laptop connected to external monitor) there is extra workspace configuration ...

# Automatically place workspaces on specific displays
# * external display =  PRIMARY
# * laptop display =    SECOND
workspace 1 output PRIMARY
workspace 10 output SECOND

Customize the included i3bar statusbar by adding text-based information snippets configured in ~/.config/i3/i3status.conf: system tray, battery status, system load and temperature, and time.

Start i3bar on the external (primary) display and a secondary statusbar on the other display ...

bar {
output PRIMARY
position top
status_command i3status --config ~/.config/i3/i3status.conf
font pango:Terminus 11px
colors {
        focused_workspace #3daee9 #3daee9 #ffffff
        inactive_workspace #4d4d4d #4d4d4d #ffffff

bar {
output SECOND
position top
tray_output none
status_command i3status --config ~/.config/i3/i3status-small.conf
font pango:Terminus 11px
colors {
        focused_workspace #3daee9 #3daee9 #ffffff
        inactive_workspace #4d4d4d #4d4d4d #ffffff

b) If only a single display ...

bar {
position top
status_command i3status --config ~/.config/i3/i3status.conf
font pango:Terminus 11px
colors {
        focused_workspace #3daee9 #3daee9 #ffffff
        inactive_workspace #4d4d4d #4d4d4d #ffffff


With some scripting and a few extra applications it all rolls together as a lightweight and delightful custom desktop environment!

Happy hacking!

More • i3debianlinux