dfzf redefines how you interact with windows in sway and i3, letting you switch windows with fzf
, sorted by recency — no more cycling or losing your mind. Unlike traditional workspaces or tabbing, it frees you from relying on mental cartography, using name- and time-based navigation to keep access effortless, even with dozens of windows.
No more mental gymnastics. Just type to fuzzy-match and access recent windows first — eventually, you’ll rely solely on dfzf-windows for seamless navigation.
Click to expand description of the GIF
This GIF shows dfzf-windows in action:
- List the current windows, recent ones come first
- Inspect the windows previews, including terminal
- Mark the windows either as "urgent" or "important"
- Kills windows one by one until none are left
- Bonus: Notice a bit of "inception" in the
dfzf-windows
preview...
Using dfzf
invites you to rethink how you use your window manager:
- No more tabs — Use
dfzf-windows
to manage windows efficiently, without relying on tabbed layouts. - No more workspaces — Replace static workspaces with a flexible color tagging system. Assign multiple tags to a single window for powerful cross-grouping and faster navigation.
- No more bars — Free up screen space and ditch the traditional bar. Invoke minimal, dedicated popups for clock, system monitor, system info, wifi, and more — only when needed.
These make your desktop cleaner, more dynamic, and easier to manage — with more pixels dedicated to what actually matters — always full-screen !
- ⏱️ Instant access — switch to any window instantly, regardless of how many are open.
- 🔍 Recent-first navigation — fuzzy-search windows by name, with recent ones prioritized.
- 🧠 Low cognitive load — remember what and when, not where.
dfzf relies on dfzf-daemon
to track window focus changes via IPC, storing the order of recently used windows in their marks. It uses dfzf-mark
to add or remove marks, such as "important" marks (shown in red). And don't worry if you're already using marks — dfzf won't interfere with your existing setup.
Just make sure the daemon is running when you try dfzf for the first time!
dfzf
is more than a window switcher — it's a full toolkit for your desktop, built with speed, consistency, and minimalism in mind:
Tool | Description | i3 | Sway |
---|---|---|---|
dfzf-windows |
Navigate windows by title or time | ✅ | ✅ |
dfzf-scrollbacks |
Fuzzy-search within all your terminals at once | ✅ | ✅ |
dfzf-launcher |
Launch desktop apps or cmds in terminal | ✅ | ✅ |
dfzf-notify |
Browse past notifications | ❌ | ✅ |
dfzf-tasks |
Manage caldav tasks | ✅ | ✅ |
dfzf-clipboard |
Searchable clipboard with image/text preview | ✅ | ✅ |
dfzf-password |
Copy and preview entries from pass | ✅ | ✅ |
dfzf-mail |
View, preview and delete emails | ✅ | ✅ |
dfzf-exit |
Logout, reboot, suspend, hibernate | ❌ | ✅ |
dfzf-tools |
Clock, calendar, top, wifi, bluetooth, fetch popup | ✅ | ✅ |
dfzf-hub |
Invoke other dfzf commnands | ✅ | ✅ |
dfzf-term |
Terminal management (kill/new/toggle/scratchpad) | ✅ | ✅ |
dfzf-git |
Smart git repository lazygit toggle | ✅ | ✅ |
Feature / Terminal | Kitty | Foot | Alacritty |
---|---|---|---|
dfzf-windows Terminal Preview |
✅ Full | ❌ Not supported | ❌ Not supported |
dfzf-scrollbacks Support |
✅ Full | ❌ Not supported | ❌ Not supported |
dfzf-clipboard Image Preview |
✅ Full | 🔻 Degraded | |
Press escape to kill popup |
✅ Full | ||
Everything else | ✅ Full | ✅ Full | ✅ Full |
Prerequisite
In general, dfzf needs:
- sway or i3, with default layout
tabbed
- fzf
- kitty version >= 0.42.1 OR alacritty OR foot
- jq version >= 1.7
- nerdfonts to display the glyphs (see nerdfont section)
- lazygit (for
dfzf-git
)
Moreover, each tool can have specific dependencies described in the Features
section.
Also be sure fzf
is accessible from sway/i3, by moving it to /usr/local/bin/
(instead of default ~/.cargo/bin
place)
or setup sway/i3 path correctly
#~/.config/sway/config
set $PATH /usr/local/bin:/opt/bin:$PATH
Download the releases
- Download/copy the binaries into
/usr/local/bin/
or anywhere in your PATH. - Download the deb package, and
sudo dpkg -i
it on debian/ubuntu.
Build/install dfzf-daemon
cd dfzf-utils
curl https://sh.rustup.rs -sSf | sh
rustup update nightly
cargo +nightly build --release
find dfzf-utils -type f -executable -name "dfzf-*" |xargs -I@ sudo cp @ /usr/local/bin/
Nerdfont
Glyph are used in some dfzf modules (windows, tasks). If you don't wan't them you can override the config that way:
#~/.config/dfzf/dfzf.conf
windows_glyph_rules_json='[{"glyph": ""}]'
You can install nerdfont by running this script (source). Also snap apps cannot access to .local/share/fonts
, reason I personally install them into ~/.fonts
instead.
#!/bin/bash
declare -a fonts=(
BitstreamVeraSansMono
CascadiaCode
CodeNewRoman
DroidSansMono
FiraCode
FiraMono
Go-Mono
Hack
Hermit
JetBrainsMono
Meslo
Noto
Overpass
ProggyClean
RobotoMono
SourceCodePro
SpaceMono
Ubuntu
UbuntuMono
)
version=$(curl -s 'https://api.github.com/repos/ryanoasis/nerd-fonts/releases/latest' | jq -r '.name')
fonts_dir="${HOME}/.fonts"
if [[ ! -d "$fonts_dir" ]]; then
mkdir -p "$fonts_dir"
fi
for font in "${fonts[@]}"; do
zip_file="${font}.zip"
download_url="https://github.com/ryanoasis/nerd-fonts/releases/download/${version}/${zip_file}"
echo "Downloading $download_url"
wget "$download_url"
unzip "$zip_file" -d "$fonts_dir"
rm "$zip_file"
done
find "$fonts_dir" -name 'Windows Compatible' -delete
fc-cache -fv
Sway configuration
exec --no-startup-id dfzf-daemon # reboot to make the daemon running
exec --no-startup-id copyq
exec mako # for the dfzf-notifs
exec swaymsg workspace 1, layout tabbed
workspace_auto_back_and_forth no
# FOR FOOT OR ALACRITTY
#set $term foot
#set $term alacritty
#set $dfzf_term foot --app-id=dfzf-popup -e
#bindsym $mod+Tab exec --no-startup-id $dfzf_term dfzf-windows
#bindsym $mod+l exec --no-startup-id $dfzf_term dfzf-hub
# FOR KITTY
set $term kitty -1
exec --no-startup-id kitty -1 --start-as hidden
exec --no-startup-id kitty -1 --instance-group dfzf --start-as hidden -o 'map escape close_window' -o 'listen_on=unix:/tmp/kitty-dfzf'
bindsym $mod+Tab exec --no-startup-id kitty -1 --class=dfzf-popup -e dfzf-windows
bindsym $mod+l exec --no-startup-id kitty -1 --instance-group dfzf --class=dfzf-popup -e dfzf-hub
bindsym $mod+n exec dfzf-term scratchpad $term
bindsym ctrl+slash exec dfzf-term toggle $term
bindsym shift+ctrl+slash exec dfzf-term kill $term
bindsym $mod+g exec dfzf-git
for_window [app_id="^dfzf-popup$"] floating enable, sticky enable, border pixel 6, exec dfzf-resize 65
# optional: hide the tabs
font pango:monospace 0.001
default_border none
default_floating_border none
titlebar_padding 1
titlebar_border_thickness 0
I3 configuration
exec --no-startup-id dfzf-daemon # reboot to make the daemon running
# make sure the workspace is tabbed by default
exec i3-msg workspace 1, layout tabbed
exec --no-startup-id copyq
workspace_auto_back_and_forth no
# FOR FOOT OR ALACRITTY
#set $term foot
#set $term alacritty
#set $dfzf_term foot --app-id=dfzf-popup -e
#bindsym $mod+Tab exec --no-startup-id $dfzf_term dfzf-windows
#bindsym $mod+l exec --no-startup-id $dfzf_term dfzf-hub
# FOR KITTY
set $term kitty -1
exec --no-startup-id kitty -1 --start-as hidden
exec --no-startup-id kitty -1 --instance-group dfzf --start-as hidden -o 'map escape close_window' -o 'listen_on=unix:/tmp/kitty-dfzf'
bindsym $mod+Tab exec --no-startup-id kitty -1 --class=dfzf-popup -e dfzf-windows
bindsym $mod+l exec --no-startup-id kitty -1 --instance-group dfzf --class=dfzf-popup -e dfzf-hub
bindsym $mod+n exec dfzf-term scratchpad $term
bindsym ctrl+slash exec dfzf-term toggle $term
bindsym shift+ctrl+slash exec dfzf-term kill $term
bindsym $mod+g exec dfzf-git
for_window [class="^dfzf-popup$"] floating enable, sticky enable, border pixel 6, exec dfzf-resize 65
# optional: hide the tabs
font pango:monospace 0
default_border none
default_floating_border none
# reset font for the bar
bar {
font pango:monospace 10 # needed
status_command i3status
}
user configuration [optional]
you can override default configurations:
# ~/.config/dfzf/dfzf.conf
#kitty only: regexp to match the prompt
windows_prompt_pattern="^[>$%] "
#remove pattern from the window's title
windows_title_rm_pattern=' —[^—]*?— Mozilla Firefox'
# rename the application classes
windows_app_id_map_json='{"evolution": "mail", "kitty": "terminal", "jetbrains-idea-ce": "jetbrains"}'
# assign glyphs to application classes
windows_glyph_rules_json='[
{ "field": "name", "regex": "vim\\b", "glyph": " " },
{ "field": "app_id", "regex": "terminal", "glyph": " " },
{ "field": "app_id", "regex": "firefox", "glyph": " " },
{ "field": "app_id", "regex": "jetbrains", "glyph": " " },
{ "field": "app_id", "regex": "gimp", "glyph": " " },
{ "field": "app_id", "regex": "thunar|nautilus", "glyph": " " },
{ "field": "app_id", "regex": "thunderbird|evolution|geary|mailspring|k9mail|mail", "glyph": " " },
{ "glyph": " " }
]'
# override the exit list and respective commands
exit_options=(
"l: Lock (swaylock)"
"e: Restart GDM"
"s: Lock and Suspend"
"r: Reboot"
"S: Shutdown"
"h: Hibernate"
)
exit_cmd_l='swaylock -e -F -f -k -c 000000'
exit_cmd_e='sudo /usr/bin/systemctl restart gdm'
exit_cmd_s='swaylock -e -F -f -k -c 000000 && systemctl suspend'
exit_cmd_r='sudo reboot'
exit_cmd_S='shutdown now'
exit_cmd_h='sudo /bin/systemctl hibernate'
tools_clock_cmd="tty-clock -c -C 4 -s"
tools_calendar_cmd="~/.venv/3.11.6/bin/khal interactive"
tools_top_cmd="gotop"
# hub user customization
hub_options=(
"a: Audio"
"b: Bluetooth"
"c: Clipboard"
"d: Date"
"e: Exit"
"f: Fetch"
"g: Gotop"
"k: Calendar"
"l: Launcher"
"m: Mail"
"n: Notif"
"p: Password"
"s: Scrollback"
"t: Task"
"w: Wifi"
"i: Iotop"
"q: Pomatez"
)
# hub custom command mappings
hub_cmd_a='dfzf-exec exec pavucontrol'
hub_cmd_b='dfzf-tools bluetooth'
hub_cmd_c='dfzf-clipboard'
hub_cmd_d='dfzf-tools clock'
hub_cmd_e='dfzf-exit'
hub_cmd_f='dfzf-tools fetch'
hub_cmd_g='dfzf-tools top'
hub_cmd_k='dfzf-tools calendar'
hub_cmd_l='dfzf-launcher'
hub_cmd_m='dfzf-mail'
hub_cmd_n='dfzf-notifs'
hub_cmd_p='dfzf-password'
hub_cmd_s='dfzf-scrollbacks'
hub_cmd_t='dfzf-tasks'
hub_cmd_w='dfzf-tools wifi'
hub_cmd_i='TERM=xterm sudo /usr/sbin/iotop -o'
hub_cmd_q="pomatez || dfzf-windows-load|rg pomatez|sed -Ez 's/.*#([0-9]+).*/\1/'|xargs -I@ dfzf-exec '[con_id=@]' focus"
Kitty configuration [optional]
#~/.config/kitty/kitty.conf
confirm_os_window_close 0
allow_remote_control yes
listen_on unix:/tmp/kitty
Windows terminal preview in kitty:
the terminal preview compares the i3/sway window title with the kitty title. In some case there is duplicates, and we cannot determinate the right terminal. So the current hack is to add 2 random characters to the title so that they get unique. For that, you will have to disable kitty title handling and tweak the shell title. Here for zsh:
#~/.config/kitty/kitty.conf
shell_integration no-title
tweak zsh:
# ~/.oh-my-zsh/lib/termsupport.zsh
case "$TERM" in
cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty*|st*|foot*|contour*)
print -Pn "\e]2;${2:q} /$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 2)\a" # set window name
print -Pn "\e]1;${1:q} /$(< /dev/urandom tr -dc A-Za-z0-9 | head -c 2)\a" # set tab name
Firefox [optional]
Install the below extensions:
- tabs are windows
- hostname in windows title
I use this template
{title} - {href} —
, together with this variable in dfzf config to bring perfect ff titles.
# remove pattern from the window's title
windows_title_rm_pattern=' —[^—]*?— Mozilla Firefox'
Chromium [optional]
Install the below extensions:
- new-tab-new-window
- either URL in title or Title morph
Windows
- windows ordered by last access
- cycle previous window
- terminal scrollback preview (kitty only)
keybindings:
-
Return
: focus window -
ctrl-b
: toggle color blue -
ctrl-g
: toggle color green -
ctrl-o
: toggle color orange -
ctrl-r
: toggle color red -
B
: filter color blue -
G
: filter color green -
O
: filter color orange -
R
: filter color red -
ctrl-k
: kill window -
ctrl-u
: toggle urgent (yellow color) -
ctrl-i
: toggle important (red color) -
ctrl-j
: preview windows -
escape
: return to current windows (works after previews) -
ctrl-t
: will toggle tilling to the multi-selected windowssudo apt install jq ripgrep
Scrollbacks
Scrollbacks let you fuzzy-search across all your terminal histories (Kitty only) and focus the right one — great for digging up lost work from vague command memories.
sudo apt install ripgrep
Hub
The hub lets you launch any dfzf command with a single keystroke — one keybinding to rule them all.
Clipboard
- list latest mails
- preview text mails
ctrl-j
: preview html mails in the browser
sudo apt install jq himalaya
Notifications
- list notification ordered
Return
: notification actionctrl-k
: kill notificationctrl-h
: toggle notif history
sudo apt install jq mako-notifier
Tasks
Manage caldav tasks:
ctrl-t
: new taskctrl-e
: edit taskctrl-k
: delete taskctrl-d
: set status done for taskctrl-r
: sync tasks with remote caldavctrl-l
: choose the collection
pip install todoman vdirsyncer
Tools
Set of tools not related with fzf, but useful even to drop the sway bar.
- resource usage: top, htop, gotop ...
- calendar: khal, calcurse ...
- clock: tty-clock ...
- wifi
- bluetooth
- fetch: fastfetch
Terminal Management
dfzf-term
provides two terminal integrations for different work contexts: project-specific tasks in companion terminals and general tasks in a shared global terminal.
Companion Terminals (project-specific work):
- One terminal per window, attached to any application (IDE, browser, etc.)
- Auto-detects working directory: JetBrains
[/path/to/project]
, Neovim- NVIM
suffix, Terminal path patterns, defaults to home - Toggles between split vertical and stacked layouts (stacked allows fullscreen switching between windows)
Ctrl + /
- Toggle layout |Shift + Ctrl + /
- Kill the companion- Automatically moves away any non-companion windows that might be added inadvertently during toggle operations
Global Terminal (general tasks):
- Single floating scratchpad terminal shared across workspaces
- 90% screen size, centered and floating
dfzf-term scratchpad [terminal_command]
- Toggle visibility- Works across sway/i3, independent of companion terminals
Git Repository Management
`dfzf-git` provides intelligent git repository integration with lazygit in a scratchpad terminal.Smart Repository Detection:
- Automatically detects git repository from focused window context
- Extracts directory paths from window titles (JetBrains
[/path/to/project]
, Neovim- NVIM
suffix, etc.) - Recursively searches upward for
.git
folder from detected directory - Falls back to current working directory if no git repository found from window context
Scratchpad Integration:
- Single floating lazygit terminal shared across workspaces
- 90% screen size, centered and floating
dfzf-git
- Toggle lazygit in detected git repository- Automatically opens lazygit in the root of the detected git repository
- Works across sway/i3, uses
dfzf-git
app_id to avoid conflicts with other terminals
Example Usage:
# Bind to a key (e.g., Alt+g)
bindsym $mod+g exec dfzf-git
dfzf
is the combination ofd
menu andfzf
- dfzf-daemon comes from i3-back
- dfzf-launcher comes from sway-launcher-desktop
- wofi-scripts has inspired dfzf-windows
- swayr: a window-switcher & more for sway
- i3-tools: switch to previous window
This project is licensed under the GNU General Public License v3.0.