diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index a52409ba95ea..daa3030cd6e7 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -7,6 +7,7 @@ # [1] https://github.com/NixOS/nixpkgs/blob/737449404589e4a80b3fa99ecbc6d4d803c1f6dc/maintainers/maintainer-list.nix#LC1 { # keep-sorted start case=no numeric=no block=yes + _3ulalia = { name = "Eulalia del Sol"; email = "3ulalia@proton.me"; diff --git a/modules/misc/news/2026/07/2026-07-19_12-04-45.nix b/modules/misc/news/2026/07/2026-07-19_12-04-45.nix new file mode 100644 index 000000000000..9749629b764e --- /dev/null +++ b/modules/misc/news/2026/07/2026-07-19_12-04-45.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: +{ + time = "2026-07-19T09:04:45+00:00"; + condition = pkgs.stdenv.hostPlatform.isLinux; + message = '' + A new module is available: 'programs.dank-material-shell'. + DankMaterialShell is a complete desktop shell for niri, Hyprland, MangoWC, + Sway, labwc, Scroll, Miracle WM, and other Wayland compositors. It replaces + waybar, swaylock, swayidle, mako, fuzzel, polkit, and everything else you'd + normally stitch together to make a desktop. + ''; +} diff --git a/modules/programs/dank-material-shell.nix b/modules/programs/dank-material-shell.nix new file mode 100644 index 000000000000..622ab6169edd --- /dev/null +++ b/modules/programs/dank-material-shell.nix @@ -0,0 +1,281 @@ +{ + lib, + pkgs, + config, + ... +}: +let + inherit (lib) + types + mkIf + mkEnableOption + mkPackageOption + mkOption + mkRenamedOptionModule + mkRemovedOptionModule + ; + + cfg = config.programs.dank-material-shell; + + jsonFormat = pkgs.formats.json { }; + + hasPluginSettings = lib.any (plugin: plugin.settings != { }) ( + lib.attrValues (lib.filterAttrs (_n: v: v.enable) cfg.plugins) + ); + pluginSettings = lib.mapAttrs (_name: plugin: { enabled = plugin.enable; } // plugin.settings) ( + lib.filterAttrs (_n: v: v.enable) cfg.plugins + ); + + common = { + packages = [ + cfg.package + ] + ++ lib.optional cfg.enableSystemMonitoring cfg.dgop.package + ++ lib.optionals cfg.enableVPN [ + pkgs.glib + pkgs.networkmanager + ] + ++ lib.optional cfg.enableDynamicTheming pkgs.matugen + ++ lib.optional cfg.enableAudioWavelength pkgs.cava + ++ lib.optional cfg.enableCalendarEvents pkgs.khal; + + plugins = lib.mapAttrs (_name: plugin: { + source = plugin.src; + }) (lib.filterAttrs (_n: v: v.enable) cfg.plugins); + }; + + path = [ + "programs" + "dank-material-shell" + ]; + + builtInRemovedMsg = "This is now built-in in DMS and doesn't need additional dependencies."; + +in +{ + meta.maintainers = [ lib.maintainers.artur-sannikov ]; + + imports = [ + (mkRenamedOptionModule + [ + "programs" + "dankMaterialShell" + ] + [ + "programs" + "dank-material-shell" + ] + ) + + (mkRemovedOptionModule (path ++ [ "enableBrightnessControl" ]) builtInRemovedMsg) + (mkRemovedOptionModule (path ++ [ "enableColorPicker" ]) builtInRemovedMsg) + (mkRemovedOptionModule (path ++ [ "enableClipboard" ]) builtInRemovedMsg) + (mkRemovedOptionModule (path ++ [ "enableNightMode" ]) "Night mode is now always available") + (mkRemovedOptionModule ( + path ++ [ "enableSystemSound" ] + ) "qtmultimedia is now included on dms-shell package.") + (mkRemovedOptionModule ( + path + ++ [ + "default" + "settings" + ] + ) "Default settings have been removed and been replaced with programs.dank-material-shell.settings") + (mkRemovedOptionModule ( + path + ++ [ + "default" + "session" + ] + ) "Default session has been removed and been replaced with programs.dank-material-shell.session") + (mkRenamedOptionModule + [ "programs" "dank-material-shell" "enableSystemd" ] + [ "programs" "dank-material-shell" "systemd" "enable" ] + ) + ]; + + options.programs.dank-material-shell = { + + enable = mkEnableOption "DankMaterialShell"; + + package = mkPackageOption pkgs "dms-shell" { nullable = true; }; + + settings = mkOption { + inherit (jsonFormat) type; + default = { }; + description = '' + DankMaterialShell configuration settings as an attribute set, to be written to ~/.config/DankMaterialShell/settings.json. + Full up-to-date list of available settings can be found at https://raw.githubusercontent.com/AvengeMedia/DankMaterialShell/refs/heads/master/quickshell/Common/settings/SettingsSpec.js. + ''; + }; + + dgop = { + package = mkPackageOption pkgs "dgop" { }; + }; + + enableSystemMonitoring = mkOption { + type = types.bool; + default = true; + description = "Add needed dependencies to use system monitoring widgets"; + }; + + enableVPN = mkOption { + type = types.bool; + default = true; + description = "Add needed dependencies to use the VPN widget"; + }; + + enableDynamicTheming = mkOption { + type = types.bool; + default = true; + description = "Add needed dependencies to have dynamic theming support"; + }; + + enableAudioWavelength = mkOption { + type = types.bool; + default = true; + description = "Add needed dependencies to have audio wavelength support"; + }; + + enableCalendarEvents = mkOption { + type = types.bool; + default = true; + description = "Add calendar events support via khal"; + }; + + enableClipboardPaste = mkOption { + type = types.bool; + default = true; + description = "Deprecated: paste is built into dms; no extra dependencies needed. Kept as a no-op for compatibility."; + }; + + quickshell = { + package = mkPackageOption pkgs "quickshell" { + extraDescription = "(we recommend at least 0.3.0, currently available in nixos-unstable)"; + }; + }; + + plugins = lib.mkOption { + type = types.attrsOf ( + types.submodule { + options = { + enable = lib.mkOption { + type = types.bool; + default = true; + description = "Whether to enable this plugin"; + }; + src = lib.mkOption { + type = types.either types.package types.path; + description = "Source of the plugin package or path"; + }; + settings = lib.mkOption { + inherit (jsonFormat) type; + default = { }; + description = "Plugin settings as an attribute set"; + }; + }; + } + ); + default = { }; + description = "DMS Plugins to install and enable"; + example = lib.literalExpression '' + { + DockerManager = { + src = pkgs.fetchFromGitHub { + owner = "LuckShiba"; + repo = "DmsDockerManager"; + rev = "v1.2.0"; + sha256 = "sha256-VoJCaygWnKpv0s0pqTOmzZnPM922qPDMHk4EPcgVnaU="; + }; + }; + AnotherPlugin = { + enable = true; + src = pkgs.another-plugin; + }; + } + ''; + }; + + clipboardSettings = mkOption { + inherit (jsonFormat) type; + default = { }; + description = "DankMaterialShell clipboard settings as an attribute set, to be written to ~/.config/DankMaterialShell/clsettings.json."; + }; + + session = mkOption { + inherit (jsonFormat) type; + default = { }; + description = '' + DankMaterialShell session settings as an attribute set, to be written to ~/.local/state/DankMaterialShell/session.json. + Full up-to-date list of available settings can be found at https://raw.githubusercontent.com/AvengeMedia/DankMaterialShell/refs/heads/master/quickshell/Common/settings/SessionSpec.js + + ''; + }; + + managePluginSettings = mkOption { + type = lib.types.bool; + default = hasPluginSettings; + defaultText = lib.literalExpression '' + true if any enabled plugin has non-empty `settings`, otherwise false + ''; + description = "Whether to manage plugin settings. Automatically enabled if any plugins have settings configured."; + }; + + systemd = { + enable = lib.mkEnableOption "DankMaterialShell systemd startup"; + }; + + systemd.target = mkOption { + type = lib.types.str; + default = config.wayland.systemd.target; + defaultText = lib.literalExpression "config.wayland.systemd.target"; + description = "Systemd target to bind to."; + }; + }; + + config = mkIf cfg.enable { + programs.quickshell = { + enable = true; + inherit (cfg.quickshell) package; + }; + + systemd.user.services.dms = mkIf cfg.systemd.enable { + Unit = { + Description = "DankMaterialShell"; + PartOf = [ cfg.systemd.target ]; + After = [ cfg.systemd.target ]; + }; + + Service = { + ExecStart = lib.getExe cfg.package + " run --session"; + Restart = "on-failure"; + }; + + Install.WantedBy = [ cfg.systemd.target ]; + }; + + xdg.stateFile."DankMaterialShell/session.json" = mkIf (cfg.session != { }) { + source = jsonFormat.generate "session.json" cfg.session; + }; + + xdg.configFile = { + "DankMaterialShell/settings.json" = mkIf (cfg.settings != { }) { + source = jsonFormat.generate "settings.json" cfg.settings; + }; + "DankMaterialShell/clsettings.json" = mkIf (cfg.clipboardSettings != { }) { + source = jsonFormat.generate "clsettings.json" cfg.clipboardSettings; + }; + "DankMaterialShell/plugin_settings.json" = mkIf cfg.managePluginSettings { + source = jsonFormat.generate "plugin_settings.json" pluginSettings; + }; + } + // (lib.mapAttrs' (name: value: { + name = "DankMaterialShell/plugins/${name}"; + inherit value; + }) common.plugins); + warnings = + lib.optional (!cfg.managePluginSettings && hasPluginSettings) + "You have disabled managePluginSettings but provided plugin settings. These settings will be ignored."; + home.packages = common.packages; + }; +} diff --git a/tests/modules/services/dank-material-shell/clsettings.json b/tests/modules/services/dank-material-shell/clsettings.json new file mode 100644 index 000000000000..db89e59a4ff5 --- /dev/null +++ b/tests/modules/services/dank-material-shell/clsettings.json @@ -0,0 +1,9 @@ +{ + "autoClearDays": 1, + "clearAtStartup": true, + "disableHistory": false, + "disablePersist": true, + "disabled": false, + "maxEntrySize": 5242880, + "maxHistory": 25 +} diff --git a/tests/modules/services/dank-material-shell/default.nix b/tests/modules/services/dank-material-shell/default.nix new file mode 100644 index 000000000000..1113a153b048 --- /dev/null +++ b/tests/modules/services/dank-material-shell/default.nix @@ -0,0 +1,5 @@ +{ lib, pkgs, ... }: + +lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { + dank-material-shell-example = ./example-config.nix; +} diff --git a/tests/modules/services/dank-material-shell/example-config.nix b/tests/modules/services/dank-material-shell/example-config.nix new file mode 100644 index 000000000000..e61eaaf6d522 --- /dev/null +++ b/tests/modules/services/dank-material-shell/example-config.nix @@ -0,0 +1,38 @@ +{ + programs.dank-material-shell = { + enable = true; + + settings = { + theme = "dark"; + dynamicTheming = true; + }; + + session = { + isLightMode = false; + }; + + clipboardSettings = { + maxHistory = 25; + maxEntrySize = 5242880; + autoClearDays = 1; + clearAtStartup = true; + disabled = false; + disableHistory = false; + disablePersist = true; + }; + }; + + nmt.script = '' + assertFileExists home-files/.config/DankMaterialShell/settings.json + assertFileContent home-files/.config/DankMaterialShell/settings.json \ + ${./settings.json} + + assertFileExists home-files/.local/state/DankMaterialShell/session.json + assertFileContent home-files/.local/state/DankMaterialShell/session.json \ + ${./session.json} + + assertFileExists home-files/.config/DankMaterialShell/clsettings.json + assertFileContent home-files/.config/DankMaterialShell/clsettings.json \ + ${./clsettings.json} + ''; +} diff --git a/tests/modules/services/dank-material-shell/session.json b/tests/modules/services/dank-material-shell/session.json new file mode 100644 index 000000000000..1375b4e06979 --- /dev/null +++ b/tests/modules/services/dank-material-shell/session.json @@ -0,0 +1,3 @@ +{ + "isLightMode": false +} diff --git a/tests/modules/services/dank-material-shell/settings.json b/tests/modules/services/dank-material-shell/settings.json new file mode 100644 index 000000000000..d50c557e33e9 --- /dev/null +++ b/tests/modules/services/dank-material-shell/settings.json @@ -0,0 +1,4 @@ +{ + "dynamicTheming": true, + "theme": "dark" +}