diff --git a/flake.in.nix b/flake.in.nix index 8d1fac1..d3a20bf 100644 --- a/flake.in.nix +++ b/flake.in.nix @@ -65,6 +65,7 @@ hyprlock = flake "github:hyprwm/hyprlock" // unstable "nixpkgs"; hyprpaper = flake "github:hyprwm/hyprpaper" // unstable "nixpkgs"; hyprpicker = flake "github:hyprwm/hyprpicker" // unstable "nixpkgs"; + niri = flake "github:sodiboo/niri-flake" // unstable "nixpkgs"; nix-flatpak = flake "github:gmodena/nix-flatpak?ref=v0.5.1"; nix-vscode-extensions = flake "github:nix-community/nix-vscode-extensions" // unstable "nixpkgs"; nixd = flake "github:nix-community/nixd" // unstable "nixpkgs"; @@ -131,6 +132,7 @@ inputs.arion.nixosModules.arion inputs.disko.nixosModules.disko inputs.fw-fanctrl.nixosModules.default + inputs.niri.nixosModules.niri ]; home-manager.users.${config.custom.username}.imports = [ diff --git a/flake.nix b/flake.nix index 7a9f471..5cf444d 100644 --- a/flake.nix +++ b/flake.nix @@ -95,6 +95,10 @@ flake = false; url = "github:Rawa/lifx-cli"; }; + niri = { + inputs.nixpkgs.follows = "nixpkgs-unstable"; + url = "github:sodiboo/niri-flake"; + }; nix-flatpak.url = "github:gmodena/nix-flatpak?ref=v0.5.1"; nix-index-database-stable = { inputs.nixpkgs.follows = "nixpkgs-stable"; diff --git a/machines/myork/default.nix b/machines/myork/default.nix index dedab8d..f0ea4b5 100644 --- a/machines/myork/default.nix +++ b/machines/myork/default.nix @@ -54,6 +54,19 @@ in { }; home-manager.users.${config.custom.username} = { + programs.niri.settings.outputs = { + "eDP-1" = { + background-color = "#073642"; + + mode = with config.custom; { + inherit width height; + refresh = refresh + 0.0; + }; + + scale = config.custom.scale; + }; + }; + wayland.windowManager.hyprland.settings = { device = [ { diff --git a/options/custom/default.nix b/options/custom/default.nix index f442185..8d7160e 100644 --- a/options/custom/default.nix +++ b/options/custom/default.nix @@ -31,7 +31,7 @@ in { # TODO: Use option for border size border = mkOption {default = 2;}; - gap = mkOption {default = 5;}; + gap = mkOption {default = 15;}; padding = mkOption {default = 51;}; # ?? journalctl --user -u waybar.service | grep height: rounding = mkOption {default = 10;}; diff --git a/options/custom/desktops/default.nix b/options/custom/desktops/default.nix index c247e86..f07701e 100644 --- a/options/custom/desktops/default.nix +++ b/options/custom/desktops/default.nix @@ -8,6 +8,7 @@ with lib; { #// gnome.enable = true; hyprland.enable = true; #// kde.enable = true; + niri.enable = true; #// sway.enable = true; }; } diff --git a/options/custom/desktops/niri/binds.nix b/options/custom/desktops/niri/binds.nix new file mode 100644 index 0000000..3fdc141 --- /dev/null +++ b/options/custom/desktops/niri/binds.nix @@ -0,0 +1,125 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + audio = "~/.local/bin/audio"; + cat = "${pkgs.coreutils}/bin/cat"; + clipse = "${pkgs.clipse}/bin/clipse"; + codium = "${config.home-manager.users.${config.custom.username}.programs.vscode.package}/bin/codium"; + gnome-text-editor = "${pkgs.gnome-text-editor}/bin/gnome-text-editor"; + hyprlock = "${config.home-manager.users.${config.custom.username}.programs.hyprlock.package}/bin/hyprlock"; + hyprpicker = "${pkgs.hyprpicker}/bin/hyprpicker"; + inhibit = config.home-manager.users.${config.custom.username}.home.file.".local/bin/inhibit".source; + jq = "${pkgs.jq}/bin/jq"; + kill = "${pkgs.procps}/bin/kill"; + kitty = "${config.home-manager.users.${config.custom.username}.programs.kitty.package}/bin/kitty"; + left = config.home-manager.users.${config.custom.username}.home.file.".local/bin/left".source; + libreoffice = "${config.custom.programs.libreoffice.package}/bin/libreoffice"; + loginctl = "${pkgs.systemd}/bin/loginctl"; + menu = config.home-manager.users.${config.custom.username}.home.file.".local/bin/menu".source; + nautilus = "${pkgs.nautilus}/bin/nautilus"; + networkmanager_dmenu = "${pkgs.networkmanager_dmenu}/bin/networkmanager_dmenu"; + notify-send = "${pkgs.libnotify}/bin/notify-send"; + niri = "${config.programs.niri.package}/bin/niri"; + obsidian = "${pkgs.obsidian}/bin/obsidian"; + onlyoffice-desktopeditors = "${pkgs.onlyoffice-bin}/bin/onlyoffice-desktopeditors --system-title-bar --xdg-desktop-portal"; + pkill = "${pkgs.procps}/bin/pkill"; + playerctl = "${pkgs.playerctl}/bin/playerctl"; + power = config.home-manager.users.${config.custom.username}.home.file.".local/bin/power".source; + remote = config.home-manager.users.${config.custom.username}.home.file.".local/bin/remote".source; + rofi-rbw = "${pkgs.rofi-rbw}/bin/rofi-rbw"; + rm = "${pkgs.coreutils}/bin/rm"; + sleep = "${pkgs.coreutils}/bin/sleep"; + smile = "${pkgs.smile}/bin/smile"; + steam = "${config.programs.steam.package}/bin/steam"; + swayosd-client = "${pkgs.swayosd}/bin/swayosd-client"; + systemctl = "${pkgs.systemd}/bin/systemctl"; + toggle = "~/.local/bin/toggle"; + virt-manager = "${config.programs.virt-manager.package}/bin/virt-manager"; + vrr = config.home-manager.users.${config.custom.username}.home.file.".local/bin/vrr".source; + walker = "${config.home-manager.users.${config.custom.username}.programs.walker.package}/bin/walker"; + waydroid = "${pkgs.waydroid}/bin/waydroid"; + window = config.home-manager.users.${config.custom.username}.home.file.".local/bin/window".source; + workspace = config.home-manager.users.${config.custom.username}.home.file.".local/bin/workspace".source; + zoom = config.home-manager.users.${config.custom.username}.home.file.".local/bin/zoom".source; + + cfg = config.custom.desktops.niri.binds; +in { + options.custom.desktops.niri.binds = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + home-manager.users.${config.custom.username} = { + # https://github.com/YaLTeR/niri/wiki/Configuration:-Key-Bindings + #?? Mod = Super/Win, Alt when nested; Mod5 = AltGr + #?? wev + programs.niri.settings.binds = let + # Swap modifiers and key for alphabetical sorting + #?? (key "KEY" "MODIFIERS" (ACTION "ARGUMENT")) + key = key: modifiers: action: { + name = "${ + if (isString modifiers) + then "${modifiers}+" + else "" + }${key}"; + value = {inherit action;}; + }; + in + listToAttrs (with config.home-manager.users.${config.custom.username}.lib.niri.actions; [ + (key "0" "Mod" (spawn [swayosd-client "--output-volume" "mute-toggle"])) + (key "A" "Mod" focus-column-or-monitor-left) + (key "A" "Mod+Shift" move-column-left-or-to-monitor-left) + (key "Apostrophe" "Mod" screenshot) + (key "Apostrophe" "Mod+Ctrl+Shift" screenshot-screen) + (key "Apostrophe" "Mod+Shift" screenshot-window) + (key "Backslash" "Mod" (spawn inhibit)) + (key "Bracketleft" "Mod" (switch-layout "prev")) + (key "Bracketright" "Mod" (switch-layout "next")) + (key "Delete" "Ctrl+Alt" quit) + (key "Delete" "Mod" (spawn [playerctl] "play-pause")) + (key "Down" "Mod" (spawn [swayosd-client "--brightness" "lower"])) + (key "Equal" "Mod" (spawn [swayosd-client "--output-volume" "raise"])) + (key "L" "Mod+Shift" suspend) + (key "L" "Mod" (spawn [hyprlock "--immediate" "&" niri "msg" "power-off-monitors"])) + (key "Left" "Mod" (spawn [playerctl "previous"])) + (key "Minus" "Mod" (spawn [swayosd-client "--output-volume" "lower"])) + (key "Q" "Mod" close-window) + (key "R" "Mod" focus-window-or-workspace-down) + (key "R" "Mod+Shift" move-window-down-or-to-workspace-down) + (key "Return" "Mod" maximize-column) + (key "Return" "Mod+Shift" fullscreen-window) + (key "Right" "Mod" (spawn [playerctl "next"])) + (key "S" "Mod" focus-column-or-monitor-right) + (key "S" "Mod+Shift" move-column-right-or-to-monitor-right) + (key "Slash" "Mod+Shift" show-hotkey-overlay) + (key "T" "Mod" (spawn kitty)) + (key "Up" "Mod" (spawn [swayosd-client "--brightness" "raise"])) + (key "W" "Mod" focus-window-or-workspace-up) + (key "W" "Mod+Shift" move-window-up-or-to-workspace-up) + (key "X" "Mod" switch-preset-column-width) + (key "Z" "Mod" switch-preset-window-height) + + # BUG: Release binds execute with all binds involving that modifier + # https://github.com/YaLTeR/niri/issues/605 + #// (key "Super_L" "Mod" spawn menu) + (key "Space" "Mod" (spawn menu)) + + # Media keys + # https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h + (key "XF86AudioMute" null (spawn [swayosd-client "--output-volume" "mute-toggle"])) # F1 + (key "XF86AudioLowerVolume" null (spawn [swayosd-client "--output-volume" "lower"])) # F2 + (key "XF86AudioRaiseVolume" null (spawn [swayosd-client "--output-volume" "raise"])) # F3 + (key "XF86AudioPrev" null (spawn [playerctl "previous"])) # F4 + (key "XF86AudioPlay" null (spawn [playerctl "play-pause"])) # F5 + (key "XF86AudioNext" null (spawn [playerctl "next"])) # F6 + (key "XF86MonBrightnessDown" null (spawn [swayosd-client "--brightness" "lower"])) # F7 + (key "XF86MonBrightnessUp" null (spawn [swayosd-client "--brightness" "raise"])) # F8 + (key "XF86AudioMedia" null (spawn [notify-send "test"])) # F12 + ]); + }; + }; +} diff --git a/options/custom/desktops/niri/default.nix b/options/custom/desktops/niri/default.nix new file mode 100644 index 0000000..a04fb0e --- /dev/null +++ b/options/custom/desktops/niri/default.nix @@ -0,0 +1,46 @@ +{ + config, + inputs, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.custom.desktops.niri; +in { + options.custom.desktops.niri = { + enable = mkOption {default = false;}; + xwayland = mkOption {default = true;}; + }; + + config = mkIf cfg.enable { + custom.desktops.niri = mkIf config.custom.full { + binds.enable = true; + input.enable = true; + layout.enable = true; + misc.enable = true; + rules.enable = true; + }; + + # https://github.com/YaLTeR/niri + # https://github.com/sodiboo/niri-flake + # https://github.com/sodiboo/niri-flake/blob/main/docs.md + programs.niri = { + enable = true; + package = pkgs.niri; # nixpkgs + }; + + nixpkgs.overlays = [inputs.niri.overlays.niri]; + + #!! Disabled bundled KDE polkit agent + # https://github.com/sodiboo/niri-flake?tab=readme-ov-file#additional-notes + systemd.user.services.niri-flake-polkit.enable = false; + + # Enable rootless Xwayland + custom.services.xwayland-satellite.enable = cfg.xwayland; + + home-manager.users.${config.custom.username} = { + programs.niri.package = config.programs.niri.package; + }; + }; +} diff --git a/options/custom/desktops/niri/input.nix b/options/custom/desktops/niri/input.nix new file mode 100644 index 0000000..ab093fd --- /dev/null +++ b/options/custom/desktops/niri/input.nix @@ -0,0 +1,56 @@ +{ + config, + lib, + ... +}: +with lib; let + cfg = config.custom.desktops.niri.input; +in { + options.custom.desktops.niri.input = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + home-manager.users.${config.custom.username} = { + # https://github.com/YaLTeR/niri/wiki/Configuration:-Input + programs.niri.settings.input = { + keyboard = { + repeat-delay = 300; + repeat-rate = 40; + }; + + touchpad = { + accel-profile = "adaptive"; + accel-speed = 0.3; + click-method = "clickfinger"; # Multi-finger click + dwt = true; # Disable while typing + dwtp = true; # Disable while trackpointing + scroll-factor = 0.5; + }; + + mouse = { + # BUG: Applies to trackball device, switch to "flat" when per-device configuration is supported + # https://github.com/YaLTeR/niri/issues/371 + accel-profile = "adaptive"; + + accel-speed = 0.0; + }; + + trackball = { + accel-profile = "adaptive"; + accel-speed = 0.5; + middle-emulation = true; + }; + + power-key-handling.enable = false; + + focus-follows-mouse = { + enable = true; + max-scroll-amount = "70%"; + }; + + workspace-auto-back-and-forth = true; + }; + }; + }; +} diff --git a/options/custom/desktops/niri/layout.nix b/options/custom/desktops/niri/layout.nix new file mode 100644 index 0000000..840fe83 --- /dev/null +++ b/options/custom/desktops/niri/layout.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + ... +}: +with lib; let + cfg = config.custom.desktops.niri.layout; +in { + options.custom.desktops.niri.layout = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + home-manager.users.${config.custom.username} = { + # https://github.com/YaLTeR/niri/wiki/Configuration:-Layout + programs.niri.settings.layout = let + gap = config.custom.gap / 2; + in { + gaps = gap; + #// center-focused-column = "always"; + always-center-single-column = true; + + # TODO: Uncomment after next release > v1.10.1 + # https://github.com/YaLTeR/niri/wiki/Configuration:-Layout#empty-workspace-above-first + #// empty-workspace-above-first = true; + + preset-column-widths = [ + {proportion = 0.5;} + {proportion = 0.3;} + {proportion = 1.0;} + {proportion = 0.7;} # Default + ]; + + default-column-width = {proportion = 0.7;}; + + preset-window-heights = [ + {proportion = 0.7;} + {proportion = 0.5;} + {proportion = 0.3;} + {proportion = 1.0;} # Default + ]; + + border = { + enable = true; + width = config.custom.border; + active.color = "#d33682"; + inactive.color = "#586e75"; + }; + + focus-ring.enable = false; + + insert-hint = { + enable = true; + display.color = "#d3368280"; + }; + + struts = { + left = gap; + right = gap; + top = gap; + bottom = gap; + }; + }; + }; + }; +} diff --git a/options/custom/desktops/niri/misc.nix b/options/custom/desktops/niri/misc.nix new file mode 100644 index 0000000..a57608e --- /dev/null +++ b/options/custom/desktops/niri/misc.nix @@ -0,0 +1,42 @@ +{ + config, + lib, + ... +}: +with lib; let + niri = "${config.programs.niri.package}/bin/niri"; + + cfg = config.custom.desktops.niri.misc; +in { + options.custom.desktops.niri.misc = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + home-manager.users.${config.custom.username} = { + programs.niri.settings = { + # https://github.com/YaLTeR/niri/wiki/Configuration:-Miscellaneous + + # HACK: Inherit home-manager environment variables in lieu of upstream fix + # https://github.com/nix-community/home-manager/issues/2659 + # https://github.com/YaLTeR/niri/wiki/Configuration:-Miscellaneous#environment + environment = mapAttrs (name: value: builtins.toString value) config.home-manager.users.${config.custom.username}.home.sessionVariables; + + cursor = { + hide-after-inactive-ms = 1000 * 15; # Milliseconds + hide-when-typing = true; + }; + + hotkey-overlay.skip-at-startup = true; + prefer-no-csd = true; # Electron windows have odd borders otherwise + + # https://github.com/YaLTeR/niri/wiki/Configuration:-Switch-Events + switch-events = { + # Turn display off while inhibiting suspend + lid-close.action.spawn = [niri "msg" "action" "power-off-monitors"]; + lid-open.action.spawn = [niri "msg" "action" "power-on-monitors"]; + }; + }; + }; + }; +} diff --git a/options/custom/desktops/niri/rules.nix b/options/custom/desktops/niri/rules.nix new file mode 100644 index 0000000..cea22a0 --- /dev/null +++ b/options/custom/desktops/niri/rules.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + ... +}: +with lib; let + cfg = config.custom.desktops.niri.rules; +in { + options.custom.desktops.niri.rules = { + enable = mkOption {default = false;}; + }; + + config = mkIf cfg.enable { + home-manager.users.${config.custom.username} = { + # https://github.com/YaLTeR/niri/wiki/Configuration:-Window-Rules + programs.niri.settings.window-rules = [ + { + geometry-corner-radius = let + radius = config.custom.rounding + 0.0; # Convert to float + in { + top-left = radius; + top-right = radius; + bottom-right = radius; + bottom-left = radius; + }; + + clip-to-geometry = true; + } + ]; + }; + }; +} diff --git a/options/custom/settings/environment.nix b/options/custom/settings/environment.nix index 8f17a45..c3c529e 100644 --- a/options/custom/settings/environment.nix +++ b/options/custom/settings/environment.nix @@ -25,7 +25,7 @@ in { #// i18n.defaultLocale = "C.UTF-8"; sessionVariables = { - GDK_SCALE = toString config.custom.scale; # Steam HiDPI + GDK_SCALE = mkIf (!config.custom.services.xwayland-satellite.enable) (toString config.custom.scale); # Steam HiDPI # https://wiki.nixos.org/wiki/Wayland#Electron_and_Chromium NIXOS_OZONE_WL = mkIf cfg.wayland "1";