nix-conf/system/modules/niri.nix
2026-03-06 17:06:53 +08:00

309 lines
9.8 KiB
Nix
Executable file

{
config,
pkgs,
lib,
...
}:
let
inherit (lib)
getExe
mkIf
pipe
mapAttrs
;
inherit (builtins) fetchurl genList listToAttrs;
inherit (config.systemConf) username;
niri_peekaboo = fetchurl {
url = "https://raw.githubusercontent.com/heyoeyo/niri_tweaks/refs/heads/main/niri_peekaboo.py";
sha256 = "sha256:0l1x0bsa9vr089jhzgcz3xbh1hg15sw6njb91q0j9pdbrp2ym3dc";
};
in
{
config = mkIf config.programs.niri.enable {
programs.niri = {
package = pkgs.niri-unstable;
};
home-manager.users."${username}" =
{
osConfig,
config,
...
}:
let
rNiri = pkgs.writeShellScriptBin "rNiri" ''
NIRI_SOCKET="/run/user/1000/$(ls /run/user/1000 | grep niri | head -n 1)" niri $@
'';
wmCfg = config.wm;
bindCfg = wmCfg.keybinds;
in
with config.lib.niri.actions;
{
home.packages = with pkgs; [
nautilus # xdg-desktop-portal-gnome file picker
rNiri
];
xdg.portal = {
extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
};
services.nfsm.enable = true;
programs.niri.package = osConfig.programs.niri.package;
programs.niri.settings = {
spawn-at-startup = [
{ argv = [ "${wmCfg.exec-once}" ]; }
];
screenshot-path = "~/Pictures/Screenshots/%Y-%m-%d_%H-%M-%S.png";
prefer-no-csd = true;
xwayland-satellite = {
enable = true;
path = getExe pkgs.xwayland-satellite-unstable;
};
animations = {
workspace-switch.kind.spring = {
damping-ratio = 1.0;
stiffness = 1000;
epsilon = 0.0001;
};
window-open.kind.easing = {
duration-ms = 150;
curve = "ease-out-expo";
};
window-close.kind.easing = {
duration-ms = 150;
curve = "ease-out-quad";
};
window-resize.kind.spring = {
damping-ratio = 1.0;
stiffness = 800;
epsilon = 0.0001;
};
};
layout.border = {
enable = true;
width = 4;
active.gradient = {
from = wmCfg.border.active.from;
to = wmCfg.border.active.to;
angle = wmCfg.border.active.angle;
in' = "oklab";
relative-to = "window";
};
inactive.gradient = {
from = wmCfg.border.inactive.from;
to = wmCfg.border.inactive.to;
angle = wmCfg.border.inactive.angle;
in' = "oklab";
relative-to = "window";
};
};
blur = {
passes = 3;
offset = 3;
noise = 0.02;
saturation = 1.5;
};
debug = {
honor-xdg-activation-with-invalid-serial = [ ];
};
layer-rules = [
{
matches = [
{ namespace = "^noctalia-overview*"; }
];
place-within-backdrop = true;
}
{
matches = [
{ namespace = "^noctalia-background-.*$"; }
];
background-effect = {
blur = true;
};
}
];
window-rules = [
# Global
{
background-effect = {
blur = true;
};
geometry-corner-radius =
let
round = wmCfg.border.radius + 0.0;
in
{
bottom-left = round;
bottom-right = round;
top-left = round;
top-right = round;
};
clip-to-geometry = true;
opacity = 0.8;
draw-border-with-background = false;
}
# non transparent
{
matches = [
{ app-id = "^(com.mitchellh.ghostty)$"; }
{ app-id = "^(zen-twilight)$"; }
];
opacity = 1.0;
}
# Float
{
matches = [
{ app-id = "^xdg-desktop-portal-gtk$"; }
{ app-id = "^(org.gnome.Nautilus)$"; }
{ app-id = "^(org.gnome.Loupe)$"; }
];
open-floating = true;
}
];
input = {
focus-follows-mouse = {
max-scroll-amount = "90%";
enable = true;
};
mouse.accel-speed = -0.1;
keyboard = {
repeat-delay = wmCfg.input.keyboard.repeat-delay;
repeat-rate = wmCfg.input.keyboard.repeat-rate;
};
};
binds =
let
sh = spawn "sh" "-c";
spawnKeybinds = mapAttrs (name: value: {
action = sh value;
}) (wmCfg.keybinds.spawn-repeat // wmCfg.keybinds.spawn);
in
spawnKeybinds
// {
# ==== Movement ==== #
# Mouse Scroll
"Mod+WheelScrollDown" = {
cooldown-ms = 150;
action = focus-workspace-down;
};
"Mod+WheelScrollUp" = {
cooldown-ms = 150;
action = focus-workspace-up;
};
"Mod+Shift+WheelScrollDown" = {
cooldown-ms = 150;
action = focus-column-or-monitor-right;
};
"Mod+Shift+WheelScrollUp" = {
cooldown-ms = 150;
action = focus-column-or-monitor-left;
};
"Mod+WheelScrollRight".action = focus-column-right;
"Mod+WheelScrollLeft".action = focus-column-left;
# Touchpad
"Mod+TouchpadScrollDown" = {
cooldown-ms = 150;
action = focus-window-or-workspace-down;
};
"Mod+TouchpadScrollUp" = {
cooldown-ms = 150;
action = focus-window-or-workspace-up;
};
# Monitor Focus
"${bindCfg.move-monitor-focus.left}".action = focus-monitor-left;
"${bindCfg.move-monitor-focus.right}".action = focus-monitor-right;
# Workspace Focus
"${bindCfg.move-workspace-focus.next}".action = focus-workspace-down;
"${bindCfg.move-workspace-focus.prev}".action = focus-workspace-up;
# General Focus
"${bindCfg.move-window-focus.down}".action = focus-window-or-workspace-down;
"${bindCfg.move-window-focus.up}".action = focus-window-or-workspace-up;
"${bindCfg.move-window-focus.left}".action = focus-column-or-monitor-left;
"${bindCfg.move-window-focus.right}".action = focus-column-or-monitor-right;
# Workspace Move
"${bindCfg.move-workspace.down}".action = move-workspace-down;
"${bindCfg.move-workspace.up}".action = move-workspace-up;
# Window & Column Move
"${bindCfg.move-window.down}".action = move-window-down-or-to-workspace-down;
"${bindCfg.move-window.up}".action = move-window-up-or-to-workspace-up;
"${bindCfg.move-window.right}".action = move-column-right-or-to-monitor-right;
"${bindCfg.move-window.left}".action = move-column-left-or-to-monitor-left;
# Window Comsume
"${bindCfg.consume-window.right}".action = consume-or-expel-window-right;
"${bindCfg.consume-window.left}".action = consume-or-expel-window-left;
# ==== Action ==== #
# General
"${bindCfg.center-window}".action = center-window;
"${bindCfg.toggle-overview}".action = toggle-overview;
"${bindCfg.close-window}".action = close-window;
"${bindCfg.toggle-fullscreen}".action =
if config.services.nfsm.enable then (spawn "nfsm-cli") else fullscreen-window;
"Mod+Shift+slash".action = show-hotkey-overlay;
"Mod+Ctrl+Shift+P".action = spawn "${getExe pkgs.python312}" "${niri_peekaboo}";
# Column Scale
"${bindCfg.switch-preset-column-width}".action = switch-preset-column-width;
"${bindCfg.switch-preset-window-height}".action = switch-preset-window-height;
"${bindCfg.expand-column-to-available-width}".action = expand-column-to-available-width;
"${bindCfg.maximize-column}".action = maximize-column;
"${bindCfg.reset-window-height}".action = reset-window-height;
# Float
"${bindCfg.toggle-float}".action = toggle-window-floating;
"${bindCfg.switch-focus-between-floating-and-tiling}".action =
switch-focus-between-floating-and-tiling;
# Screenshot
"${bindCfg.screenshot.area}".action.screenshot = [ { show-pointer = false; } ];
"${bindCfg.screenshot.window}".action.screenshot-window = [
{
write-to-disk = false;
}
];
"${bindCfg.screenshot.screen}".action.screenshot-screen = [
{
write-to-disk = false;
}
];
}
# Map Mod+{1 ~ 9} to workspace{1 ~ 9}
// (pipe 9 [
(x: genList (i: i + 1) x)
(
x:
map (i: {
name = "${bindCfg.focus-workspace-prefix}+${toString i}";
value.action = focus-workspace i;
}) x
)
(x: listToAttrs x)
]);
};
};
};
}