From 7d9a0dae365158f6fbf3c0eaa8be95470d879941 Mon Sep 17 00:00:00 2001 From: alexion Date: Wed, 22 Jul 2026 15:52:21 -0400 Subject: [PATCH] feat(desktop): add the rofi launcher (task 0024) Add a rofi module to the desktop group, enabled by the aggregator. It runs the drun application launcher, bound on Super+R. A session menu built on the same themed rofi is bound on Super+Shift+X, and every rofi -dmenu call inherits the Stylix theme, so later utility menus reuse it for free. Also give layer surfaces their own fade-in (layersIn and fadeLayersIn) a touch quicker than the window animation, so the launcher fades in briskly rather than snapping into place. --- .claude/tasks/0024-rofi-launcher.md | 26 +++++++++++--- modules/desktop/desktop.nix | 1 + modules/desktop/hyprland/hyprland.nix | 3 ++ modules/desktop/rofi.nix | 52 +++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 modules/desktop/rofi.nix diff --git a/.claude/tasks/0024-rofi-launcher.md b/.claude/tasks/0024-rofi-launcher.md index 42f8b5a..90f08a6 100644 --- a/.claude/tasks/0024-rofi-launcher.md +++ b/.claude/tasks/0024-rofi-launcher.md @@ -13,8 +13,24 @@ Structure it so it is reusable as the dmenu-style frontend for later utility men ## Acceptance criteria -- [ ] A rofi module exists in the desktop group and is enabled by the aggregator. -- [ ] rofi combines application-run, binary-run, and window-switch modes, plus math evaluation and emoji. -- [ ] rofi opens on `Super+R`. -- [ ] rofi is usable as a dmenu-style frontend for utility menus, and a power menu is provided through it. -- [ ] neogaia builds green under `nix flake check`. +- [x] A rofi module exists in the desktop group and is enabled by the aggregator. +- [-] rofi combines application-run, binary-run, and window-switch modes, plus math evaluation and emoji. +- [x] rofi opens on `Super+R`. +- [x] rofi is usable as a dmenu-style frontend for utility menus, and a power menu is provided through it. +- [x] neogaia builds green under `nix flake check`. + +## Implementation Notes + +- `rofi-wayland` no longer exists as a separate package: nixpkgs merged the Wayland fork into `pkgs.rofi` (now 2.0.0). + The module uses the plain `pkgs.rofi`, which is the Wayland-capable build. +- Criterion 2 is deliberately reduced (`[-]`): the launcher is application-launch only, `modi = "drun"`, opened with `rofi -show drun` on `Super+R`. + Binary-run, window-switch, math (`rofi-calc`) and emoji (`rofi-emoji`) were all dropped at the operator's direction, and the two plugins removed with them, to keep the prompt as fast and uncluttered as possible. + This narrows the parent spec's "search-everything launcher" (user story 7) to a plain application launcher — a reversible choice, since any mode or plugin can be added back later. + Application icons are disabled too (`show-icons = false`), since resolving an icon per entry is the largest part of drun's per-launch startup and rofi runs no resident daemon to amortise it. +- The dmenu-style reuse is the themed rofi itself, not a separate abstraction: any `rofi -dmenu` invocation reads the same config and Stylix theme, so the power menu — and later clipboard/utility menus — look uniform for free. +- The launcher and power-menu keybinds live in this module rather than in `hyprland.nix`, contributed through `settings.bind`, which the module system concatenates with the compositor's own binds in the single `hyprland.conf`. + This keeps each command next to its binding and referenced by store path, so a rename cannot silently break the bind. +- The power menu is bound to `Super+Shift+X`, chosen by the operator. + It pairs with lock on `Super+X` (a key the spec's table does list), while the parent spec's table has no power-menu key of its own. +- No Waybar `window-rewrite` icon mapping was added: rofi renders as a Wayland layer-shell overlay, not a tiled window with a class on a workspace, so it never appears on the workspace indicator the convention governs. +- The launcher's quick appearance is a Hyprland change, not a rofi one: layer surfaces get their own `layersIn`/`fadeLayersIn` fade at `2`, a step quicker than the `3` windows use, so the launcher fades in without feeling laggy. diff --git a/modules/desktop/desktop.nix b/modules/desktop/desktop.nix index 6492d2c..aa6b80d 100644 --- a/modules/desktop/desktop.nix +++ b/modules/desktop/desktop.nix @@ -11,6 +11,7 @@ in config = lib.mkIf cfg.enable { modules.desktop.hyprland.enable = lib.mkDefault true; modules.desktop.login.enable = lib.mkDefault true; + modules.desktop.rofi.enable = lib.mkDefault true; modules.desktop.terminal.enable = lib.mkDefault true; modules.desktop.theming.enable = lib.mkDefault true; modules.desktop.waybar.enable = lib.mkDefault true; diff --git a/modules/desktop/hyprland/hyprland.nix b/modules/desktop/hyprland/hyprland.nix index 8908aad..263b1bd 100644 --- a/modules/desktop/hyprland/hyprland.nix +++ b/modules/desktop/hyprland/hyprland.nix @@ -98,6 +98,9 @@ in animation = [ "windows, 1, 3, ease" "fade, 1, 3, ease" + # Layer surfaces like the launcher fade in a touch quicker than windows. + "layersIn, 1, 2, ease" + "fadeLayersIn, 1, 2, ease" "workspaces, 1, 3, ease" "border, 1, 3, ease" ]; diff --git a/modules/desktop/rofi.nix b/modules/desktop/rofi.nix new file mode 100644 index 0000000..6e4b8cd --- /dev/null +++ b/modules/desktop/rofi.nix @@ -0,0 +1,52 @@ +{ + config, + lib, + pkgs, + ... +}: +# rofi as the desktop launcher and dmenu-style menu frontend. +let + cfg = config.modules.desktop.rofi; + user = config.user.name; + + # A session menu built on the same themed rofi, so the power actions look + # like every other menu the launcher drives. + powerMenu = pkgs.writeShellScript "rofi-power-menu" '' + chosen=$(printf '%s\n' Lock Suspend 'Log out' Reboot 'Shut down' \ + | ${pkgs.rofi}/bin/rofi -dmenu -i -p Power) + case "$chosen" in + Lock) ${pkgs.systemd}/bin/loginctl lock-session ;; + Suspend) ${pkgs.systemd}/bin/systemctl suspend ;; + 'Log out') ${pkgs.systemd}/bin/loginctl terminate-session "$XDG_SESSION_ID" ;; + Reboot) ${pkgs.systemd}/bin/systemctl reboot ;; + 'Shut down') ${pkgs.systemd}/bin/systemctl poweroff ;; + esac + ''; +in +{ + options.modules.desktop.rofi.enable = lib.mkEnableOption "the rofi launcher"; + + config = lib.mkIf cfg.enable { + home-manager.users.${user} = { + # No theme is set here: Stylix's rofi target supplies the Nord one. + programs.rofi = { + enable = true; + + # Application launch is the only mode, kept minimal so the prompt opens + # as fast as rofi can read the desktop entries. + # Icons are off: resolving one per entry is the bulk of drun's startup. + extraConfig = { + modi = "drun"; + show-icons = false; + }; + }; + + # The launcher and the session menu, kept next to the tool they drive. + # $mod is defined by the compositor config these binds share. + wayland.windowManager.hyprland.settings.bind = [ + "$mod, R, exec, ${pkgs.rofi}/bin/rofi -show drun" + "$mod SHIFT, X, exec, ${powerMenu}" + ]; + }; + }; +} -- 2.47.3