# 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 desktop files. Cycling changes only the HUD selection; accepting that selection raises all of the application's windows and focuses its most-recent window. 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. - `Escape`: cancel without changing application focus or window stacking. - `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 ### Nix The project flake owns the Rust and GTK build dependencies. Build or run the locked package directly: ```sh nix build nix run . -- show ``` Use `nix develop` for a shell containing Cargo, Clippy, rustfmt, and the native GTK dependencies. Downstream flakes can install `packages.${system}.default` and make this flake's `nixpkgs` input follow their own. ### Cargo 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`. A Nix profile usually exposes it as `~/.nix-profile/bin/hypr-switcher`. Configure the applicable absolute path, then start the daemon and define 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. 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. ## 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.