Files
Nomarchy/modules/home/hyprland.nix
Bernardo Magri 961314ea86 feat(home): switch launcher/menu from fuzzel to rofi 2.0
rofi 2.0 landed in nixpkgs 26.05 with native Wayland (mainline upstreamed
the lbonn rofi-wayland fork — `wayland enabled`), so the original reason
to prefer fuzzel (rofi being X11-only / needing a community fork) is gone.
rofi's `.rasi` is far more expressive than fuzzel's flat INI, which lets
the launcher be a proper themed hero surface and revives the legacy
per-theme launcher designs.

- modules/home/rofi.nix replaces fuzzel.nix: per-element theme generated
  from theme-state.json (accent border, highlighted selection, rounded
  inputbar) via lib.formats.rasi.mkLiteral; themes/<slug>/rofi.rasi
  whole-swap; the nomarchy-menu dispatcher re-pointed to `rofi -dmenu`
  (power/theme/clipboard/calc with -mesg/files/web + root picker).
- SUPER+D is now `rofi -show drun`; the menu binds are unchanged.
- nomarchy.fuzzel.enable → nomarchy.rofi.enable; fuzzel dropped from
  home.packages. Pango handles nf-glyph fallback (no explicit font list
  needed as fuzzel's fcft did). show-icons off until an icon theme ships.

Verified: flake check green, HM generation builds, the generated
theme.rasi parses under `rofi -dump-theme`, Hyprland config verifies.
Not verified: rofi's on-screen rendering needs a real session.

Docs: README menu/override/roadmap sections and the module tree updated;
the per-theme launcher roadmap item now points at porting the legacy
rofi.rasi designs (the whole-swap mechanism is in place).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 14:41:46 +01:00

190 lines
6.8 KiB
Nix

# Hyprland — fully driven by config.nomarchy.theme (theme-state.json).
# Gaps, borders and colors are baked from the JSON at eval time; theme
# changes arrive via `home-manager switch`.
{ config, lib, ... }:
let
t = config.nomarchy.theme;
c = t.colors;
inherit (config.nomarchy.lib) rgb rgba;
# SUPER+1..9 / SUPER+SHIFT+1..9 workspace binds, generated.
workspaceBinds = builtins.concatLists (builtins.genList
(i:
let ws = toString (i + 1);
in [
"$mod, ${ws}, workspace, ${ws}"
"$mod SHIFT, ${ws}, movetoworkspace, ${ws}"
])
9);
in
{
wayland.windowManager.hyprland = lib.mkIf config.nomarchy.hyprland.enable {
enable = true;
# The binary and portal come from the NixOS module
# (programs.hyprland.enable); HM only manages configuration.
package = null;
portalPackage = null;
# HM defaults stateVersion >= 26.05 to the new Lua config and would
# render these hyprlang-style settings as broken `hl.$mod(...)` Lua
# (Hyprland then boots into emergency mode with no binds).
configType = "hyprlang";
settings = {
"$mod" = "SUPER";
"$terminal" = config.nomarchy.terminal;
# mkDefault so a downstream `monitor = [...]` replaces it with a
# plain assignment (the live ISO uses mkForce for the same reason).
monitor = lib.mkDefault [ ",preferred,auto,1" ];
# exec-once is a list at normal priority, so downstream additions
# CONCATENATE (your autostart runs alongside ours) rather than
# replace. Same for the bind* lists below.
exec-once = [
# nixpkgs' swww is awww (renamed fork); the binary is awww-daemon.
"awww-daemon"
# Paint the wallpaper as soon as the session is up (waits for
# the daemon internally).
"nomarchy-theme-sync wallpaper"
];
# ── Theme-driven look ──────────────────────────────────────────
# These flow from theme-state.json and stay at NORMAL priority:
# change them with `nomarchy-theme-sync set ui.<key>` (the intended
# path), or lib.mkForce in home.nix to hardcode against the theme.
# The non-theme knobs around them are lib.mkDefault — override
# those with a plain home.nix assignment. See docs/OVERRIDES.md.
general = {
gaps_in = t.ui.gapsIn;
gaps_out = t.ui.gapsOut;
border_size = t.ui.borderSize;
"col.active_border" = "${rgb c.accent} ${rgb c.accentAlt} 45deg";
"col.inactive_border" = rgb c.overlay;
layout = lib.mkDefault "dwindle";
resize_on_border = lib.mkDefault true;
};
decoration = {
rounding = t.ui.rounding;
active_opacity = t.ui.activeOpacity;
inactive_opacity = t.ui.inactiveOpacity;
blur = {
enabled = t.ui.blur;
size = lib.mkDefault 8;
passes = lib.mkDefault 2;
popups = lib.mkDefault true;
};
shadow = {
enabled = t.ui.shadow;
range = lib.mkDefault 20;
render_power = lib.mkDefault 3;
color = rgba c.mantle "aa";
};
};
# ── Behaviour (mkDefault → plain home.nix assignment overrides) ──
animations = {
enabled = lib.mkDefault true;
bezier = lib.mkDefault [
"smooth, 0.25, 0.1, 0.25, 1.0"
"snappy, 0.6, 0.0, 0.1, 1.0"
];
animation = lib.mkDefault [
"windows, 1, 4, snappy, popin 85%"
"border, 1, 8, smooth"
"fade, 1, 5, smooth"
"workspaces, 1, 4, snappy, slidefade 15%"
];
};
input = {
# kb_layout/variant come from nomarchy.keyboard.* — set that
# option (the installer writes it; it also drives tty/LUKS).
kb_layout = config.nomarchy.keyboard.layout;
kb_variant = config.nomarchy.keyboard.variant;
follow_mouse = lib.mkDefault 1;
touchpad.natural_scroll = lib.mkDefault true;
};
# dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo`
# dispatcher still exists); setting it aborts config parsing.
dwindle.preserve_split = lib.mkDefault true;
# Hyprland 0.51+ replaced gestures:workspace_swipe with the
# gesture keyword — without this, touchpads have NO gestures.
gesture = lib.mkDefault [
"3, horizontal, workspace"
"4, pinch, fullscreen"
];
misc = {
disable_hyprland_logo = lib.mkDefault true;
disable_splash_rendering = lib.mkDefault true;
force_default_wallpaper = lib.mkDefault 0;
};
bind = [
"$mod, Return, exec, $terminal"
"$mod, D, exec, rofi -show drun"
"$mod, E, exec, $terminal -e yazi"
"$mod, Q, killactive"
"$mod, F, fullscreen"
"$mod, V, togglefloating"
"$mod SHIFT, E, exit"
# Theme picker (menu dispatcher): apply writes the state and
# runs home-manager switch (progress via notify-send).
"$mod, T, exec, nomarchy-menu theme"
# Cycle the current theme's wallpapers (instant, no rebuild).
"$mod SHIFT, T, exec, nomarchy-theme-sync bg next"
# Power menu (rofi dmenu via the nomarchy-menu dispatcher).
# Not Escape: Super+Escape gets swallowed before reaching the
# dispatcher on some setups (input methods / modal handling).
"$mod, X, exec, nomarchy-menu power"
# Notification centre (swaync).
"$mod, N, exec, swaync-client -t"
# Clipboard history (cliphist via the menu dispatcher).
"$mod CTRL, V, exec, nomarchy-menu clipboard"
# Focus
"$mod, H, movefocus, l"
"$mod, L, movefocus, r"
"$mod, K, movefocus, u"
"$mod, J, movefocus, d"
# Screenshot region to clipboard
", Print, exec, grim -g \"$(slurp)\" - | wl-copy"
] ++ workspaceBinds;
# Media keys: wpctl talks to wireplumber directly (no
# pipewire-pulse shim like pamixer); e = repeat, l = also on a
# locked screen — the standard flags for hardware keys.
bindel = [
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
", XF86MonBrightnessUp, exec, brightnessctl set +5%"
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
];
bindl = [
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioPause, exec, playerctl play-pause"
", XF86AudioNext, exec, playerctl next"
", XF86AudioPrev, exec, playerctl previous"
];
bindm = [
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
];
};
};
}