A keyboard shortcut utility for GNOME that lets you instantly show or hide any window with a single key press.
Ever wanted to hide a distracting window with one key press and bring it back just as quickly? window-toggle gives you a keyboard shortcut for each window, so you can:
- Hide a terminal or browser that's in your way
- Bring it back instantly with the same shortcut
- Works like "hide app" on macOS, but per-window
You have 3 terminals open on different workspaces.
You assign Ctrl+Alt+F1 to terminal 1, F2 to terminal 2, F3 to terminal 3.
Now you can:
- Press Ctrl+Alt+F1 → terminal 1 appears (was hidden)
- Press Ctrl+Alt+F1 → terminal 1 minimizes (was visible)
- Repeat anywhere in GNOME
# Setup build directory (only needed once)
meson setup build
# Compile the project
meson compile -C build
# Install to system (requires sudo)
sudo meson install -C buildAfter installation, run from anywhere:
window-toggle --configureIf you modify the source code and want to re-install:
# Recompile and install
meson compile -C build && sudo meson install -C buildOr in two steps:
meson compile -C build
sudo meson install -C build./window-toggle --configureThe program will:
- Ask you to press a key combination (e.g.,
Ctrl+Alt+F1) - Show a list of open windows - select one
- Automatically register the shortcut in GNOME
Press Ctrl+Alt+F1 anywhere in GNOME:
- Window hidden? → It appears on screen
- Window visible? → It minimizes
./window-toggle --show| Command | Description |
|---|---|
--configure |
Add a new shortcut for a window |
--run |
Toggle window (used by GNOME shortcut) |
--show |
List all configured shortcuts |
--clean |
Remove all shortcuts |
--start |
Clean and start fresh |
--stop |
Stop the daemon |
--status |
Show whether the daemon is running |
--version |
Print version and release highlights |
--key KEY |
Specify which key was pressed (used by the daemon-callback command) |
--config PATH |
Use a non-default config file path |
Starting with v1.8, the same Fx key (e.g. F1) can be bound to five different modifier combinations, each toggling an independent window:
- bare Fx — e.g.
F1 - Ctrl+Fx — e.g.
Ctrl+F1 - Ctrl+Alt+Fx — e.g.
Ctrl+Alt+F1 - Ctrl+Shift+Fx — e.g.
Ctrl+Shift+F1 - Super+Fx — e.g.
Super+F1
Run window-toggle --configure once per binding. The tool writes a separate
dconf slot for each one and the run-time --key argument carries the modifier
through to the lookup, so pressing Ctrl+F1 toggles the Ctrl+F1 binding
while pressing plain F1 toggles the bare-F1 binding.
- Uses X11
_NET_WM_STATE_HIDDENto detect window state - Sends
_NET_ACTIVE_WINDOWto show,XIconifyWindowto hide - Stores config in
/tmp/window-toggle-config.json - Registers shortcuts via GNOME's
dconfsettings
- GNOME Desktop (for keyboard shortcuts)
- libX11
- xkbcommon
- GCC
- meson, ninja (for building)
- Ubuntu 24.04 with GNOME
Bind a modifier shortcut to "launch this app + toggle this window":
# Bind Ctrl+F12 to launch nautilus, anchored to the first launched window
window-toggle --bind-app Ctrl+F12 nautilus org.gnome.Nautilus
# List bindings
window-toggle --show-app
# Remove a binding
window-toggle --unbind-app Ctrl+F12Behavior on press:
- If the anchored window is alive — toggle (minimize / activate), same as a normal slot binding.
- If the anchored window is gone —
fork+execlp <cmd>, poll for a window matchingWM_CLASS, anchor the first match, and stop. The newly-launched window is visible by default, so it is not toggled. - Multi-instance: opening a second instance of the same class does not drift the binding; the anchor stays on the originally launched window.
Storage: the same /tmp/window-toggle-config.json, in a section marked ### app_bindings ###. The slot pipeline stops at this delimiter, so app bindings and slot bindings do not interfere. --clean removes slot bindings but preserves the app section.
- fix: dconf action parameter order (
--key X --run-appinstead of--run-app --key X) so the dconf callback actually fires - fix: app binding config now lives at
~/.config/window-toggle/bindings.json(XDG) instead of/tmp/window-toggle-config.json, so bindings survive reboot - chore: ensure parent dir is created on first write
- New:
--bind-app <key> <cmd> <wm_class>to bind a shortcut to "launch app + toggle window" - New:
--unbind-app <key>,--show-app,--run-app(dconf callback) - Anchor semantics: first launched window is remembered, never drifts
- Config: app bindings stored in a
### app_bindings ###section, isolated from slot data --cleanpreserves the app section; use--unbind-appto remove a single binding- Silent XErrorHandler added around stale-anchor checks
- Add
--versionflag with bilingual release notes - See v1.7 for the bulk of the modifier-matrix work
- Five modifier combinations can now coexist for the same Fx key (bare Fx, Ctrl+Fx, Ctrl+Alt+Fx, Ctrl+Shift+Fx, Super+Fx), each toggling an independent window
- Add persistent-X daemon mode (
--start/--stop/--status) to avoid the X-connection-exhaustion issue when Chrome has many windows. Seedoc/IMPLEMENT_DAEMON_MODE.mdfor the design notes - dconf command writes the full shortcut string (e.g.
--key Ctrl+F1) so the run-time lookup can recover the modifier - Fix dedup state-machine bug in
save_shortcut_mappingthat was corrupting the config file (the modifiers: line lost its trailing newline throughstrcspn) - Increase
line[]buffer from 512 to 4096 bytes in the config reader; the previous size truncated longwindow_titlefields
- Show
window_classin--showoutput
- Daemon-mode plumbing and assorted fixes; see
doc/GITHUB_STATUS.mdfor the historical commit list
- Fix config file format corruption when saving shortcuts
- Fix newline preservation in config file
- Support multiple independent shortcuts (F1, F2, etc.)
- Support shortcut override (reconfigure same key to different window)
- Add slot_id to config file for better tracking
- Add duplicate shortcut override support
- Initial release show
- Basic/hide window toggle functionality
MIT