i3wm
i3wm configuration
Based from the auto-generated file created by i3-config-wizard(1).
Please see https://i3wm.org/docs/userguide.html for a complete reference!
Monitor configuration
At startup, only enable my built-in laptop screen.
#exec xrandr --output eDP-1 --auto --output DP-1 --off --output DP-2 --off
Having correct HiDPI requires ~/.Xresources
, see https://dougie.io/linux/hidpi-retina-i3wm/
export GDK_SCALE=2 export GDK_DPI_SCALE=0.5 export QT_AUTO_SCREEN_SCALE_FACTOR=1 export QT_FONT_DPI=140
Button configuration
i3 modifier
Make the Windows/Cmd/Whatever key the i3 modifier.
set $mod Mod4
Make CAPS lock a Ctrl
Make CAPS lock an additional Ctrl key.
exec setxkbmap -option ctrl:nocaps
Arrow mapping to letters
Use these keys for focus, movement, and resize directions when reaching for the arrows is not convenient.
set $left h set $down j set $up k set $right l
Appearance
Border
I don’t want no borders.
default_border normal 3 hide_edge_borders both
Font
This font is widely installed, provides lots of unicode glyphs, right-to-left text rendering and scalability on retina/hidpi displays (thanks to pango).
font pango:Fira Emacs Retina 8
Default
Make tabbed
the default layout:
workspace_layout tabbed
Wallpaper
Set the wallpaper:
exec --no-startup-id feh --bg-fill --geometry -0 --no-fehbg ~/Dropbox/images/wallpaper/homer-on-car.png
Mouse
Drag windows
Use Mouse+$mod
to drag floating windows to their wanted position
floating_modifier $mod
Natural scrolling
Enable natural scrolling for the trackpad.
exec xinput set-prop "Synaptics TM3276-022" "libinput Natural Scrolling Enabled" 1
Enable tapping
Enable click on tap.
exec xinput set-prop "Synaptics TM3276-022" "libinput Tapping Enabled" 1
Some bindings
Terminal
Start a terminal.
bindsym $mod+Return exec i3-sensible-terminal
Kill
Kill focused window.
bindsym $mod+Shift+q kill
Launcher
Start dmenu (a program launcher).
bindsym $mod+d exec dmenu_run
There also is the (new) i3-dmenu-desktop which only displays applications shipping a .desktop file. It is a wrapper around dmenu, so you need that installed.
bindsym $mod+d exec --no-startup-id i3-dmenu-desktop
Change focus
Use vim-like keys to change focus to a different window.
bindsym $mod+$left focus left bindsym $mod+$down focus down bindsym $mod+$up focus up bindsym $mod+$right focus right
Alternatively, you can use the cursor keys:
bindsym $mod+Left focus left bindsym $mod+Down focus down bindsym $mod+Up focus up bindsym $mod+Right focus right
Moving windows
Move focused window, with the same keys, combined with Shift
.
bindsym $mod+Shift+$left move left bindsym $mod+Shift+$down move down bindsym $mod+Shift+$up move up bindsym $mod+Shift+$right move right
Alternatively, you can use the cursor keys:
bindsym $mod+Shift+Left move left bindsym $mod+Shift+Down move down bindsym $mod+Shift+Up move up bindsym $mod+Shift+Right move right
Splitting containers
Split in horizontal orientation.
bindsym $mod+n split h
Split in vertical orientation.
bindsym $mod+v split v
Fullscreen
Enter fullscreen mode for the focused container
bindsym $mod+f fullscreen toggle
Container layout
Change container layout:
- Stacked
- Tabbed
- Toggle Horizontal <-> Vertical
bindsym $mod+s layout stacking bindsym $mod+w layout tabbed bindsym $mod+e layout toggle split
Floating
Toggle between tiling & floating.
bindsym $mod+Shift+space floating toggle
Change focus between tiling / floating windows.
bindsym $mod+space focus mode_toggle
Change focus
Focus the parent container.
bindsym $mod+a focus parent
Focus the child container.
bindsym $mod+d focus child
Workspaces
Define names for default workspaces for which we configure key bindings later on. We use variables to avoid repeating the names in multiple places.
set $ws1 "1" set $ws2 "2" set $ws3 "3" set $ws4 "4" set $ws5 "5" set $ws6 "6" set $ws7 "7" set $ws8 "8" set $ws9 "9" set $ws0 "0"
Switching workspace
Switch to workspace.
bindsym $mod+1 workspace $ws1 bindsym $mod+2 workspace $ws2 bindsym $mod+3 workspace $ws3 bindsym $mod+4 workspace $ws4 bindsym $mod+5 workspace $ws5 bindsym $mod+6 workspace $ws6 bindsym $mod+7 workspace $ws7 bindsym $mod+8 workspace $ws8 bindsym $mod+9 workspace $ws9 bindsym $mod+0 workspace $ws0
Moving containers
Move focused container to workspace.
bindsym $mod+Shift+1 move container to workspace $ws1 bindsym $mod+Shift+2 move container to workspace $ws2 bindsym $mod+Shift+3 move container to workspace $ws3 bindsym $mod+Shift+4 move container to workspace $ws4 bindsym $mod+Shift+5 move container to workspace $ws5 bindsym $mod+Shift+6 move container to workspace $ws6 bindsym $mod+Shift+7 move container to workspace $ws7 bindsym $mod+Shift+8 move container to workspace $ws8 bindsym $mod+Shift+9 move container to workspace $ws9 bindsym $mod+Shift+0 move container to workspace $ws0
Move workspaces between monitors
Source: https://unix.stackexchange.com/a/397270/9358
bindsym $mod+Ctrl+greater move workspace to output right bindsym $mod+Ctrl+less move workspace to output left
Choose monitor setup
I have 2 external monitors and using a mode to enable/disable them.
set $mode_monitors Monitor setup: (0) laptop only, (1) one external, (2) two external mode "$mode_monitors" { bindsym 0 exec --no-startup-id "xrandr --output DP-1 --off --output DP-2 --off", mode "default" #bindsym 1 exec --no-startup-id "xrandr --output eDP-1 --auto --output DP-1 --auto --left-of eDP-1 --output DP-2 --off", mode "default" #bindsym 2 exec --no-startup-id "xrandr --output eDP-1 --auto --output DP-1 --auto --left-of eDP-1 --output DP-2 --auto --left-of DP-1", mode "default" bindsym 2 exec --no-startup-id "xrandr --output eDP-1 --auto --pos 7680x0 --output DP-1 --scale 1x1 --mode 3840x2160 --pos 3840x0 --output DP-2 --scale 1x1 --mode 3840x2160 --pos 0x0", mode "default" # back to normal: Enter or Escape bindsym Return mode "default" bindsym Escape mode "default" } bindsym XF86Display mode "$mode_monitors"
Controlling i3 itself
Reload
Reload the configuration file.
bindsym $mod+Shift+c reload
Restart
Restart i3 inplace. This preserves your layout/session, can be used to upgrade i3.
bindsym $mod+Shift+r restart
Exit
Exit i3. It logs you out of your X session.
bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'"
Resizing
Resize window. You can also use the mouse for that.
mode "resize" { # These bindings trigger as soon as you enter the resize mode # Pressing left will shrink the window’s width. # Pressing right will grow the window’s width. # Pressing up will shrink the window’s height. # Pressing down will grow the window’s height. bindsym $left resize shrink width 10 px or 10 ppt bindsym $down resize grow height 10 px or 10 ppt bindsym $up resize shrink height 10 px or 10 ppt bindsym $right resize grow width 10 px or 10 ppt # same bindings, but for the arrow keys bindsym Left resize shrink width 10 px or 10 ppt bindsym Down resize grow height 10 px or 10 ppt bindsym Up resize shrink height 10 px or 10 ppt bindsym Right resize grow width 10 px or 10 ppt # back to normal: Enter or Escape or Mod1+r bindsym Return mode "default" bindsym Escape mode "default" bindsym $mod+r mode "default" } bindsym $mod+r mode "resize"
Shutdown
A mode to select the shutdown/reboot/etc.
From i3wm faq.
set $mode_system System (l) lock, (e) logout, (s) suspend, (h) hibernate, (r) reboot, (Shift+s) shutdown mode "$mode_system" { bindsym l exec --no-startup-id xset s activate, mode "default" bindsym e exec --no-startup-id i3-msg exit, mode "default" bindsym s exec --no-startup-id "xset s activate; systemctl suspend", mode "default" bindsym h exec --no-startup-id "i3lock; systemctl hibernate", mode "default" bindsym r exec --no-startup-id systemctl reboot, mode "default" bindsym Shift+s exec --no-startup-id systemctl poweroff, mode "default" # back to normal: Enter or Escape bindsym Return mode "default" bindsym Escape mode "default" } bindsym $mod+Delete mode "$mode_system"
TODO Auto-suspend and lock
https://wiki.archlinux.org/index.php/Power_management#Sleep_hooks https://www.reddit.com/r/i3wm/comments/9ebemt/locking_i3_when_lid_of_laptop_is_closed/ https://faq.i3wm.org/question/6665/lockscreen-after-closing-my-laptop.1.html https://github.com/ruudud/i3wm-scripts https://www.reddit.com/r/i3wm/comments/609vbj/systemd_lock_on_suspend_isnt_working/ https://www.reddit.com/r/archlinux/comments/6h6e0p/i3wm_laptop_power_management/
Dim the screen after three minutes of inactivity, lock the screen two minutes later using i3lock.
Disable DPMS when unlocked, the lock.sh
script will enable it again.
exec xset s 180 120 -dpms exec --no-startup-id xss-lock -n ~/.config/i3/dim-screen.sh -- ~/.config/i3/lock.sh
Brightness
From https://askubuntu.com/a/823691/850746 using light.
bindsym XF86MonBrightnessUp exec light -A 2 bindsym XF86MonBrightnessDown exec light -U 2
Media keys
I’m using to use pactl
.
bindsym XF86AudioRaiseVolume exec --no-startup-id "pactl info | grep 'Default Sink' | cut -d: -f2 | xargs -I{} pactl set-sink-volume {} +5%" bindsym XF86AudioLowerVolume exec --no-startup-id "pactl info | grep 'Default Sink' | cut -d: -f2 | xargs -I{} pactl set-sink-volume {} -5%" bindsym XF86AudioMute exec --no-startup-id "pactl info | grep 'Default Sink' | cut -d: -f2 | xargs -I{} pactl set-sink-mute {} toggle"
This changes the volume in pulseaudio
.
I also tried a better way, and to do it in alsa
, but it turned out to be less reliable and
also does not allow me to go over 100%, which is something desired.
bindsym XF86AudioMute exec amixer sset 'Master' toggle bindsym XF86AudioLowerVolume exec amixer -n sset 'Master' 5%- bindsym XF86AudioRaiseVolume exec amixer -n sset 'Master' 5%+
Screenshots
Create screenshots.
About the use of --release
, see https://www.reddit.com/r/i3wm/wiki/faq/screenshot_binding
Print
- Save screenshot of selected area to file.
Shift
+Print
- Save screenshot of selected area to clipboard.
Ctrl
+Print
- Save screenshot of whole screen to file.
bindsym Print exec "flameshot gui -p ~/Pictures" bindsym Shift+Print exec "flameshot gui" bindsym Ctrl+Print exec "flameshot full"
Status bar
Start i3bar
to display a workspace bar (plus the system information
i3status
finds out, if available).
bar {
tray_output primary
status_command bash ~/.config/i3status/wrapper.sh
}
Applets
Network manager
Start network manager applet.
exec --no-startup-id nm-applet
Dropbox
Start dropbox daemon.
exec --no-startup-id exec ~/.dropbox-dist/dropboxd
Window assignment
Assign some windows to a workspace. Just like I want them.
To get the class and instance, you can use xprop
. After clicking on the
window, you will see the following output:
WM_CLASS(STRING) = "irssi", "URxvt"
assign [class="Slack"] → $ws1 #assign [class="-terminal$"] → $ws2 assign [class="^emacs"] → $ws3 assign [class="^firefox$"] → $ws4 assign [class="^firefoxdeveloperedition$"] → $ws5
Floating windows
Some windows aren’t properly handled as floating by default.
- “zoom”
- This window is a little popup shown when someone has become the host of the meeting
for_window [title="^zoom$"] floating enable
Workspace assignment
Also each workspace has its preferred screen. By specifying multiple outputs, the first one available will be used.
workspace $ws1 output primary workspace $ws2 output primary workspace $ws3 output DP-1 primary workspace $ws4 output DP-1 primary workspace $ws5 output DP-2 DP-1 primary workspace $ws6 output DP-1 primary workspace $ws8 output DP-1 primary workspace $ws9 output DP-2 DP-1 primary
Dim script
Taken from /usr/share/doc/xss-lock/dim-screen.sh
.
#!/bin/bash # Example notifier script -- lowers screen brightness, then waits to be killed # and restores previous brightness on exit. ## CONFIGURATION ############################################################## # Brightness will be lowered to this value. min_brightness=0 # If your video driver works with xbacklight, set -time and -steps for fading # to $min_brightness here. Setting steps to 1 disables fading. fade_time=200 fade_steps=20 # If you have a driver without RandR backlight property (e.g. radeon), set this # to use the sysfs interface and create a .conf file in /etc/tmpfiles.d/ # containing the following line to make the sysfs file writable for group # "users": # # m /sys/class/backlight/acpi_video0/brightness 0664 root users - - # sysfs_path=/sys/class/backlight/intel_backlight/brightness # Time to sleep (in seconds) between increments when using sysfs. If unset or # empty, fading is disabled. fade_step_time=0.01 ############################################################################### get_brightness() { if [[ -z $sysfs_path ]]; then xbacklight -get else cat $sysfs_path fi } set_brightness() { if [[ -z $sysfs_path ]]; then xbacklight -steps 1 -set $1 else echo $1 > $sysfs_path fi } fade_brightness() { if [[ -z $sysfs_path ]]; then xbacklight -time $fade_time -steps $fade_steps -set $1 elif [[ -z $fade_step_time ]]; then set_brightness $1 else local level for level in $(eval echo {$(get_brightness)..$1}); do set_brightness $level sleep $fade_step_time done fi } trap 'exit 0' TERM INT trap "set_brightness $(get_brightness); kill %%" EXIT fade_brightness $min_brightness sleep 2147483647 & wait
Lock script
This was inspired by a Reddit comment.
The script is taken from xss-lock/transfer-sleep-lock-i3lock.sh.
## CONFIGURATION ############################################################## # Options to pass to i3lock bgcolor="282A36AF" textcolor="F8F8F2FF" vercolor="BD93F92F" wrongcolor="FF5555FF" ringcolor="BD93F9FF" keycolor="50FA7BFF" backcolor="FFB86CFF" datestr="%a, %b %d" # Use non-breaking spaces, text is cut at normal spaces i3lock_options="--ignore-empty-password --indicator --clock --composite --line-uses-inside \ --pass-media-keys --pass-screen-keys --date-str=$datestr \ --image=/home/toon/Dropbox/images/wallpaper/lego-technic-tiling.jpg --tiling \ --insidever-color=$bgcolor --insidewrong-color=$bgcolor --inside-color=$bgcolor \ --ringver-color=$vercolor --ringwrong-color=$wrongcolor --ring-color=$ringcolor \ --keyhl-color=$keycolor --bshl-color=$backcolor --verif-color=$textcolor \ --wrong-color=$textcolor --layout-color=$textcolor --time-color=$textcolor --date-color=$textcolor" #i3lock_options="--color=4c7899 --ignore-empty-password --show-failed-attempts --nofork" # Run before starting the locker pre_lock() { xset s off dpms 0 30 300 return } # Run after the locker exits post_lock() { xset s 180 120 -dpms return } ############################################################################### pre_lock # We set a trap to kill the locker if we get killed, then start the locker and # wait for it to exit. The waiting is not that straightforward when the locker # forks, so we use this polling only if we have a sleep lock to deal with. if [[ -e /dev/fd/${XSS_SLEEP_LOCK_FD:--1} ]]; then kill_i3lock() { pkill -xu $EUID "$@" i3lock } trap kill_i3lock TERM INT # we have to make sure the locker does not inherit a copy of the lock fd i3lock $i3lock_options {XSS_SLEEP_LOCK_FD}<&- # now close our fd (only remaining copy) to indicate we're ready to sleep exec {XSS_SLEEP_LOCK_FD}<&- while kill_i3lock -0; do sleep 0.5 done else trap 'kill %%' TERM INT i3lock -n $i3lock_options & wait fi post_lock
i3status
Configure i3status
.
general { output_format = "i3bar" colors = true interval = 1 color_good = "#33cc33" color_degraded = "#cccc33" color_bad = "#cc3333" } order += "wireless _first_" order += "ethernet _first_" order += "path_exists wireguard" order += "battery all" order += "load" order += "memory" order += "tztime local" wireless _first_ { format_up = "%quality 📡 %essid" format_down = "" color_good = "#ffffff" } ethernet _first_ { format_up = "🔗 %speed" format_down = "" } path_exists wireguard { format = "🔒" format_down = "" path = "/var/run/wireguard/tun0.sock" } battery all { format = "%percentage %status %remaining" format_down = "" status_chr = "🔌" status_bat = "🔋" status_unk = "🧲 " status_full = "⚡" path = "/sys/class/power_supply/BAT%d/uevent" low_threshold = 10 integer_battery_capacity = true } tztime local { format = "%Y-%m-%d @@ %H:%M:%S" } load { format = "📟 %5min" format_above_threshold = "🌋 %1min" } memory { format = "📪 %used" threshold_degraded = "10%" format_degraded = "📬 %free" } disk "/" { format = "%free" }
i3status-wrapper
A wrapper script for i3status
. Pipe the ouput of i3status
through
this script and it will replace @@
with a Unicode clock.
clock_symbol() { local c="🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🕛🕧🕐" local h=$(date +%-I) local m=$(date +%-M) local q=$(($m / 15)) local i=$((($h * 2) + ($q - $q/2))) echo ${c:$i:1} } i3status | while : do read line clock=$(clock_symbol) echo "${line/@@/$clock}" || exit 1 done