Introduction
Continuing the framework laptop blog post series, where I first wrote about my impression of the framework laptop, then about what I had to do to fix EndeavourOS / Archlinux on it and lastely about the installation and configuration of some “core” softwares. This post is about my i3wm configuration that I have redone from scratch, heavily inspired by EndeavourOS one.
The TLDR; as usual, is look at my dotfiles :)
Mandatory screenshot:

Figure 1: My desktop screenshot
Be careful, this post is very long due to covering many topics. For this reason, I’m adding for the first time a table of content for this post:
- Introduction
- configuring i3wm
- Conclusion
Configuring i3wm
The basics
The basic settings, with comments that shouldn’t need more explaination:
# set the mod key to the winkey:
set $mod Mod4
# default i3 tiling mode:
workspace_layout default
# Back and forth between workspaces
workspace_auto_back_and_forth yes
#border indicator on windows:
new_window pixel 1
# Set inner/outer gaps
gaps inner 3
gaps outer 2
# Use Mouse+$mod to drag floating windows to their wanted position
floating_modifier $mod
Workspaces
Workspaces naming convention
First, let’s define the different workspaces. I have both “personal” and “work” related workspace. To visualy separate them, I add “🌢” in front of the “name” of each work related workspace (yes there is a connection^^).
I use 10 workspaces each, they are the same: browsers (web and gemini, in tabbed mode), “terminal”, emails, chats, files, 7, 8, 9, 10.
## Personal workspaces
set $ws1 "1:"
set $ws2 "2:"
set $ws3 "3:✉️"
set $ws4 "4:"
set $ws5 "5:"
set $ws6 "6:"
set $ws7 "7:7"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10"
## Work workspaces
set $wsw1 "11:🌢"
set $wsw2 "12:🌢"
set $wsw3 "13:🌢✉️"
set $wsw4 "14:🌢"
set $wsw5 "15:🌢"
set $wsw6 "16:🌢"
set $wsw7 "17:🌢7"
set $wsw8 "18:🌢8"
set $wsw9 "19:🌢9"
set $wsw10 "20:🌢10"
Assigning workspaces to screens
To assign workspace to specific screens, it is easy:
workspace $ws1 output DP1
workspace $ws2 output DP2-2
workspace $ws3 output DP2-2
workspace $ws4 output eDP1
workspace $wsw1 output DP1
workspace $wsw2 output DP2-2
workspace $wsw3 output DP1
workspace $wsw4 output DP2-1
Switching between workspaces
Of course, naming is fine, but more important is to switch between them. To switch between personal workspaces, I’m using the window
($mod
) key and a number key. To switch between work workspaces, I’m using the window
($mod
) key + Alt
(Mod1
) key + a number key.
# switch to workspace
## Personal workspaces
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 $ws10
## Work workspaces
bindsym $mod+Mod1+1 workspace $wsw1
bindsym $mod+Mod1+2 workspace $wsw2
bindsym $mod+Mod1+3 workspace $wsw3
bindsym $mod+Mod1+4 workspace $wsw4
bindsym $mod+Mod1+5 workspace $wsw5
bindsym $mod+Mod1+6 workspace $wsw6
bindsym $mod+Mod1+7 workspace $wsw7
bindsym $mod+Mod1+8 workspace $wsw8
bindsym $mod+Mod1+9 workspace $wsw9
bindsym $mod+Mod1+0 workspace $wsw10
Moving workspaces around
To move workspaces between screens (outputs), window
($mod
) + shift
+ Left/Right/Up/Down:
# Move workspaces to output
bindsym $mod+Shift+Mod1+Left move workspace to output left
bindsym $mod+Shift+Mod1+Right move workspace to output right
bindsym $mod+Shift+Mod1+Up move workspace to output up
bindsym $mod+Shift+Mod1+Down move workspace to output down
Switch between workspace
To replicate the usual “alt+tab” but for workspaces, I use window
+ tab
(with shift
to go backward).
# switch/iterate between workspaces
bindsym $mod+Tab workspace next
bindsym $mod+Shift+Tab workspace prev
Renaming workspace
I very often rename workspace, specially for work related workspace, I usually rename them with a customer or specific project name. For this I’m using window
+ x
to rename personal workspace (ask for name and use it as is) and window
+ alt
+ x
to rename a work related workspace (use the name with “🌢” before).
# rename workspace
bindsym $mod+x exec "i3-input -F 'move container to workspace %s; workspace %s' -P 'Rename workspace to: '"
bindsym $mod+Mod1+x exec "i3-input -F 'move container workspace 🌢%s; workspace 🌢%s' -P 'Rename workspace to: 🌢'"
Open new empty workspace
In case all workspace are taken (never really happens…), I use window
+ shift
+ n
to open a new empty one using a script called empty_workspace
. The script came with the i3wm configuration of EndeavourOS, thanks to them!
# open new empty workspace
bindsym $mod+Shift+n exec ~/.config/i3/scripts/empty_workspace
The empty_workspace
script:
#!/usr/bin/env bash
MAX_DESKTOPS=20
WORKSPACES=$(seq -s '\n' 1 1 ${MAX_DESKTOPS})
EMPTY_WORKSPACE=$( (i3-msg -t get_workspaces | tr ',' '\n' | grep num | awk -F: '{print int($2)}' ; \
echo -e ${WORKSPACES} ) | sort -n | uniq -u | head -n 1)
i3-msg workspace ${EMPTY_WORKSPACE}
Containers / Window
Changing focus between windows
Using window
+ Left/Up/Right/Down keys:
# change focus
bindsym $mod+Left focus left
bindsym $mod+Down focus down
bindsym $mod+Up focus up
bindsym $mod+Right focus right
Also, for the usual “alt+tab” behaviour:
# alt tab old school style
bindsym Mod1+Tab focus right
bindsym Mod1+Shift+Tab focus left
For focusing the parent container:
# focus the parent container
bindsym $mod+a focus parent
Moving to the latest “urgent” window
# urgent
bindsym $mod+Escape [urgent=latest] focus
Move focused window around
window
($mod
) + shift
+ a Left/Up/Down/Right to windows around.
# move focused window
bindsym $mod+Shift+Left move left
bindsym $mod+Shift+Down move down
bindsym $mod+Shift+Up move up
bindsym $mod+Shift+Right move right
Moving focused containers (windows) between workspaces
Easy, window
($mod
) + shift
+ a key number to move to a personal workspace. window
($mod
) + alt
(Mod1
) + shift
+ a key number to move to a work workspace.
# move focused container to workspace
## Personal workspaces
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 $ws10
## Work workspaces
bindsym $mod+Mod1+Shift+1 move container to workspace $wsw1
bindsym $mod+Mod1+Shift+2 move container to workspace $wsw2
bindsym $mod+Mod1+Shift+3 move container to workspace $wsw3
bindsym $mod+Mod1+Shift+4 move container to workspace $wsw4
bindsym $mod+Mod1+Shift+5 move container to workspace $wsw5
bindsym $mod+Mod1+Shift+6 move container to workspace $wsw6
bindsym $mod+Mod1+Shift+7 move container to workspace $wsw7
bindsym $mod+Mod1+Shift+8 move container to workspace $wsw8
bindsym $mod+Mod1+Shift+9 move container to workspace $wsw9
bindsym $mod+Mod1+Shift+0 move container to workspace $wsw10
Floating and resizing
Toggle tiling / floating of a window:
# toggle tiling / floating
bindsym $mod+Shift+f floating toggle
Switch focus between tiling and floating windows:
# change focus between tiling / floating windows
bindsym $mod+space focus mode_toggle
Resizing is done via window
+ shift
+ s
and then arrow keys or h/j/k/l:
# 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 j resize shrink width 10 px or 10 ppt
bindsym k resize grow height 10 px or 10 ppt
bindsym l resize shrink height 10 px or 10 ppt
bindsym h 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
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+Shift+s mode "resize"
Scratchpad
From time to time, I like putting windows as scratchpad windows, for this I use window
(+ shift
) + ²
:
# scratchpad
bindsym $mod+Shift+twosuperior move scratchpad
bindsym $mod+twosuperior scratchpad show
Layouts
Spliting layout
I like creating a horizontal split with window
+ v
and a vertical split with window
+ h
. It’s the opposite of the default, but it makes more sense for me^^.
# split in horizontal orientation
bindsym $mod+h split v
# split in vertical orientation
bindsym $mod+v split h
Workspace layout
Layout selection is done via window
+ s
(stacking), window
+ z
(tabbed) or window
+ e
(split toggle):
# change container layout (stacked, tabbed, toggle split)
bindsym $mod+s layout stacking
bindsym $mod+z layout tabbed
bindsym $mod+e layout toggle split
i3bar
config
Basically, having the i3bar at the top of each screen. System tray displayed on the primary screen (in my case the central one). For the status part, I use i3blocks (see next paragraph).
bar {
font pango: Noto Sans Regular 10
status_command i3blocks -c ~/.config/i3/i3blocks.conf
position top
tray_output primary
tray_padding 0
strip_workspace_numbers yes
}
i3blocks
My status looks like this:

Figure 2: Screenshots of i3 status with i3blocks
This example includes the system tray, which represent the last 4 icons, from right to left: syncthing, redshift, nm-applet and blueman-applet.
I’m using mostly default stuff from i3blocks, except 2 custom scripts:
- One for checking I’ve made recent backup (more on that later in a blog post series about backup with borg)
- One for toggling notification, see below.
[dunst]
command=~/workspace/contrib/i3blocks-contrib/dunst/dunst
format=json
interval=-1
The ~/workspace/contrib/i3blocks-contrib/dunst/dunst
comes from i3blocks-contrib and can be found here.
QoL improvements with rofi
All my rofi configuration can be found on sourcehut
Application launcher
To launch application, I start the launcher with window
+ d
:

Figure 3: Screenshots of the application launcher
bindsym $mod+d exec rofi -modi drun -show drun -config ~/.config/rofi/rofidmenu.rasi
Window selector
Open a window listing all windows (in any workspace) with filter to quickly jump to it. Example:

Figure 4: Screenshots of the window selector
bindsym $mod+t exec rofi -show window -config ~/.config/rofi/rofidmenu.rasi
Workspace selector
Open a window listing all workspaces with filter to quickly jump to it. Example:

Figure 5: Screenshots of the workspace selector
# keybinding in fancy rofi (automated):
bindsym $mod+mod1+Tab exec ~/.config/i3/scripts/keyhint-2
Clipboard

Figure 6: Screenshots of the clipboard selector
bindsym $mod+c exec --no-startup-id rofi -modi "clipboard:greenclip print" -show clipboard -config ~/.config/rofi/rofidmenu.rasi
Password store integration

Figure 7: Screenshots of the password selector
Configuration or rofi-pass:
mkdir ~/.config/rofi-pass && cp /etc/rofi-pass.conf ~/.config/rofi-pass/config
And i3wm configuration:
bindsym $mod+p exec /usr/bin/rofi-pass
Power menu
The power menu allow easy select to hibernate, suspend, lock, logout, reboot or shutdown:

Figure 8: Screenshots of the power menu
bindsym $mod+Shift+e exec ~/.config/i3/scripts/powermenu
Power profiles switcher
The power profiles menu allow easy select different power profiles: performance, balanced or power saver:

Figure 9: Screenshots of the power menu
bindsym $mod+Shift+p exec ~/.config/i3/scripts/power-profiles
Some keybinds
Audio related
Audio specific keybind:
# volume
bindsym XF86AudioRaiseVolume exec amixer -D pulse sset Master 5%+ && pkill -RTMIN+1 i3blocks
bindsym XF86AudioLowerVolume exec amixer -D pulse sset Master 5%- && pkill -RTMIN+1 i3blocks
# gradular volume control
bindsym $mod+XF86AudioRaiseVolume exec amixer -D pulse sset Master 1%+ && pkill -RTMIN+1 i3blocks
bindsym $mod+XF86AudioLowerVolume exec amixer -D pulse sset Master 1%- && pkill -RTMIN+1 i3blocks
# mute
bindsym XF86AudioMute exec amixer sset Master toggle && killall -USR1 i3blocks
# audio control
bindsym XF86AudioPlay exec playerctl play
bindsym XF86AudioPause exec playerctl pause
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioPrev exec playerctl previous
Backlight control
Remember to fix the backlight control as described in the previous post.
# Backlight control
bindsym XF86MonBrightnessUp exec xbacklight +5 && notify-send "Brightness - $(xbacklight -get | cut -d '.' -f 1)%"
bindsym XF86MonBrightnessDown exec xbacklight -5 && notify-send "Brightness - $(xbacklight -get | cut -d '.' -f 1)%"
Screenshots
3 possibility to take screenshots with scrot
: Full screenshots (all screens) with Print Screen
, screenshot of the focused window with window
+ Print Screen
or a screenshot of a manually selected area with shift
+ Print Screen
(and then just click and select the area to screenshot):
bindsym Print exec scrot ~/Téléchargements/screenshots/%Y-%m-%d-%T-screenshot.png && notify-send "Screenshot saved"
bindsym $mod+Print exec scrot --focus ~/Téléchargements/screenshots/%Y-%m-%d-%T-screenshot.png && notify-send "Screenshot saved"
bindsym --release Shift+Print exec scrot --select ~/Téléchargements/screenshots/%Y-%m-%d-%T-screenshot.png && notify-send "Screenshot saved"
Applications
Open app via Keybinds
Just giving an example, it’s that easy:
bindsym $mod+w exec /usr/bin/firefox-nightly -P bacardi55
Bind app to workspaces
I have some app being binded to specific workspace:
# bind program to workspace and focus to them on startup:
assign [class="(?i)firefox-nightly"] $ws1
assign [class="(?i)firefox"] $wsw1
assign [class="Thunar"] $ws5
assign [class="Emacs"] $ws2
# automatic set focus new window if it opens on another workspace than the current:
for_window [class=Xfce4-terminal] focus
for_window [class=(?i)firefox] focus
for_window [class=Thunar] focus
Floating rules
For some specific windows, I want them to be automatically floating:
for_window [class="Galculator" instance="galculator"] floating enable
for_window [class="Pavucontrol" instance="pavucontrol"] floating enable
for_window [window_role="About"] floating enable
Others
There are other things in my config, such as autostarted programs, theming (will be part of another post regarding the global “theming” of my laptop) or keybind to open window (self explanatory based on the documention). To have a full view, feel free to read the full configuration file on source hut.