2026-07-18 11:21:00 -07:00
|
|
|
# hypr-switcher
|
|
|
|
|
|
|
|
|
|
A macOS-style application switcher for Hyprland. It runs as a small GTK
|
|
|
|
|
layer-shell daemon, tracks focus through Hyprland's event socket, and exposes
|
|
|
|
|
commands for application and same-application window switching.
|
|
|
|
|
|
|
|
|
|
The application HUD groups windows by Hyprland `class`, orders applications and
|
|
|
|
|
their windows by most-recent focus, and resolves names and icons from installed
|
2026-07-26 18:33:15 -07:00
|
|
|
desktop files. Cycling changes only the HUD selection; accepting that selection
|
|
|
|
|
raises all of the application's windows and focuses its most-recent window.
|
2026-07-18 11:21:00 -07:00
|
|
|
|
|
|
|
|
This implementation uses only standard Hyprland IPC. It does not depend on the
|
|
|
|
|
custom `cycleapp` or `cycleappwindow` dispatchers.
|
|
|
|
|
|
|
|
|
|
## Behavior
|
|
|
|
|
|
|
|
|
|
- `Super+Tab` / `Super+Shift+Tab`: show the application HUD and move selection.
|
|
|
|
|
- Release `Super` or press `Enter`: accept the selection.
|
2026-07-26 18:33:15 -07:00
|
|
|
- `Escape`: cancel without changing application focus or window stacking.
|
2026-07-18 11:21:00 -07:00
|
|
|
- `Super+grave` / `Super+Shift+grave`: cycle windows in the current application.
|
|
|
|
|
- `Super+H`: hide every window in the current application.
|
|
|
|
|
|
|
|
|
|
Hidden windows are moved silently to `special:hypr-switcher-hidden`. Their
|
|
|
|
|
applications remain visible, dimmed, at the end of the HUD. Selecting a hidden
|
|
|
|
|
application restores all of its windows to the current workspace and focuses
|
|
|
|
|
its most-recent window. The special workspace also lets the daemon rediscover
|
|
|
|
|
hidden applications after a restart.
|
|
|
|
|
|
|
|
|
|
The HUD displays applications from the current workspace plus hidden
|
|
|
|
|
applications. Normal application switching does not pull visible windows from
|
|
|
|
|
other workspaces.
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
|
|
- Hyprland with its command and event IPC sockets enabled (the default)
|
|
|
|
|
- GTK 4
|
|
|
|
|
- gtk4-layer-shell
|
|
|
|
|
- A working icon theme and desktop files under the standard XDG data paths
|
|
|
|
|
- Rust and Cargo to build from source
|
|
|
|
|
|
|
|
|
|
## Build and install
|
|
|
|
|
|
|
|
|
|
Run this from the directory containing this README:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
cargo test
|
|
|
|
|
cargo clippy --workspace --all-targets -- -D warnings
|
|
|
|
|
cargo install --path . --root ~/.local --force
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The binary is installed as `~/.local/bin/hypr-switcher`. The accompanying
|
|
|
|
|
`../hyprland.conf` starts the daemon and defines the bindings:
|
|
|
|
|
|
|
|
|
|
```ini
|
|
|
|
|
$switcher = ~/.local/bin/hypr-switcher
|
|
|
|
|
|
|
|
|
|
exec-once = $switcher daemon
|
|
|
|
|
layerrule = match:namespace ^(hypr-switcher)$, no_anim 1
|
|
|
|
|
|
|
|
|
|
bind = SUPER, Tab, exec, $switcher show
|
|
|
|
|
bind = SUPER SHIFT, Tab, exec, $switcher show-previous
|
|
|
|
|
bind = SUPER, grave, exec, $switcher window-next
|
|
|
|
|
bind = SUPER SHIFT, grave, exec, $switcher window-previous
|
|
|
|
|
bind = SUPER, H, exec, $switcher hide-current
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
After rebuilding, restart the daemon so the running process uses the new
|
|
|
|
|
binary. Reload Hyprland after changing bindings.
|
|
|
|
|
|
|
|
|
|
## Commands
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
hypr-switcher daemon
|
|
|
|
|
hypr-switcher show
|
|
|
|
|
hypr-switcher show-previous
|
|
|
|
|
hypr-switcher window-next
|
|
|
|
|
hypr-switcher window-previous
|
|
|
|
|
hypr-switcher hide-current
|
|
|
|
|
hypr-switcher cancel
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Set `RUST_LOG=hypr_switcher=debug` on the daemon command for diagnostics.
|
|
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
|
|
- `src/ipc.rs` talks directly to Hyprland's Unix sockets, listens for focus and
|
|
|
|
|
window events, raises/focuses windows, and moves hidden apps.
|
|
|
|
|
- `src/model.rs` owns address normalization, window metadata, application
|
|
|
|
|
grouping, and MRU ordering.
|
|
|
|
|
- `src/desktop.rs` resolves application names and icons from XDG desktop files.
|
|
|
|
|
- `src/main.rs` owns the daemon command socket, switch sessions, GTK HUD, and
|
|
|
|
|
keyboard handling.
|
|
|
|
|
|
2026-07-26 18:33:15 -07:00
|
|
|
The daemon freezes MRU updates while the HUD is active, keeping the application
|
|
|
|
|
order stable throughout the switch session. It does not raise or focus the
|
|
|
|
|
highlighted application while cycling. Final focus is sent shortly after the
|
|
|
|
|
layer-shell HUD closes, allowing its exclusive keyboard grab to be released
|
|
|
|
|
first.
|
2026-07-18 11:21:00 -07:00
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
- If commands report that the daemon is unavailable, start
|
|
|
|
|
`hypr-switcher daemon` or begin a new Hyprland session so `exec-once` runs.
|
|
|
|
|
- If the HUD works from the command line but not from `Super+Tab`, inspect live
|
|
|
|
|
bindings with `hyprctl binds` and verify which config is active with
|
|
|
|
|
`readlink -f ~/.config/hypr/hyprland.conf`.
|
|
|
|
|
- If an icon is missing, compare the Hyprland window `class` from
|
|
|
|
|
`hyprctl clients` with the desktop file name or its `StartupWMClass` value.
|