{ self, inputs, ... }: { imports = [ ./window-rules.nix ./base-settings.nix ./binds.nix ]; flake.homeManagerModules.desktopNiri = { config, lib, pkgs, osConfig ? { }, ... }: let home = config.home.homeDirectory; niriOs = osConfig.chiasson.desktop.niri or { }; niriEnabled = osConfig.chiasson.desktop.niri.enable or false; keyringEnabled = osConfig.chiasson.desktop.keyring.enable or false; dmsEnabled = (osConfig.chiasson.desktop.shell or null) == "dms"; keyringNiriStartupKdl = '' spawn-at-startup "dbus-update-activation-environment" "--systemd" "--all" ''; niriBaseSettings = pkgs: dmsEnabled: self.lib.niriBaseSettings pkgs // { binds = self.lib.niriBinds { inherit pkgs dmsEnabled; dmsIpcBinds = self.lib.dmsIpcBinds; }; }; mergeNiriSettings = pkgs: niriCfg: keyringEnable: dmsEnabled: let lib = pkgs.lib; pi5 = self.lib.pi5NiriKdl; rpi5Extra = lib.optionalString (niriCfg.raspberryPi5DrmWorkaround or false) pi5.drmExtraConfig; base = niriBaseSettings pkgs dmsEnabled; userExtra = niriCfg.extraSettings or { }; keyringExtra = lib.optionalString keyringEnable keyringNiriStartupKdl; extraConfigMerged = keyringExtra + rpi5Extra + (userExtra.extraConfig or ""); windowRules = (base.window-rules or [ ]) ++ (userExtra.window-rules or [ ]); userExtraNoSpecial = lib.removeAttrs userExtra [ "window-rules" "extraConfig" "binds" ]; mergedBinds = (base.binds or { }) // (userExtra.binds or { }) // (niriCfg.extraBinds or { }); in lib.recursiveUpdate base ( userExtraNoSpecial // { binds = mergedBinds; } // lib.optionalAttrs (windowRules != [ ]) { window-rules = windowRules; } // lib.optionalAttrs (extraConfigMerged != "") { extraConfig = extraConfigMerged; } ); dmsWindowRulesPath = "${home}/.config/niri/dms/windowrules.kdl"; dmsWindowRulesInclude = lib.optionalString dmsEnabled '' include "${dmsWindowRulesPath}" ''; baseMergedSettings = mergeNiriSettings pkgs niriOs keyringEnabled dmsEnabled; mergedSettings = lib.recursiveUpdate baseMergedSettings { extraConfig = dmsWindowRulesInclude + (baseMergedSettings.extraConfig or ""); }; niriConfigPkg = inputs.wrapper-modules.wrappers.niri.wrap { inherit pkgs; settings = mergedSettings; disableConfigValidation = dmsEnabled; }; in { config = lib.mkIf niriEnabled (lib.mkMerge [ { xdg.configFile."niri/config.kdl".source = "${niriConfigPkg}/niri-config.kdl"; } (lib.mkIf dmsEnabled { home.activation.dmsNiriWindowRulesSeed = lib.hm.dag.entryAfter [ "writeBoundary" ] '' rulesDir="$HOME/.config/niri/dms" rulesFile="$rulesDir/windowrules.kdl" mkdir -p "$rulesDir" if [ ! -e "$rulesFile" ]; then ${pkgs.coreutils}/bin/touch "$rulesFile" fi ''; }) ]); }; flake.nixosModules.desktopNiri = { config, options, lib, pkgs, self, ... }: let cfg = config.chiasson.desktop; hmAvailable = lib.hasAttrByPath [ "home-manager" "sharedModules" ] options; in { options.chiasson.desktop.niri = { enable = lib.mkOption { type = lib.types.bool; default = false; description = "Niri compositor session + NixOS packages."; }; raspberryPi5DrmWorkaround = lib.mkEnableOption '' Pi 5 + RP1 DSI: Niri DRM debug rules (renderD128, ignore card1/2) + matching DankGreeter niri config. Opt-in only — HDMI-only / other Pi setups do not need this. ''; extraSettings = lib.mkOption { type = lib.types.attrs; default = { }; description = '' Merged into shared defaults → `config.kdl` via wrapper-modules. Put raw KDL in `extraConfig`. ''; }; extraBinds = lib.mkOption { type = lib.types.attrsOf lib.types.anything; default = { }; description = '' Keybind overrides merged with shared defaults and `extraSettings.binds`. Use this when multiple modules need to add binds without overwriting each other. ''; }; }; config = lib.mkMerge [ { assertions = [ { assertion = !cfg.niri.raspberryPi5DrmWorkaround || cfg.niri.enable; message = "chiasson.desktop.niri.raspberryPi5DrmWorkaround requires chiasson.desktop.niri.enable."; } ]; } (lib.mkIf cfg.niri.enable { programs.niri.enable = true; programs.niri.package = pkgs.niri; programs.xwayland.enable = true; xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gnome ]; environment.systemPackages = [ pkgs.xwayland-satellite ]; }) (lib.mkIf (cfg.niri.enable && hmAvailable) { "home-manager".sharedModules = [ self.homeManagerModules.desktopNiri ]; }) ]; }; }