From fce4bdc5262a1cf803ebf89390c49bdd06f94992 Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:12:07 -0400 Subject: [PATCH 1/6] feat(hyprland): emit compositor config as lua --- configs/nixos/AGENTS.md | 9 +- configs/nixos/hosts/zeus/default.nix | 15 +- .../desktop/session/hyprland/default.nix | 335 +++++++++++++----- .../desktop/session/hyprland/hyprlock.nix | 16 +- .../nixos/modules/desktop/session/mako.nix | 15 +- .../nixos/modules/desktop/session/rofi.nix | 17 +- .../modules/desktop/utilities/clipboard.nix | 15 +- .../modules/desktop/utilities/recording.nix | 15 +- .../modules/desktop/utilities/screenshot.nix | 28 +- 9 files changed, 346 insertions(+), 119 deletions(-) diff --git a/configs/nixos/AGENTS.md b/configs/nixos/AGENTS.md index 2f538cf..5bfd948 100644 --- a/configs/nixos/AGENTS.md +++ b/configs/nixos/AGENTS.md @@ -8,7 +8,7 @@ Match the mapping on the window class. Run `hyprctl clients -j | jq -r '.[].class' | sort -u` to list classes in the running session. - TODO: Verify this path after the NixOS configuration is migrated. - Set Hyprland session environment variables in `modules/desktop/session/hyprland/default.nix` with `env = KEY,VALUE`. + Set Hyprland session environment variables in `modules/desktop/session/hyprland/default.nix` with Lua `env` call records. `home.sessionVariables` do **not** reach the Hyprland session because UWSM does not source `hm-session-vars.sh`. Source cursor values from `config.stylix.cursor`. Set `XCURSOR_*` and `HYPRCURSOR_*` to the same theme for Bibata. @@ -65,3 +65,10 @@ and Zeus), not in the generic host module. - Module-relative paths resolve from the module file. Update them when moving a module into a subdirectory. - On Pikachu, `uptime` does not support `-s`. Use `who -b` to report the boot time. +- Changing `networking.hostId` makes ZFS reject a previously imported pool. Force-import the pool once after confirming no other host uses it. +- Remote `ssh pikachu` starts Fish. Pass `sh -c` when a command needs POSIX shell syntax. +- `deploy-to` runs on the initiating host. Deploy its Fish definition to that host before testing workflow changes. +- Home Manager stores `programs.ssh.settings` blocks as DAG entries. Read configured values from each entry's `data` attribute. +- A `NOLINT(let_order)` comment before a `let` suppresses the whole let scope. Place it on an individual binding to limit suppression. +- `util.deriveMac` derives a deterministic locally administered MAC address from a name. +- GameMode needs membership in the `gamemode` group only when enabled settings require it, such as process renicing or core parking. diff --git a/configs/nixos/hosts/zeus/default.nix b/configs/nixos/hosts/zeus/default.nix index 9e49cd8..56bdf2f 100644 --- a/configs/nixos/hosts/zeus/default.nix +++ b/configs/nixos/hosts/zeus/default.nix @@ -49,8 +49,19 @@ modules.desktop.apps.vencord.enable = true; home-manager.users.${config.user.name}.wayland.windowManager.hyprland.settings.monitor = [ - "HDMI-A-1,1920x1080@120,0x0,1,transform,3" - "DP-3,2560x1440@239.96,1080x0,1" + { + output = "HDMI-A-1"; + mode = "1920x1080@120"; + position = "0x0"; + scale = 1; + transform = 3; + } + { + output = "DP-3"; + mode = "2560x1440@239.96"; + position = "1080x0"; + scale = 1; + } ]; } diff --git a/configs/nixos/modules/desktop/session/hyprland/default.nix b/configs/nixos/modules/desktop/session/hyprland/default.nix index 7cc25db..6487cf1 100644 --- a/configs/nixos/modules/desktop/session/hyprland/default.nix +++ b/configs/nixos/modules/desktop/session/hyprland/default.nix @@ -5,16 +5,40 @@ ... }: # The Hyprland compositor. -let +let # NOLINT(let_order) cfg = config.modules.desktop.session.hyprland; # NOLINT(let_order) cursor = config.stylix.cursor; + bind = key: dispatcher: { + _args = [ + key + dispatcher + ]; + }; + luaCall = function: args: mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + terminal = "ghostty"; + execBindWith = + key: command: options: + bindWith key (luaCall "hl.dsp.exec_cmd" [ command ]) options; + bindWith = key: dispatcher: options: { + _args = [ + key + dispatcher + options + ]; + }; # Numbered-workspace switch and move for 1..9, the operator's i3 muscle memory. workspaceBinds = lib.concatMap (n: [ - "$mod, ${toString n}, workspace, ${toString n}" - "$mod SHIFT, ${toString n}, movetoworkspace, ${toString n}" + (bind "${mod} + ${toString n}" (luaCall "hl.dsp.focus" [ { workspace = n; } ])) + (bind "${mod} + SHIFT + ${toString n}" (luaCall "hl.dsp.window.move" [ { workspace = n; } ])) ]) (lib.range 1 9); + execBind = key: command: bind key (luaCall "hl.dsp.exec_cmd" [ command ]); + + inherit (lib.generators) mkLuaInline; + + mod = "SUPER"; + toLua = lib.generators.toLua { }; user = config.user.name; # Flip the tiling strategy between the two built-in layouts, since neither a @@ -56,14 +80,16 @@ in # uwsm owns the systemd graphical-session targets. systemd.enable = false; - # Write the native hyprlang hyprland.conf, whose variable and bind syntax - # the settings below are expressed in. - configType = "hyprlang"; + # Write the native Lua Hyprland config. Home Manager renders the Nix + # settings below as hl.* calls. + configType = "lua"; + importantPrefixes = [ + "config" + "curve" + "animation" + ]; settings = { - "$mod" = "SUPER"; - "$terminal" = "ghostty"; - # Session variables handed to the compositor directly. # UWSM launches the session without the shell profile that would carry # them, so a variable the compositor or its children must see is set @@ -72,119 +98,232 @@ in # Chromium and Electron apps read this to select native Wayland; # nixpkgs wrappers (Obsidian's included) gate their Wayland flags on # it, so without it they run under XWayland and blur at this DPI. - "NIXOS_OZONE_WL,1" + { + _args = [ + "NIXOS_OZONE_WL" + "1" + ]; + } ] # Bibata ships XCursor only. # The hyprcursor variables name the same theme, which Hyprland # resolves through its XCursor fallback. ++ lib.optionals (cursor != null) [ - "XCURSOR_THEME,${cursor.name}" - "XCURSOR_SIZE,${toString cursor.size}" - "HYPRCURSOR_THEME,${cursor.name}" - "HYPRCURSOR_SIZE,${toString cursor.size}" + { + _args = [ + "XCURSOR_THEME" + cursor.name + ]; + } + { + _args = [ + "XCURSOR_SIZE" + (toString cursor.size) + ]; + } + { + _args = [ + "HYPRCURSOR_THEME" + cursor.name + ]; + } + { + _args = [ + "HYPRCURSOR_SIZE" + (toString cursor.size) + ]; + } ]; - input = { - kb_layout = "us"; - # Caps is a second Escape. - # Shift+Caps still toggles a real CapsLock. - kb_options = "caps:escape_shifted_capslock"; - # Snappy key repeat. - repeat_delay = 250; - repeat_rate = 45; - accel_profile = "flat"; - touchpad = { - natural_scroll = true; - tap-to-click = true; - disable_while_typing = true; + config = { + input = { + kb_layout = "us"; + # Caps is a second Escape. + # Shift+Caps still toggles a real CapsLock. + kb_options = "caps:escape_shifted_capslock"; + # Snappy key repeat. + repeat_delay = 250; + repeat_rate = 45; + accel_profile = "flat"; + touchpad = { + natural_scroll = true; + tap_to_click = true; + disable_while_typing = true; + }; + }; + + general = { + gaps_in = 4; + gaps_out = 8; + border_size = 2; + layout = "dwindle"; + }; + + decoration = { + rounding = 6; + blur.enabled = cfg.blur; + }; + + # XWayland clients render at the panel's native resolution instead of + # being raster-scaled by the compositor at the fractional monitor scale. + xwayland.force_zero_scaling = true; + + animations.enabled = true; + + dwindle = { + preserve_split = true; }; }; - general = { - gaps_in = 4; - gaps_out = 8; - border_size = 2; - layout = "dwindle"; - }; - - decoration = { - rounding = 6; - blur.enabled = cfg.blur; - }; - - # XWayland clients render at the panel's native resolution instead of - # being raster-scaled by the compositor at the fractional monitor scale. - xwayland.force_zero_scaling = true; - - animations = { - enabled = true; - bezier = [ "ease, 0.25, 0.1, 0.25, 1.0" ]; - # Durations are in centiseconds. - # Short values keep the motion subtle. - 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" + curve = { + _args = [ + "ease" + { + type = "bezier"; + points = [ + [ + 0.25 + 0.1 + ] + [ + 0.25 + 1.0 + ] + ]; + } ]; }; - dwindle = { - preserve_split = true; - }; + # Durations are in centiseconds. + # Short values keep the motion subtle. + animation = [ + { + leaf = "windows"; + enabled = true; + speed = 3; + bezier = "ease"; + } + { + leaf = "fade"; + enabled = true; + speed = 3; + bezier = "ease"; + } + # Layer surfaces like the launcher fade in a touch quicker than windows. + { + leaf = "layersIn"; + enabled = true; + speed = 2; + bezier = "ease"; + } + { + leaf = "fadeLayersIn"; + enabled = true; + speed = 2; + bezier = "ease"; + } + { + leaf = "workspaces"; + enabled = true; + speed = 3; + bezier = "ease"; + } + { + leaf = "border"; + enabled = true; + speed = 3; + bezier = "ease"; + } + ]; bind = [ - "$mod, Return, exec, $terminal" + (execBind "${mod} + Return" terminal) # Move focus. - "$mod, H, movefocus, l" - "$mod, J, movefocus, d" - "$mod, K, movefocus, u" - "$mod, L, movefocus, r" + (bind "${mod} + H" (luaCall "hl.dsp.focus" [ { direction = "left"; } ])) + (bind "${mod} + J" (luaCall "hl.dsp.focus" [ { direction = "down"; } ])) + (bind "${mod} + K" (luaCall "hl.dsp.focus" [ { direction = "up"; } ])) + (bind "${mod} + L" (luaCall "hl.dsp.focus" [ { direction = "right"; } ])) # Move the window within the layout. - "$mod SHIFT, H, movewindow, l" - "$mod SHIFT, J, movewindow, d" - "$mod SHIFT, K, movewindow, u" - "$mod SHIFT, L, movewindow, r" + (bind "${mod} + SHIFT + H" (luaCall "hl.dsp.window.move" [ { direction = "left"; } ])) + (bind "${mod} + SHIFT + J" (luaCall "hl.dsp.window.move" [ { direction = "down"; } ])) + (bind "${mod} + SHIFT + K" (luaCall "hl.dsp.window.move" [ { direction = "up"; } ])) + (bind "${mod} + SHIFT + L" (luaCall "hl.dsp.window.move" [ { direction = "right"; } ])) # Resize the active window. - "$mod ALT, H, resizeactive, -40 0" - "$mod ALT, J, resizeactive, 0 40" - "$mod ALT, K, resizeactive, 0 -40" - "$mod ALT, L, resizeactive, 40 0" + (bind "${mod} + ALT + H" ( + luaCall "hl.dsp.window.resize" [ + { + x = -40; + y = 0; + relative = true; + } + ] + )) + (bind "${mod} + ALT + J" ( + luaCall "hl.dsp.window.resize" [ + { + x = 0; + y = 40; + relative = true; + } + ] + )) + (bind "${mod} + ALT + K" ( + luaCall "hl.dsp.window.resize" [ + { + x = 0; + y = -40; + relative = true; + } + ] + )) + (bind "${mod} + ALT + L" ( + luaCall "hl.dsp.window.resize" [ + { + x = 40; + y = 0; + relative = true; + } + ] + )) - "$mod, Space, togglefloating," - "$mod, F, fullscreen," - # togglesplit is a dwindle layout message, reached through layoutmsg. - "$mod, T, layoutmsg, togglesplit" - "$mod SHIFT, T, exec, ${toggleLayout}" - "$mod SHIFT, Q, killactive," - "$mod CTRL, Q, forcekillactive," + (bind "${mod} + Space" (luaCall "hl.dsp.window.float" [ { action = "toggle"; } ])) + (bind "${mod} + F" (luaCall "hl.dsp.window.fullscreen" [ ])) + # togglesplit is a dwindle layout message, reached through layout. + (bind "${mod} + T" (luaCall "hl.dsp.layout" [ "togglesplit" ])) + (execBind "${mod} + SHIFT + T" "${toggleLayout}") + (bind "${mod} + SHIFT + Q" (luaCall "hl.dsp.window.close" [ ])) + (bind "${mod} + CTRL + Q" (luaCall "hl.dsp.window.kill" [ ])) + + # Volume and brightness keys repeat while held, each raising a popup + # through the OSD client. + # Volume is capped at 100 percent. + # The client floors brightness so a full hold cannot black the screen out. + (execBindWith "XF86AudioRaiseVolume" + "${pkgs.swayosd}/bin/swayosd-client --output-volume raise --max-volume 100" + { repeating = true; } + ) + (execBindWith "XF86AudioLowerVolume" "${pkgs.swayosd}/bin/swayosd-client --output-volume lower" { + repeating = true; + }) + (execBindWith "XF86MonBrightnessUp" "${pkgs.swayosd}/bin/swayosd-client --brightness raise" { + repeating = true; + }) + (execBindWith "XF86MonBrightnessDown" "${pkgs.swayosd}/bin/swayosd-client --brightness lower" { + repeating = true; + }) + + # Mute and media transport still fire while the session is locked. + (execBindWith "XF86AudioMute" "${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" { + locked = true; + }) + (execBindWith "XF86AudioPlay" "${pkgs.playerctl}/bin/playerctl play-pause" { locked = true; }) + (execBindWith "XF86AudioNext" "${pkgs.playerctl}/bin/playerctl next" { locked = true; }) + (execBindWith "XF86AudioPrev" "${pkgs.playerctl}/bin/playerctl previous" { locked = true; }) ] ++ workspaceBinds; - - # Volume and brightness keys repeat while held, each raising a popup - # through the OSD client. - # Volume is capped at 100 percent. - # The client floors brightness so a full hold cannot black the screen out. - binde = [ - ", XF86AudioRaiseVolume, exec, ${pkgs.swayosd}/bin/swayosd-client --output-volume raise --max-volume 100" - ", XF86AudioLowerVolume, exec, ${pkgs.swayosd}/bin/swayosd-client --output-volume lower" - ", XF86MonBrightnessUp, exec, ${pkgs.swayosd}/bin/swayosd-client --brightness raise" - ", XF86MonBrightnessDown, exec, ${pkgs.swayosd}/bin/swayosd-client --brightness lower" - ]; - - # Mute and media transport still fire while the session is locked. - bindl = [ - ", XF86AudioMute, exec, ${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" - ", XF86AudioPlay, exec, ${pkgs.playerctl}/bin/playerctl play-pause" - ", XF86AudioNext, exec, ${pkgs.playerctl}/bin/playerctl next" - ", XF86AudioPrev, exec, ${pkgs.playerctl}/bin/playerctl previous" - ]; }; }; }; diff --git a/configs/nixos/modules/desktop/session/hyprland/hyprlock.nix b/configs/nixos/modules/desktop/session/hyprland/hyprlock.nix index b83a453..de12b73 100644 --- a/configs/nixos/modules/desktop/session/hyprland/hyprlock.nix +++ b/configs/nixos/modules/desktop/session/hyprland/hyprlock.nix @@ -6,6 +6,16 @@ }: # The lock screen: a hyprlock session-lock surface the compositor owns. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; # The hyprlock this module installs, used by the lock keybind below. @@ -15,6 +25,7 @@ let sleepOffIcon = builtins.fromJSON ''"\udb81\udcb3"''; idleLockToggle = pkgs.writeShellScript "lockscreen-idle-inhibit-toggle" '' + unit=lockscreen-idle-inhibit.service refresh_waybar() { @@ -42,6 +53,7 @@ let ${pkgs.swayosd}/bin/swayosd-client --custom-message "${sleepOffIcon}" fi ''; + toLua = lib.generators.toLua { }; in { options.modules.desktop.session.hyprland.hyprlock.enable = @@ -86,8 +98,8 @@ in # The guard drops the keypress when a locker is already up, so a second # hyprlock never stacks over the first. wayland.windowManager.hyprland.settings.bind = [ - "$mod, X, exec, ${pkgs.procps}/bin/pidof hyprlock || ${hyprlock}" - "$mod CTRL, X, exec, ${idleLockToggle}" + (execBind "SUPER + X" "${pkgs.procps}/bin/pidof hyprlock || ${hyprlock}") + (execBind "SUPER + CTRL + X" "${idleLockToggle}") ]; }; }; diff --git a/configs/nixos/modules/desktop/session/mako.nix b/configs/nixos/modules/desktop/session/mako.nix index f335717..9dc9e3f 100644 --- a/configs/nixos/modules/desktop/session/mako.nix +++ b/configs/nixos/modules/desktop/session/mako.nix @@ -6,9 +6,21 @@ }: # mako as the notification daemon: toasts, a do-not-disturb mode, and history recall. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; makoctl = "${pkgs.mako}/bin/makoctl"; + + toLua = lib.generators.toLua { }; in { options.modules.desktop.session.mako.enable = lib.mkEnableOption "the mako notification daemon"; @@ -34,9 +46,8 @@ in # Recall the last notification from history, keyboard-only like the rest # of the session. - # $mod is defined by the compositor config these binds share. wayland.windowManager.hyprland.settings.bind = [ - "$mod, N, exec, ${makoctl} restore" + (execBind "SUPER + N" "${makoctl} restore") ]; }; }; diff --git a/configs/nixos/modules/desktop/session/rofi.nix b/configs/nixos/modules/desktop/session/rofi.nix index 261cb7d..2f38201 100644 --- a/configs/nixos/modules/desktop/session/rofi.nix +++ b/configs/nixos/modules/desktop/session/rofi.nix @@ -6,6 +6,16 @@ }: # rofi as the desktop launcher and dmenu-style menu frontend. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; # A session menu built on the same themed rofi, so the power actions look @@ -21,6 +31,8 @@ let 'Shut down') ${pkgs.systemd}/bin/systemctl poweroff ;; esac ''; + + toLua = lib.generators.toLua { }; in { options.modules.desktop.session.rofi.enable = lib.mkEnableOption "the rofi launcher"; @@ -41,10 +53,9 @@ in }; # 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}" + (execBind "SUPER + R" "${pkgs.rofi}/bin/rofi -show drun") + (execBind "SUPER + SHIFT + X" "${powerMenu}") ]; }; }; diff --git a/configs/nixos/modules/desktop/utilities/clipboard.nix b/configs/nixos/modules/desktop/utilities/clipboard.nix index 4579982..6a676fc 100644 --- a/configs/nixos/modules/desktop/utilities/clipboard.nix +++ b/configs/nixos/modules/desktop/utilities/clipboard.nix @@ -6,6 +6,16 @@ }: # Clipboard history: cliphist records every copy, picked back through rofi. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; cliphist = "${pkgs.cliphist}/bin/cliphist"; @@ -22,6 +32,8 @@ let | ${cliphist} decode \ | ${wl-copy} ''; + + toLua = lib.generators.toLua { }; in { options.modules.desktop.utilities.clipboard.enable = @@ -39,9 +51,8 @@ in # session so uwsm starts and stops them with it. services.cliphist.enable = true; - # $mod is defined by the compositor config these binds share. wayland.windowManager.hyprland.settings.bind = [ - "$mod SHIFT, V, exec, ${picker}" + (execBind "SUPER + SHIFT + V" "${picker}") ]; }; }; diff --git a/configs/nixos/modules/desktop/utilities/recording.nix b/configs/nixos/modules/desktop/utilities/recording.nix index 50385d5..5f87bd4 100644 --- a/configs/nixos/modules/desktop/utilities/recording.nix +++ b/configs/nixos/modules/desktop/utilities/recording.nix @@ -6,6 +6,16 @@ }: # Keybound screen recording: pick a region, then toggle a video-only capture. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; slurp = "${pkgs.slurp}/bin/slurp"; @@ -38,6 +48,8 @@ let ${wf-recorder} -g "$region" -f "$file" ${notify-send} -a "Screen recording" "Recording saved" "$file" ''; + + toLua = lib.generators.toLua { }; in { options.modules.desktop.utilities.recording.enable = @@ -45,9 +57,8 @@ in config = lib.mkIf config.modules.desktop.utilities.recording.enable { home-manager.users.${user} = { - # $mod is defined by the compositor config these binds share. wayland.windowManager.hyprland.settings.bind = [ - "$mod SHIFT, R, exec, ${toggle}" + (execBind "SUPER + SHIFT + R" "${toggle}") ]; }; }; diff --git a/configs/nixos/modules/desktop/utilities/screenshot.nix b/configs/nixos/modules/desktop/utilities/screenshot.nix index 1d723ef..6b16894 100644 --- a/configs/nixos/modules/desktop/utilities/screenshot.nix +++ b/configs/nixos/modules/desktop/utilities/screenshot.nix @@ -7,6 +7,16 @@ # Keyboard-driven screenshots copy to the clipboard before Satty opens for # annotation. Satty copies annotated screenshots when it saves them. let + execBind = key: command: { + _args = [ + key + (luaCall "hl.dsp.exec_cmd" [ command ]) + ]; + }; + luaCall = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + user = config.user.name; grimblast = "${pkgs.grimblast}/bin/grimblast"; @@ -31,6 +41,8 @@ let --early-exit \ --actions-on-enter save-to-clipboard ''; + + toLua = lib.generators.toLua { }; in { options.modules.desktop.utilities.screenshot.enable = @@ -40,19 +52,21 @@ in home-manager.users.${user} = { # satty is a one-shot annotation surface, so float it rather than letting # it claim a tile in the layout. - # windowrule v3 syntax: space-separated field/value tokens, comma - # separated, with matchers under a match: prefix and effects bare. - wayland.windowManager.hyprland.settings.windowrule = [ - "float 1, match:class ^(com\\.gabm\\.satty)$" + wayland.windowManager.hyprland.settings.window_rule = [ + { + name = "satty-float"; + match.class = "^(com\\.gabm\\.satty)$"; + float = true; + } ]; # Print with plain/Shift/Ctrl for region/window/full. # Super+L is already the hjkl focus and movement bind, so screenshots take # the Print key instead. wayland.windowManager.hyprland.settings.bind = [ - ", Print, exec, ${capture "area"}" - "SHIFT, Print, exec, ${capture "active"}" - "CTRL, Print, exec, ${capture "screen"}" + (execBind "Print" "${capture "area"}") + (execBind "SHIFT + Print" "${capture "active"}") + (execBind "CTRL + Print" "${capture "screen"}") ]; }; }; -- 2.47.3 From cd0a4877578a2b8452802118d8c72840275192c6 Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:17:35 -0400 Subject: [PATCH 2/6] fix(hyprland): mark zeus main output for xwayland --- configs/nixos/hosts/zeus/default.nix | 46 +++++++++++++++++++--------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/configs/nixos/hosts/zeus/default.nix b/configs/nixos/hosts/zeus/default.nix index 56bdf2f..d99267b 100644 --- a/configs/nixos/hosts/zeus/default.nix +++ b/configs/nixos/hosts/zeus/default.nix @@ -1,6 +1,7 @@ { config, lib, + pkgs, ... }: # zeus — Ryzen desktop with AMD graphics. @@ -48,20 +49,35 @@ modules.desktop.apps.steam.enable = true; modules.desktop.apps.vencord.enable = true; - home-manager.users.${config.user.name}.wayland.windowManager.hyprland.settings.monitor = [ - { - output = "HDMI-A-1"; - mode = "1920x1080@120"; - position = "0x0"; - scale = 1; - transform = 3; - } - { - output = "DP-3"; - mode = "2560x1440@239.96"; - position = "1080x0"; - scale = 1; - } - ]; + home-manager.users.${config.user.name}.wayland.windowManager.hyprland.settings = { + monitor = [ + { + output = "HDMI-A-1"; + mode = "1920x1080@120"; + position = "0x0"; + scale = 1; + transform = 3; + } + { + output = "DP-3"; + mode = "2560x1440@239.96"; + position = "1080x0"; + scale = 1; + } + ]; + + # Some XWayland games query RandR primary output instead of Hyprland's + # layout, so mark the main panel explicitly. + on = { + _args = [ + "hyprland.start" + (lib.generators.mkLuaInline '' + function() + hl.exec_cmd("${pkgs.xrandr}/bin/xrandr --output DP-3 --primary") + end + '') + ]; + }; + }; } -- 2.47.3 From 4eeaaa75d570ddf781482fa3dd08e3fe59b376a4 Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:18:59 -0400 Subject: [PATCH 3/6] fix(hyprland): make dp output the layout origin --- configs/nixos/hosts/zeus/default.nix | 46 +++++++++------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/configs/nixos/hosts/zeus/default.nix b/configs/nixos/hosts/zeus/default.nix index d99267b..d961d9c 100644 --- a/configs/nixos/hosts/zeus/default.nix +++ b/configs/nixos/hosts/zeus/default.nix @@ -1,7 +1,6 @@ { config, lib, - pkgs, ... }: # zeus — Ryzen desktop with AMD graphics. @@ -49,35 +48,20 @@ modules.desktop.apps.steam.enable = true; modules.desktop.apps.vencord.enable = true; - home-manager.users.${config.user.name}.wayland.windowManager.hyprland.settings = { - monitor = [ - { - output = "HDMI-A-1"; - mode = "1920x1080@120"; - position = "0x0"; - scale = 1; - transform = 3; - } - { - output = "DP-3"; - mode = "2560x1440@239.96"; - position = "1080x0"; - scale = 1; - } - ]; - - # Some XWayland games query RandR primary output instead of Hyprland's - # layout, so mark the main panel explicitly. - on = { - _args = [ - "hyprland.start" - (lib.generators.mkLuaInline '' - function() - hl.exec_cmd("${pkgs.xrandr}/bin/xrandr --output DP-3 --primary") - end - '') - ]; - }; - }; + home-manager.users.${config.user.name}.wayland.windowManager.hyprland.settings.monitor = [ + { + output = "DP-3"; + mode = "2560x1440@239.96"; + position = "0x0"; + scale = 1; + } + { + output = "HDMI-A-1"; + mode = "1920x1080@120"; + position = "-1080x0"; + scale = 1; + transform = 3; + } + ]; } -- 2.47.3 From 03c582e4ba50c20faaf446d3584bcfa56a687071 Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:22:06 -0400 Subject: [PATCH 4/6] refactor(hyprland): remove let order suppression --- .../desktop/session/hyprland/default.nix | 133 +++++++++--------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/configs/nixos/modules/desktop/session/hyprland/default.nix b/configs/nixos/modules/desktop/session/hyprland/default.nix index 6487cf1..4ee7e6f 100644 --- a/configs/nixos/modules/desktop/session/hyprland/default.nix +++ b/configs/nixos/modules/desktop/session/hyprland/default.nix @@ -5,40 +5,39 @@ ... }: # The Hyprland compositor. -let # NOLINT(let_order) +let cfg = config.modules.desktop.session.hyprland; # NOLINT(let_order) + lua = rec { + toLua = lib.generators.toLua { }; + call = + function: args: + lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; + bind = key: dispatcher: { + _args = [ + key + dispatcher + ]; + }; + bindWith = key: dispatcher: options: { + _args = [ + key + dispatcher + options + ]; + }; + execBind = key: command: bind key (call "hl.dsp.exec_cmd" [ command ]); + execBindWith = + key: command: options: + bindWith key (call "hl.dsp.exec_cmd" [ command ]) options; + + # Numbered-workspace switch and move for 1..9, the operator's i3 muscle memory. + workspaceBinds = lib.concatMap (n: [ + (bind "SUPER + ${toString n}" (call "hl.dsp.focus" [ { workspace = n; } ])) + (bind "SUPER + SHIFT + ${toString n}" (call "hl.dsp.window.move" [ { workspace = n; } ])) + ]) (lib.range 1 9); + }; + cursor = config.stylix.cursor; - bind = key: dispatcher: { - _args = [ - key - dispatcher - ]; - }; - luaCall = function: args: mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; - terminal = "ghostty"; - execBindWith = - key: command: options: - bindWith key (luaCall "hl.dsp.exec_cmd" [ command ]) options; - bindWith = key: dispatcher: options: { - _args = [ - key - dispatcher - options - ]; - }; - - # Numbered-workspace switch and move for 1..9, the operator's i3 muscle memory. - workspaceBinds = lib.concatMap (n: [ - (bind "${mod} + ${toString n}" (luaCall "hl.dsp.focus" [ { workspace = n; } ])) - (bind "${mod} + SHIFT + ${toString n}" (luaCall "hl.dsp.window.move" [ { workspace = n; } ])) - ]) (lib.range 1 9); - - execBind = key: command: bind key (luaCall "hl.dsp.exec_cmd" [ command ]); - - inherit (lib.generators) mkLuaInline; - - mod = "SUPER"; - toLua = lib.generators.toLua { }; user = config.user.name; # Flip the tiling strategy between the two built-in layouts, since neither a @@ -237,23 +236,23 @@ in ]; bind = [ - (execBind "${mod} + Return" terminal) + (lua.execBind "SUPER + Return" "ghostty") # Move focus. - (bind "${mod} + H" (luaCall "hl.dsp.focus" [ { direction = "left"; } ])) - (bind "${mod} + J" (luaCall "hl.dsp.focus" [ { direction = "down"; } ])) - (bind "${mod} + K" (luaCall "hl.dsp.focus" [ { direction = "up"; } ])) - (bind "${mod} + L" (luaCall "hl.dsp.focus" [ { direction = "right"; } ])) + (lua.bind "SUPER + H" (lua.call "hl.dsp.focus" [ { direction = "left"; } ])) + (lua.bind "SUPER + J" (lua.call "hl.dsp.focus" [ { direction = "down"; } ])) + (lua.bind "SUPER + K" (lua.call "hl.dsp.focus" [ { direction = "up"; } ])) + (lua.bind "SUPER + L" (lua.call "hl.dsp.focus" [ { direction = "right"; } ])) # Move the window within the layout. - (bind "${mod} + SHIFT + H" (luaCall "hl.dsp.window.move" [ { direction = "left"; } ])) - (bind "${mod} + SHIFT + J" (luaCall "hl.dsp.window.move" [ { direction = "down"; } ])) - (bind "${mod} + SHIFT + K" (luaCall "hl.dsp.window.move" [ { direction = "up"; } ])) - (bind "${mod} + SHIFT + L" (luaCall "hl.dsp.window.move" [ { direction = "right"; } ])) + (lua.bind "SUPER + SHIFT + H" (lua.call "hl.dsp.window.move" [ { direction = "left"; } ])) + (lua.bind "SUPER + SHIFT + J" (lua.call "hl.dsp.window.move" [ { direction = "down"; } ])) + (lua.bind "SUPER + SHIFT + K" (lua.call "hl.dsp.window.move" [ { direction = "up"; } ])) + (lua.bind "SUPER + SHIFT + L" (lua.call "hl.dsp.window.move" [ { direction = "right"; } ])) # Resize the active window. - (bind "${mod} + ALT + H" ( - luaCall "hl.dsp.window.resize" [ + (lua.bind "SUPER + ALT + H" ( + lua.call "hl.dsp.window.resize" [ { x = -40; y = 0; @@ -261,8 +260,8 @@ in } ] )) - (bind "${mod} + ALT + J" ( - luaCall "hl.dsp.window.resize" [ + (lua.bind "SUPER + ALT + J" ( + lua.call "hl.dsp.window.resize" [ { x = 0; y = 40; @@ -270,8 +269,8 @@ in } ] )) - (bind "${mod} + ALT + K" ( - luaCall "hl.dsp.window.resize" [ + (lua.bind "SUPER + ALT + K" ( + lua.call "hl.dsp.window.resize" [ { x = 0; y = -40; @@ -279,8 +278,8 @@ in } ] )) - (bind "${mod} + ALT + L" ( - luaCall "hl.dsp.window.resize" [ + (lua.bind "SUPER + ALT + L" ( + lua.call "hl.dsp.window.resize" [ { x = 40; y = 0; @@ -289,41 +288,43 @@ in ] )) - (bind "${mod} + Space" (luaCall "hl.dsp.window.float" [ { action = "toggle"; } ])) - (bind "${mod} + F" (luaCall "hl.dsp.window.fullscreen" [ ])) + (lua.bind "SUPER + Space" (lua.call "hl.dsp.window.float" [ { action = "toggle"; } ])) + (lua.bind "SUPER + F" (lua.call "hl.dsp.window.fullscreen" [ ])) # togglesplit is a dwindle layout message, reached through layout. - (bind "${mod} + T" (luaCall "hl.dsp.layout" [ "togglesplit" ])) - (execBind "${mod} + SHIFT + T" "${toggleLayout}") - (bind "${mod} + SHIFT + Q" (luaCall "hl.dsp.window.close" [ ])) - (bind "${mod} + CTRL + Q" (luaCall "hl.dsp.window.kill" [ ])) + (lua.bind "SUPER + T" (lua.call "hl.dsp.layout" [ "togglesplit" ])) + (lua.execBind "SUPER + SHIFT + T" "${toggleLayout}") + (lua.bind "SUPER + SHIFT + Q" (lua.call "hl.dsp.window.close" [ ])) + (lua.bind "SUPER + CTRL + Q" (lua.call "hl.dsp.window.kill" [ ])) # Volume and brightness keys repeat while held, each raising a popup # through the OSD client. # Volume is capped at 100 percent. # The client floors brightness so a full hold cannot black the screen out. - (execBindWith "XF86AudioRaiseVolume" + (lua.execBindWith "XF86AudioRaiseVolume" "${pkgs.swayosd}/bin/swayosd-client --output-volume raise --max-volume 100" { repeating = true; } ) - (execBindWith "XF86AudioLowerVolume" "${pkgs.swayosd}/bin/swayosd-client --output-volume lower" { + (lua.execBindWith "XF86AudioLowerVolume" "${pkgs.swayosd}/bin/swayosd-client --output-volume lower" + { + repeating = true; + } + ) + (lua.execBindWith "XF86MonBrightnessUp" "${pkgs.swayosd}/bin/swayosd-client --brightness raise" { repeating = true; }) - (execBindWith "XF86MonBrightnessUp" "${pkgs.swayosd}/bin/swayosd-client --brightness raise" { - repeating = true; - }) - (execBindWith "XF86MonBrightnessDown" "${pkgs.swayosd}/bin/swayosd-client --brightness lower" { + (lua.execBindWith "XF86MonBrightnessDown" "${pkgs.swayosd}/bin/swayosd-client --brightness lower" { repeating = true; }) # Mute and media transport still fire while the session is locked. - (execBindWith "XF86AudioMute" "${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" { + (lua.execBindWith "XF86AudioMute" "${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" { locked = true; }) - (execBindWith "XF86AudioPlay" "${pkgs.playerctl}/bin/playerctl play-pause" { locked = true; }) - (execBindWith "XF86AudioNext" "${pkgs.playerctl}/bin/playerctl next" { locked = true; }) - (execBindWith "XF86AudioPrev" "${pkgs.playerctl}/bin/playerctl previous" { locked = true; }) + (lua.execBindWith "XF86AudioPlay" "${pkgs.playerctl}/bin/playerctl play-pause" { locked = true; }) + (lua.execBindWith "XF86AudioNext" "${pkgs.playerctl}/bin/playerctl next" { locked = true; }) + (lua.execBindWith "XF86AudioPrev" "${pkgs.playerctl}/bin/playerctl previous" { locked = true; }) ] - ++ workspaceBinds; + ++ lua.workspaceBinds; }; }; }; -- 2.47.3 From 9c9d3226714591ebfcf1079b00347499f85c4f97 Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:26:12 -0400 Subject: [PATCH 5/6] refactor(hyprland): write lua bind data directly --- .../desktop/session/hyprland/default.nix | 338 ++++++++++++------ 1 file changed, 235 insertions(+), 103 deletions(-) diff --git a/configs/nixos/modules/desktop/session/hyprland/default.nix b/configs/nixos/modules/desktop/session/hyprland/default.nix index 4ee7e6f..6776e0a 100644 --- a/configs/nixos/modules/desktop/session/hyprland/default.nix +++ b/configs/nixos/modules/desktop/session/hyprland/default.nix @@ -7,36 +7,6 @@ # The Hyprland compositor. let cfg = config.modules.desktop.session.hyprland; # NOLINT(let_order) - lua = rec { - toLua = lib.generators.toLua { }; - call = - function: args: - lib.generators.mkLuaInline "${function}(${lib.concatMapStringsSep ", " toLua args})"; - bind = key: dispatcher: { - _args = [ - key - dispatcher - ]; - }; - bindWith = key: dispatcher: options: { - _args = [ - key - dispatcher - options - ]; - }; - execBind = key: command: bind key (call "hl.dsp.exec_cmd" [ command ]); - execBindWith = - key: command: options: - bindWith key (call "hl.dsp.exec_cmd" [ command ]) options; - - # Numbered-workspace switch and move for 1..9, the operator's i3 muscle memory. - workspaceBinds = lib.concatMap (n: [ - (bind "SUPER + ${toString n}" (call "hl.dsp.focus" [ { workspace = n; } ])) - (bind "SUPER + SHIFT + ${toString n}" (call "hl.dsp.window.move" [ { workspace = n; } ])) - ]) (lib.range 1 9); - }; - cursor = config.stylix.cursor; user = config.user.name; @@ -236,95 +206,257 @@ in ]; bind = [ - (lua.execBind "SUPER + Return" "ghostty") + { + _args = [ + "SUPER + Return" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${(lib.generators.toLua { }) "ghostty"})") + ]; + } # Move focus. - (lua.bind "SUPER + H" (lua.call "hl.dsp.focus" [ { direction = "left"; } ])) - (lua.bind "SUPER + J" (lua.call "hl.dsp.focus" [ { direction = "down"; } ])) - (lua.bind "SUPER + K" (lua.call "hl.dsp.focus" [ { direction = "up"; } ])) - (lua.bind "SUPER + L" (lua.call "hl.dsp.focus" [ { direction = "right"; } ])) + { + _args = [ + "SUPER + H" + (lib.generators.mkLuaInline "hl.dsp.focus(${(lib.generators.toLua { }) { direction = "left"; }})") + ]; + } + { + _args = [ + "SUPER + J" + (lib.generators.mkLuaInline "hl.dsp.focus(${(lib.generators.toLua { }) { direction = "down"; }})") + ]; + } + { + _args = [ + "SUPER + K" + (lib.generators.mkLuaInline "hl.dsp.focus(${(lib.generators.toLua { }) { direction = "up"; }})") + ]; + } + { + _args = [ + "SUPER + L" + (lib.generators.mkLuaInline "hl.dsp.focus(${(lib.generators.toLua { }) { direction = "right"; }})") + ]; + } # Move the window within the layout. - (lua.bind "SUPER + SHIFT + H" (lua.call "hl.dsp.window.move" [ { direction = "left"; } ])) - (lua.bind "SUPER + SHIFT + J" (lua.call "hl.dsp.window.move" [ { direction = "down"; } ])) - (lua.bind "SUPER + SHIFT + K" (lua.call "hl.dsp.window.move" [ { direction = "up"; } ])) - (lua.bind "SUPER + SHIFT + L" (lua.call "hl.dsp.window.move" [ { direction = "right"; } ])) + { + _args = [ + "SUPER + SHIFT + H" + (lib.generators.mkLuaInline "hl.dsp.window.move(${ + (lib.generators.toLua { }) { direction = "left"; } + })") + ]; + } + { + _args = [ + "SUPER + SHIFT + J" + (lib.generators.mkLuaInline "hl.dsp.window.move(${ + (lib.generators.toLua { }) { direction = "down"; } + })") + ]; + } + { + _args = [ + "SUPER + SHIFT + K" + (lib.generators.mkLuaInline "hl.dsp.window.move(${ + (lib.generators.toLua { }) { direction = "up"; } + })") + ]; + } + { + _args = [ + "SUPER + SHIFT + L" + (lib.generators.mkLuaInline "hl.dsp.window.move(${ + (lib.generators.toLua { }) { direction = "right"; } + })") + ]; + } # Resize the active window. - (lua.bind "SUPER + ALT + H" ( - lua.call "hl.dsp.window.resize" [ - { - x = -40; - y = 0; - relative = true; - } - ] - )) - (lua.bind "SUPER + ALT + J" ( - lua.call "hl.dsp.window.resize" [ - { - x = 0; - y = 40; - relative = true; - } - ] - )) - (lua.bind "SUPER + ALT + K" ( - lua.call "hl.dsp.window.resize" [ - { - x = 0; - y = -40; - relative = true; - } - ] - )) - (lua.bind "SUPER + ALT + L" ( - lua.call "hl.dsp.window.resize" [ - { - x = 40; - y = 0; - relative = true; - } - ] - )) + { + _args = [ + "SUPER + ALT + H" + (lib.generators.mkLuaInline "hl.dsp.window.resize(${ + (lib.generators.toLua { }) { + x = -40; + y = 0; + relative = true; + } + })") + ]; + } + { + _args = [ + "SUPER + ALT + J" + (lib.generators.mkLuaInline "hl.dsp.window.resize(${ + (lib.generators.toLua { }) { + x = 0; + y = 40; + relative = true; + } + })") + ]; + } + { + _args = [ + "SUPER + ALT + K" + (lib.generators.mkLuaInline "hl.dsp.window.resize(${ + (lib.generators.toLua { }) { + x = 0; + y = -40; + relative = true; + } + })") + ]; + } + { + _args = [ + "SUPER + ALT + L" + (lib.generators.mkLuaInline "hl.dsp.window.resize(${ + (lib.generators.toLua { }) { + x = 40; + y = 0; + relative = true; + } + })") + ]; + } - (lua.bind "SUPER + Space" (lua.call "hl.dsp.window.float" [ { action = "toggle"; } ])) - (lua.bind "SUPER + F" (lua.call "hl.dsp.window.fullscreen" [ ])) + { + _args = [ + "SUPER + Space" + (lib.generators.mkLuaInline "hl.dsp.window.float(${ + (lib.generators.toLua { }) { action = "toggle"; } + })") + ]; + } + { + _args = [ + "SUPER + F" + (lib.generators.mkLuaInline "hl.dsp.window.fullscreen()") + ]; + } # togglesplit is a dwindle layout message, reached through layout. - (lua.bind "SUPER + T" (lua.call "hl.dsp.layout" [ "togglesplit" ])) - (lua.execBind "SUPER + SHIFT + T" "${toggleLayout}") - (lua.bind "SUPER + SHIFT + Q" (lua.call "hl.dsp.window.close" [ ])) - (lua.bind "SUPER + CTRL + Q" (lua.call "hl.dsp.window.kill" [ ])) + { + _args = [ + "SUPER + T" + (lib.generators.mkLuaInline "hl.dsp.layout(${(lib.generators.toLua { }) "togglesplit"})") + ]; + } + { + _args = [ + "SUPER + SHIFT + T" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${(lib.generators.toLua { }) "${toggleLayout}"})") + ]; + } + { + _args = [ + "SUPER + SHIFT + Q" + (lib.generators.mkLuaInline "hl.dsp.window.close()") + ]; + } + { + _args = [ + "SUPER + CTRL + Q" + (lib.generators.mkLuaInline "hl.dsp.window.kill()") + ]; + } # Volume and brightness keys repeat while held, each raising a popup # through the OSD client. # Volume is capped at 100 percent. # The client floors brightness so a full hold cannot black the screen out. - (lua.execBindWith "XF86AudioRaiseVolume" - "${pkgs.swayosd}/bin/swayosd-client --output-volume raise --max-volume 100" - { repeating = true; } - ) - (lua.execBindWith "XF86AudioLowerVolume" "${pkgs.swayosd}/bin/swayosd-client --output-volume lower" - { - repeating = true; - } - ) - (lua.execBindWith "XF86MonBrightnessUp" "${pkgs.swayosd}/bin/swayosd-client --brightness raise" { - repeating = true; - }) - (lua.execBindWith "XF86MonBrightnessDown" "${pkgs.swayosd}/bin/swayosd-client --brightness lower" { - repeating = true; - }) + { + _args = [ + "XF86AudioRaiseVolume" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) + "${pkgs.swayosd}/bin/swayosd-client --output-volume raise --max-volume 100" + })") + { repeating = true; } + ]; + } + { + _args = [ + "XF86AudioLowerVolume" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.swayosd}/bin/swayosd-client --output-volume lower" + })") + { repeating = true; } + ]; + } + { + _args = [ + "XF86MonBrightnessUp" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.swayosd}/bin/swayosd-client --brightness raise" + })") + { repeating = true; } + ]; + } + { + _args = [ + "XF86MonBrightnessDown" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.swayosd}/bin/swayosd-client --brightness lower" + })") + { repeating = true; } + ]; + } # Mute and media transport still fire while the session is locked. - (lua.execBindWith "XF86AudioMute" "${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" { - locked = true; - }) - (lua.execBindWith "XF86AudioPlay" "${pkgs.playerctl}/bin/playerctl play-pause" { locked = true; }) - (lua.execBindWith "XF86AudioNext" "${pkgs.playerctl}/bin/playerctl next" { locked = true; }) - (lua.execBindWith "XF86AudioPrev" "${pkgs.playerctl}/bin/playerctl previous" { locked = true; }) + { + _args = [ + "XF86AudioMute" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.swayosd}/bin/swayosd-client --output-volume mute-toggle" + })") + { locked = true; } + ]; + } + { + _args = [ + "XF86AudioPlay" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.playerctl}/bin/playerctl play-pause" + })") + { locked = true; } + ]; + } + { + _args = [ + "XF86AudioNext" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.playerctl}/bin/playerctl next" + })") + { locked = true; } + ]; + } + { + _args = [ + "XF86AudioPrev" + (lib.generators.mkLuaInline "hl.dsp.exec_cmd(${ + (lib.generators.toLua { }) "${pkgs.playerctl}/bin/playerctl previous" + })") + { locked = true; } + ]; + } ] - ++ lua.workspaceBinds; + ++ lib.concatMap (n: [ + { + _args = [ + "SUPER + ${toString n}" + (lib.generators.mkLuaInline "hl.dsp.focus(${(lib.generators.toLua { }) { workspace = n; }})") + ]; + } + { + _args = [ + "SUPER + SHIFT + ${toString n}" + (lib.generators.mkLuaInline "hl.dsp.window.move(${(lib.generators.toLua { }) { workspace = n; }})") + ]; + } + ]) (lib.range 1 9); }; }; }; -- 2.47.3 From 586e04fee2045266ce9add9d9c7971c748abaa2c Mon Sep 17 00:00:00 2001 From: alexion Date: Fri, 9 Oct 2026 20:29:19 -0400 Subject: [PATCH 6/6] refactor(hyprland): remove unused blur option --- .../nixos/modules/desktop/session/hyprland/default.nix | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/configs/nixos/modules/desktop/session/hyprland/default.nix b/configs/nixos/modules/desktop/session/hyprland/default.nix index 6776e0a..96f4dca 100644 --- a/configs/nixos/modules/desktop/session/hyprland/default.nix +++ b/configs/nixos/modules/desktop/session/hyprland/default.nix @@ -21,13 +21,7 @@ let ''; in { - options.modules.desktop.session.hyprland = { - enable = lib.mkEnableOption "the Hyprland compositor"; - - blur = lib.mkEnableOption '' - window blur. Off by default as the single biggest battery cost on a - laptop, left on for a host with the headroom to spend it''; - }; + options.modules.desktop.session.hyprland.enable = lib.mkEnableOption "the Hyprland compositor"; config = lib.mkIf cfg.enable { # This program integration owns the session, portals, and polkit, launched @@ -130,7 +124,6 @@ in decoration = { rounding = 6; - blur.enabled = cfg.blur; }; # XWayland clients render at the panel's native resolution instead of -- 2.47.3