# This file contains the Niri configuration that will only be included on Linux { options, config, lib, inputs, pkgs, ... }: with lib; with lib.custom; let cfg = config.wms.niri; mkService = recursiveUpdate { Unit.PartOf = ["graphical-session.target"]; Unit.After = ["graphical-session.target"]; Install.WantedBy = ["graphical-session.target"]; }; actions = config.lib.niri.actions; niri = "${config.programs.niri.package}/bin/niri"; mkColor = color: {inherit color;}; mkGradient = from: to: { angle ? 180, relative-to ? "window", in' ? null, }: { gradient = {inherit from to angle relative-to in';}; }; spawnSlackOnWeekday = pkgs.writeShellScriptBin "spawn-slack-on-weekday" '' # Get the day of the week (1=Monday, ..., 7=Sunday) DAY_OF_WEEK=$(${pkgs.coreutils}/bin/date +%u) # Check if it's a weekday (between 1 and 5 inclusive) if [ "$DAY_OF_WEEK" -ge 1 ] && [ "$DAY_OF_WEEK" -le 5 ]; then # Execute Slack. Use the full path for robustness. # Ensure pkgs.slack is available (e.g., via environment.systemPackages) exec ${pkgs.slack}/bin/slack fi # Exit successfully if not a weekday or after exec replaces the process exit 0 ''; in { config = mkIf cfg.enable { programs.niri = { package = pkgs.niri; settings = { # Input device configuration input = { keyboard = { xkb = { rules = ""; model = ""; layout = "us"; variant = ""; options = "ctrl:nocaps"; }; }; touchpad = { enable = true; tap = true; dwt = true; dwtp = true; natural-scroll = true; # Other options # accel-profile = "flat"; # accel-speed = 0.0; disabled-on-external-mouse = true; }; mouse = { enable = true; natural-scroll = false; accel-speed = 0.0; accel-profile = "flat"; }; trackpoint = { enable = true; natural-scroll = false; # accel-profile = "flat"; # accel-speed = 0.0; # scroll-button = "middle"; middle-emulation = true; }; warp-mouse-to-focus = true; focus-follows-mouse = { enable = true; threshold = 1; }; }; # Output configuration outputs."DP-1" = { enable = true; mode = { width = 2560; height = 1440; refresh = 240.000; }; variable-refresh-rate = true; scale = 1.0; transform = { flipped = false; rotation = 0; }; position = { x = 0; y = 0; }; }; # Environment variables environment = { DISPLAY = ":0"; # for applications using xwayland-satillite }; hotkey-overlay = { skip-at-startup = true; }; # Window manager behavior layout = { gaps = 4; center-focused-column = true; # Column widths in preset-column-widths are relative to the available space preset-column-widths = [ {proportion = 1.0;} # One column that takes all available space {proportion = 0.5;} # Two columns of equal size {proportion = 0.66;} # Two columns: first takes 2/3, second takes 1/3 ]; # A new column will use this width by default default-column-width = { proportion = 0.5; # Half of the available space }; # Focused window highlight focus-ring = { enable = true; width = 4; active = mkGradient colors.lavender.hex colors.sapphire.hex { angle = 45; }; inactive = mkGradient colors.overlay0.hex colors.overlay0.hex { angle = 45; relative-to = "window"; }; }; # Window borders border = { enable = true; width = 4; active = colors.lavender.hex; inactive = colors.overlay0.hex; }; # Reserved screen areas (e.g., for panels) struts = { left = 0; right = 0; top = 0; bottom = 0; }; }; # Spawn processes at startup spawn-at-startup = [ {command = ["xwayland-satellite"];} {command = ["${pkgs.writeShellScriptBin "thunderbird-delayed" ''sleep 5; thunderbird''}/bin/thunderbird-delayed"];} {command = ["${pkgs.writeShellScriptBin "zen-delayed" ''sleep 5; zen''}/bin/zen-delayed"];} {command = ["vesktop"];} {command = ["spotify"];} {command = ["${spawnSlackOnWeekday}/bin/spawn-slack-on-weekday"];} ]; # Prefer server-side decorations prefer-no-csd = true; # Screenshot path screenshot-path = "${config.home.homeDirectory}/Pictures/screenshots/Screenshot_%F_%H-%M-%S.png"; # Animations for windows, workspace transitions, etc. animations = { enable = true; }; debug = { wait-for-frame-completion-in-pipewire = []; }; layer-rules = [ { # Match layer shell surfaces with the GTK layer shell namespace matches = [ {namespace = "gtk-layer-shell";} ]; # Don't blur out this layer shell surface block-out-from = ["blur"]; } ]; window-rules = [ { # Matching criteria matches = [ {app-id = "waybar";} {app-id = "eww-bar";} {app-id = "ags";} {app-id = "gtk-layer-shell";} {app-id = "mako";} {app-id = "swaync-client";} {app-id = "swaync-control-center";} ]; # Rules block-out-from = ["blur"]; } # Configure rounded corners { geometry-corner-radius = { top-left = 0; top-right = 0; bottom-left = 0; bottom-right = 0; }; clip-to-geometry = true; } # Configure a different appearance for window cast targets { matches = [{is-window-cast-target = true;}]; focus-ring = { active = colors.red.hex; inactive = colors.red.hex; }; shadow = { color = colors.red.hex; }; tab-indicator = { active = colors.red.hex; inactive = colors.red.hex; }; } # Configure floating Windows { matches = [ {app-id = "zenity";} ]; excludes = [ {title = "Zen Browser";} ]; open-floating = true; open-focused = true; default-floating-position = { relative-to = "window-manager"; x = 0; y = 0; }; } # Configure video apps { matches = [ {app-id = "mpv";} {app-id = "io.github.celluloid_player.Celluloid";} ]; variable-refresh-rate = true; } # Configure maximized Firefox { matches = [ {at-startup = true;} {app-id = "firefox";} ]; open-maximized = true; open-on-workspace = "01-browser"; } # Configure Zen Browser { matches = [ {at-startup = true;} {app-id = "zen";} ]; open-on-workspace = "01-browser"; } # Configure VSCode { matches = [ {at-startup = true;} {app-id = "code-url-handler";} ]; open-on-workspace = "02-code"; } # Configure chat apps { matches = [ {at-startup = true;} {app-id = "vesktop";} ]; open-on-workspace = "03-chat"; } ]; # Named workspaces workspaces."01-browser" = { name = "browser"; }; workspaces."02-code" = { name = "code"; }; workspaces."03-chat" = { name = "chat"; }; workspaces."04-work" = { name = "work"; }; # Keybindings binds = { # Show help "Mod+Shift+Slash" = {action = actions.show-hotkey-overlay;}; # Terminal and launcher "Mod+Return" = {action = actions.spawn "kitty";}; "Mod+D" = {action = actions.spawn "fuzzel";}; "Super+Alt+L" = {action = actions.spawn "swaylock";}; # "Mod+T" = { action = actions.spawn "bash" "-c" "notify-send hello && exec alacritty"; }; # "Mod+S" = {action = actions.set-dynamic-cast-window;}; # # "Mod+Shift+S" = {action = actions.set-dynamic-cast-monitor;}; # # "XF86AudioLowerVolume" = { # action = actions.spawn "pamixer" "--decrease" "5"; # allow-when-locked = true; # }; # "XF86AudioRaiseVolume" = { # action = actions.spawn "pamixer" "--increase" "5"; # allow-when-locked = true; # }; # "XF86AudioMute" = { # action = actions.spawn "pamixer" "--toggle-mute"; # allow-when-locked = true; # }; # "XF86AudioMicMute" = { # action = actions.spawn "pamixer" "--default-source" "--toggle-mute"; # allow-when-locked = true; # }; # "XF86MonBrightnessDown" = { # action = actions.spawn "brightnessctl" "set" "5%-"; # allow-when-locked = true; # }; # "XF86MonBrightnessUp" = { # action = actions.spawn "brightnessctl" "set" "5%+"; # allow-when-locked = true; # }; # Media controls "XF86AudioRaiseVolume" = { allow-when-locked = true; action = actions.spawn "pamixer" "-i" "5"; }; "XF86AudioLowerVolume" = { allow-when-locked = true; action = actions.spawn "pamixer" "-d" "5"; }; "XF86AudioMute" = { allow-when-locked = true; action = actions.spawn "pamixer" "--toggle-mute"; }; "XF86AudioMicMute" = { allow-when-locked = true; action = actions.spawn "pamixer" "--default-source" "--toggle-mute"; }; # Close window "Mod+Q" = {action = actions.close-window;}; # Focus windows and columns "Mod+Left" = {action = actions.focus-column-left;}; "Mod+Down" = {action = actions.focus-window-down;}; "Mod+Up" = {action = actions.focus-window-up;}; "Mod+Right" = {action = actions.focus-column-right;}; "Mod+H" = {action = actions.focus-column-left;}; "Mod+J" = {action = actions.focus-window-down;}; "Mod+K" = {action = actions.focus-window-up;}; "Mod+L" = {action = actions.focus-column-right;}; # Move windows within a column "Mod+Ctrl+Left" = {action = actions.move-column-left;}; "Mod+Ctrl+Down" = {action = actions.move-window-down;}; "Mod+Ctrl+Up" = {action = actions.move-window-up;}; "Mod+Ctrl+Right" = {action = actions.move-column-right;}; "Mod+Ctrl+H" = {action = actions.move-column-left;}; "Mod+Ctrl+J" = {action = actions.move-window-down;}; "Mod+Ctrl+K" = {action = actions.move-window-up;}; "Mod+Ctrl+L" = {action = actions.move-column-right;}; # "Mod+Alt+Left" = {action = actions.move-to-monitor-left;}; # "Mod+Alt+Down" = {action = actions.move-to-monitor-down;}; # "Mod+Alt+Up" = {action = actions.move-to-monitor-up;}; # "Mod+Alt+Right" = {action = actions.move-to-monitor-right;}; # "Mod+Alt+H" = {action = actions.move-to-monitor-left;}; # "Mod+Alt+J" = {action = actions.move-to-monitor-down;}; # "Mod+Alt+K" = {action = actions.move-to-monitor-up;}; # "Mod+Alt+L" = {action = actions.move-to-monitor-right;}; "Mod+Home" = {action = actions.focus-column-first;}; "Mod+End" = {action = actions.focus-column-last;}; "Mod+Ctrl+Home" = {action = actions.move-column-to-first;}; "Mod+Ctrl+End" = {action = actions.move-column-to-last;}; # Move window out of column "Mod+Shift+Left" = {action = actions.move-view-left;}; "Mod+Shift+Down" = {action = actions.move-view-down;}; "Mod+Shift+Up" = {action = actions.move-view-up;}; "Mod+Shift+Right" = {action = actions.move-view-right;}; "Mod+Shift+H" = {action = actions.move-view-left;}; "Mod+Shift+J" = {action = actions.move-view-down;}; "Mod+Shift+K" = {action = actions.move-view-up;}; "Mod+Shift+L" = {action = actions.move-view-right;}; "Mod+Ctrl+Shift+F" = {action = actions.toggle-windowed-fullscreen;}; # Move to a different monitor "Mod+Shift+Ctrl+Left" = {action = actions.move-to-monitor-left;}; "Mod+Shift+Ctrl+Down" = {action = actions.move-to-monitor-down;}; "Mod+Shift+Ctrl+Up" = {action = actions.move-to-monitor-up;}; "Mod+Shift+Ctrl+Right" = {action = actions.move-to-monitor-right;}; "Mod+Shift+Ctrl+H" = {action = actions.move-to-monitor-left;}; "Mod+Shift+Ctrl+J" = {action = actions.move-to-monitor-down;}; "Mod+Shift+Ctrl+K" = {action = actions.move-to-monitor-up;}; "Mod+Shift+Ctrl+L" = {action = actions.move-to-monitor-right;}; # Switch to workspace "Mod+Page_Down" = {action = actions.focus-workspace-down;}; "Mod+Page_Up" = {action = actions.focus-workspace-up;}; "Mod+U" = {action = actions.focus-workspace-previous;}; "Mod+I" = {action = actions.focus-workspace-next;}; "Mod+Ctrl+Page_Down" = {action = actions.move-column-to-workspace-down;}; "Mod+Ctrl+Page_Up" = {action = actions.move-column-to-workspace-up;}; "Mod+Ctrl+U" = {action = actions.move-column-to-workspace-down;}; "Mod+Ctrl+I" = {action = actions.move-column-to-workspace-up;}; # Move window to workspace "Mod+Shift+Page_Down" = {action = actions.move-view-to-workspace-down;}; "Mod+Shift+Page_Up" = {action = actions.move-view-to-workspace-up;}; "Mod+Shift+U" = {action = actions.move-view-to-workspace-previous;}; "Mod+Shift+I" = {action = actions.move-view-to-workspace-next;}; # Switch workspaces using scroll wheel "Mod+WheelScrollDown" = { cooldown-ms = 50; action = actions.focus-workspace-down; }; "Mod+WheelScrollUp" = { cooldown-ms = 50; action = actions.focus-workspace-up; }; "Mod+Ctrl+WheelScrollDown" = { cooldown-ms = 50; action = actions.move-column-to-workspace-down; }; "Mod+Ctrl+WheelScrollUp" = { cooldown-ms = 50; action = actions.move-column-to-workspace-up; }; "Mod+WheelScrollRight" = {action = actions.focus-column-right;}; "Mod+WheelScrollLeft" = {action = actions.focus-column-left;}; "Mod+Ctrl+WheelScrollRight" = {action = actions.move-column-right;}; "Mod+Ctrl+WheelScrollLeft" = {action = actions.move-column-left;}; "Mod+Shift+WheelScrollDown" = {action = actions.move-view-to-workspace-down;}; "Mod+Shift+WheelScrollUp" = {action = actions.move-view-to-workspace-up;}; "Mod+Ctrl+Shift+WheelScrollDown" = {action = actions.move-view-to-workspace-down;}; "Mod+Ctrl+Shift+WheelScrollUp" = {action = actions.move-view-to-workspace-up;}; # Named workspaces "Mod+Comma" = {action = actions.focus-workspace-previous;}; "Mod+Period" = {action = actions.focus-workspace-next;}; "Mod+BracketLeft" = {action = actions.consume-or-expel-window-left;}; "Mod+BracketRight" = {action = actions.consume-or-expel-window-right;}; "Mod+R" = {action = actions.switch-preset-column-width;}; "Mod+Shift+R" = {action = actions.switch-preset-window-height;}; "Mod+Ctrl+R" = {action = actions.reset-window-height;}; "Mod+F" = {action = actions.maximize-column;}; "Mod+Shift+F" = {action = actions.toggle-fullscreen;}; "Mod+C" = {action = actions.center-column;}; "Mod+Ctrl+F" = {action = actions.expand-column-to-available-width;}; "Mod+V" = {action = actions.toggle-floating;}; "Mod+Minus" = {action = actions.decrease-column-width;}; "Mod+Equal" = {action = actions.increase-column-width;}; "Mod+Shift+Minus" = {action = actions.set-column-width 33;}; "Mod+Shift+Equal" = {action = actions.set-column-width 67;}; "Print" = {action = actions.screen-shot {};}; "Mod+Shift+E" = {action = actions.quit {};}; # Default: no skip-confirmation "Ctrl+Alt+Delete" = {action = actions.quit {};}; "Mod+Shift+P" = {action = actions.lock-screen {};}; # Navigate to specific workspaces # These bindings use the names of the workspaces defined above "Mod+1" = { action = actions.focus-workspace "01-browser"; }; "Mod+2" = { action = actions.focus-workspace "02-code"; }; "Mod+3" = { action = actions.focus-workspace "03-chat"; }; "Mod+4" = { action = actions.focus-workspace "04-work"; }; }; }; systemd.user.services = { swaybg = mkService { Unit.Description = "Wallpaper Chooser"; Service = { ExecStart = "${getExe pkgs.swaybg} -i ${wallpaper}"; Restart = "always"; }; }; }; }; }; }