# Only renders ~/.config/niri/config.kdl; niri itself, its session and portals # come from modules/nixos/niri.nix. Outputs and input devices that differ # per machine live in hosts//niri.nix. { config, lib, osConfig, ... }: let # Mod+1..9 focus a workspace, Mod+Ctrl+1..9 move the column there workspaceBinds = lib.mergeAttrsList ( map (n: { "Mod+${toString n}".focus-workspace = n; "Mod+Ctrl+${toString n}".move-column-to-workspace = n; }) (lib.range 1 9) ); # shell command that also works on the lock screen lockedSh = cmd: { _props.allow-when-locked = true; spawn-sh = cmd; }; # niri has no stylix target, so the colors are picked here colors = config.lib.stylix.colors.withHashtag; in { wayland.windowManager.niri = { # only on hosts that run niri enable = osConfig.programs.niri.enable; # validate the config against the installed niri package = osConfig.programs.niri.package; systemd.enable = false; portalPackage = null; xwaylandSatellitePackage = null; # installed system-wide settings = { input = { keyboard = { xkb.layout = "ch"; xkb.variant = "nodeadkeys"; numlock = { }; }; mouse = { natural-scroll = { }; accel-speed = 0.5; scroll-method = "no-scroll"; }; }; environment.GTK_IM_MODULE = "simple"; layout = { gaps = 16; center-focused-column = "never"; preset-column-widths._children = [ { proportion = 0.33333; } { proportion = 0.5; } { proportion = 0.66667; } { fixed = 2560; } ]; default-column-width.proportion = 0.5; focus-ring = { on = { }; width = 2; active-color = colors.base03; inactive-color = colors.base00; urgent-color = colors.base0B; }; border.off = { }; shadow = { on = { }; draw-behind-window = true; softness = 30; spread = 10; offset._props = { x = 0; y = 5; }; color = "#0007"; }; }; spawn-at-startup = "noctalia"; hotkey-overlay.skip-at-startup = { }; screenshot-path = "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"; _children = [ # Open the Firefox picture-in-picture player as floating by default. { window-rule._children = [ { match._props = { app-id = "firefox$"; title = "^Picture-in-Picture$"; }; } { open-floating = true; } ]; } # Block out the password manager from screen capture. { window-rule._children = [ { match._props.app-id = "^org\\.keepassxc\\.KeePassXC$"; } { block-out-from = "screen-capture"; } ]; } { window-rule = { geometry-corner-radius = 12; clip-to-geometry = true; }; } ]; binds = workspaceBinds // { # programs: terminal, app launcher, screen locker "Mod+Return" = { _props.hotkey-overlay-title = "Open a Terminal"; spawn = "ghostty"; }; "Mod+D" = { _props.hotkey-overlay-title = "Run an Application"; spawn-sh = "noctalia msg panel-toggle launcher"; }; "Super+Alt+L" = { _props.hotkey-overlay-title = "Lock the Screen"; spawn-sh = "noctalia msg session lock"; }; # media keys (PipeWire / WirePlumber) "XF86AudioRaiseVolume" = lockedSh "wpctl set-volume @DEFAULT_SINK@ 0.01+ -l 1.0"; "XF86AudioLowerVolume" = lockedSh "wpctl set-volume @DEFAULT_SINK@ 0.01-"; "XF86AudioMute" = lockedSh "wpctl set-mute @DEFAULT_SINK@ toggle"; "XF86AudioMicMute" = lockedSh "wpctl set-mute @DEFAULT_SOURCE@ toggle"; "XF86AudioPlay" = lockedSh "playerctl play-pause"; "XF86AudioStop" = lockedSh "playerctl stop"; "XF86AudioPrev" = lockedSh "playerctl previous"; "XF86AudioNext" = lockedSh "playerctl next"; "XF86MonBrightnessUp" = lockedSh "brightnessctl --class=backlight set +10%"; "XF86MonBrightnessDown" = lockedSh "brightnessctl --class=backlight set 10%-"; "Mod+O" = { _props.repeat = false; toggle-overview = { }; }; "Mod+Q" = { _props.repeat = false; close-window = { }; }; # focus / move columns and windows "Mod+Left".focus-column-left = { }; "Mod+Down".focus-window-down = { }; "Mod+Up".focus-window-up = { }; "Mod+Right".focus-column-right = { }; "Mod+H".focus-column-left = { }; "Mod+J".focus-window-down = { }; "Mod+K".focus-window-up = { }; "Mod+L".focus-column-right = { }; "Mod+Shift+Left".move-column-left = { }; "Mod+Shift+Down".move-window-down = { }; "Mod+Shift+Up".move-window-up = { }; "Mod+Shift+Right".move-column-right = { }; "Mod+Shift+H".move-column-left = { }; "Mod+Shift+J".move-window-down = { }; "Mod+Shift+K".move-window-up = { }; "Mod+Shift+L".move-column-right = { }; "Mod+Home".focus-column-first = { }; "Mod+End".focus-column-last = { }; "Mod+Ctrl+Home".move-column-to-first = { }; "Mod+Ctrl+End".move-column-to-last = { }; # move columns between monitors "Mod+Ctrl+Left".move-column-to-monitor-left = { }; "Mod+Ctrl+Down".move-column-to-monitor-down = { }; "Mod+Ctrl+Up".move-column-to-monitor-up = { }; "Mod+Ctrl+Right".move-column-to-monitor-right = { }; "Mod+Ctrl+H".move-column-to-monitor-left = { }; "Mod+Ctrl+J".move-column-to-monitor-down = { }; "Mod+Ctrl+K".move-column-to-monitor-up = { }; "Mod+Ctrl+L".move-column-to-monitor-right = { }; # workspaces "Mod+Page_Down".focus-workspace-down = { }; "Mod+Page_Up".focus-workspace-up = { }; "Mod+U".focus-workspace-down = { }; "Mod+I".focus-workspace-up = { }; "Mod+Ctrl+Page_Down".move-column-to-workspace-down = { }; "Mod+Ctrl+Page_Up".move-column-to-workspace-up = { }; "Mod+Ctrl+U".move-column-to-workspace-down = { }; "Mod+Ctrl+I".move-column-to-workspace-up = { }; "Mod+Shift+Page_Down".move-workspace-down = { }; "Mod+Shift+Page_Up".move-workspace-up = { }; "Mod+Shift+U".move-workspace-down = { }; "Mod+Shift+I".move-workspace-up = { }; # mouse wheel "Mod+WheelScrollDown" = { _props.cooldown-ms = 150; focus-workspace-down = { }; }; "Mod+WheelScrollUp" = { _props.cooldown-ms = 150; focus-workspace-up = { }; }; "Mod+Ctrl+WheelScrollDown" = { _props.cooldown-ms = 150; move-column-to-workspace-down = { }; }; "Mod+Ctrl+WheelScrollUp" = { _props.cooldown-ms = 150; move-column-to-workspace-up = { }; }; "Mod+WheelScrollRight".focus-column-right = { }; "Mod+WheelScrollLeft".focus-column-left = { }; "Mod+Ctrl+WheelScrollRight".move-column-right = { }; "Mod+Ctrl+WheelScrollLeft".move-column-left = { }; "Mod+Shift+WheelScrollDown".focus-column-right = { }; "Mod+Shift+WheelScrollUp".focus-column-left = { }; "Mod+Ctrl+Shift+WheelScrollDown".move-column-right = { }; "Mod+Ctrl+Shift+WheelScrollUp".move-column-left = { }; # columns "Mod+BracketLeft".consume-or-expel-window-left = { }; "Mod+BracketRight".consume-or-expel-window-right = { }; "Mod+Comma".consume-window-into-column = { }; "Mod+Period".expel-window-from-column = { }; "Mod+R".switch-preset-column-width = { }; "Mod+Shift+R".switch-preset-window-height = { }; "Mod+Ctrl+R".reset-window-height = { }; "Mod+F".maximize-column = { }; "Mod+Shift+F".fullscreen-window = { }; "Mod+Ctrl+F".expand-column-to-available-width = { }; "Mod+C".center-column = { }; "Mod+Ctrl+C".center-visible-columns = { }; "Mod+Minus".set-column-width = "-10%"; "Mod+Equal".set-column-width = "+10%"; "Mod+Shift+Minus".set-window-height = "-10%"; "Mod+Shift+Equal".set-window-height = "+10%"; "Mod+Space".toggle-window-floating = { }; "Mod+Shift+Space".switch-focus-between-floating-and-tiling = { }; "Mod+W".toggle-column-tabbed-display = { }; # screenshots "Mod+P".screenshot = { }; "Alt+Print".screenshot-window = { }; # escape hatch for apps that inhibit keyboard shortcuts "Mod+Escape" = { _props.allow-inhibiting = false; toggle-keyboard-shortcuts-inhibit = { }; }; "Mod+Shift+E".quit = { }; }; }; }; }