diff --git a/modules/misc/news.nix b/modules/misc/news.nix index d402df93..524bded3 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1273,6 +1273,14 @@ in A new module is available: 'programs.thefuck'. ''; } + + { + time = "2023-10-17T06:33:24+00:00"; + condition = hostPlatform.isLinux; + message = '' + A new module is available: 'services.darkman'. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index f4a622c1..c9822486 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -254,6 +254,7 @@ let ./services/clipmenu.nix ./services/comodoro.nix ./services/copyq.nix + ./services/darkman.nix ./services/devilspie2.nix ./services/dropbox.nix ./services/dunst.nix diff --git a/modules/services/darkman.nix b/modules/services/darkman.nix new file mode 100644 index 00000000..d11f0324 --- /dev/null +++ b/modules/services/darkman.nix @@ -0,0 +1,115 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.darkman; + + yamlFormat = pkgs.formats.yaml { }; + + scriptsOptionType = kind: + mkOption { + type = types.attrsOf (types.oneOf [ types.path types.lines ]); + default = { }; + example = literalExpression '' + { + gtk-theme = ''' + ''${pkgs.dconf}/bin/dconf write \ + /org/gnome/desktop/interface/color-scheme "'prefer-${kind}'" + '''; + my-python-script = pkgs.writers.writePython3 "my-python-script" { } ''' + print('Do something!') + '''; + } + ''; + description = '' + Scripts to run when switching to "${kind} mode". + + Multiline strings are interpreted as Bash shell scripts and a shebang is + not required. + ''; + }; + + generateScripts = folder: + mapAttrs' (k: v: { + name = "${folder}/${k}"; + value = { + source = if builtins.isPath v || isDerivation v then + v + else + pkgs.writeShellScript (hm.strings.storeFileName k) v; + }; + }); +in { + meta.maintainers = [ maintainers.xlambein ]; + + options.services.darkman = { + enable = mkEnableOption '' + darkman, a tool that automatically switches dark-mode on and off based on + the time of the day''; + + package = mkPackageOption pkgs "darkman" { }; + + settings = mkOption { + type = types.submodule { freeformType = yamlFormat.type; }; + example = literalExpression '' + { + lat = 52.3; + lng = 4.8; + usegeoclue = true; + } + ''; + description = '' + Settings for the {command}`darkman` command. See + for details. + ''; + }; + + darkModeScripts = scriptsOptionType "dark"; + + lightModeScripts = scriptsOptionType "light"; + }; + + config = mkIf cfg.enable { + assertions = [ + (hm.assertions.assertPlatform "services.darkman" pkgs platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile = { + "darkman/config.yaml" = mkIf (cfg.settings != { }) { + source = yamlFormat.generate "darkman-config.yaml" cfg.settings; + }; + }; + + xdg.dataFile = mkMerge [ + (mkIf (cfg.darkModeScripts != { }) + (generateScripts "dark-mode.d" cfg.darkModeScripts)) + (mkIf (cfg.lightModeScripts != { }) + (generateScripts "light-mode.d" cfg.lightModeScripts)) + ]; + + systemd.user.services.darkman = { + Unit = { + Description = "Darkman system service"; + Documentation = "man:darkman(1)"; + PartOf = [ "graphical-session.target" ]; + BindsTo = [ "graphical-session.target" ]; + X-Restart-Triggers = + [ "${config.xdg.configFile."darkman/config.yaml".source}" ]; + }; + + Service = { + Type = "dbus"; + BusName = "nl.whynothugo.darkman"; + ExecStart = "${getExe cfg.package} run"; + Restart = "on-failure"; + TimeoutStopSec = 15; + Slice = "background.slice"; + }; + + Install.WantedBy = mkDefault [ "graphical-session.target" ]; + }; + }; +} diff --git a/tests/default.nix b/tests/default.nix index b02d4c79..50c40478 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -208,6 +208,7 @@ import nmt { ./modules/services/cliphist ./modules/services/clipman ./modules/services/comodoro + ./modules/services/darkman ./modules/services/devilspie2 ./modules/services/dropbox ./modules/services/emacs diff --git a/tests/modules/services/darkman/basic-configuration.nix b/tests/modules/services/darkman/basic-configuration.nix new file mode 100644 index 00000000..4c3e8547 --- /dev/null +++ b/tests/modules/services/darkman/basic-configuration.nix @@ -0,0 +1,70 @@ +{ config, pkgs, ... }: + +{ + services.darkman = { + enable = true; + package = config.lib.test.mkStubPackage { + name = "darkman"; + outPath = "@darkman@"; + }; + + settings.lat = 50.8; + settings.lng = 4.4; + settings.usegeoclue = true; + + darkModeScripts.color-scheme-dark = '' + dconf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'" + ''; + + lightModeScripts.color-scheme-light = pkgs.writeScript "my-python-script" '' + #!${pkgs.python}/bin/python + + print('Do something!') + ''; + }; + + test.stubs.python = { }; + + nmt.script = '' + serviceFile=$(normalizeStorePaths home-files/.config/systemd/user/darkman.service) + darkModeScriptFile=$(normalizeStorePaths home-files/.local/share/dark-mode.d/color-scheme-dark) + lightModeScriptFile=$(normalizeStorePaths home-files/.local/share/light-mode.d/color-scheme-light) + + assertFileExists $serviceFile + assertFileContent $serviceFile ${ + builtins.toFile "expected" '' + [Install] + WantedBy=graphical-session.target + + [Service] + BusName=nl.whynothugo.darkman + ExecStart=@darkman@/bin/darkman run + Restart=on-failure + Slice=background.slice + TimeoutStopSec=15 + Type=dbus + + [Unit] + BindsTo=graphical-session.target + Description=Darkman system service + Documentation=man:darkman(1) + PartOf=graphical-session.target + X-Restart-Triggers=/nix/store/00000000000000000000000000000000-darkman-config.yaml + '' + } + assertFileContent $darkModeScriptFile ${ + builtins.toFile "expected" '' + #!/nix/store/00000000000000000000000000000000-bash/bin/bash + dconf write /org/gnome/desktop/interface/color-scheme "'prefer-dark'" + + '' + } + assertFileContent $lightModeScriptFile ${ + builtins.toFile "expected" '' + #!@python@/bin/python + + print('Do something!') + '' + } + ''; +} diff --git a/tests/modules/services/darkman/default.nix b/tests/modules/services/darkman/default.nix new file mode 100644 index 00000000..6c03491b --- /dev/null +++ b/tests/modules/services/darkman/default.nix @@ -0,0 +1 @@ +{ darkman-basic-configuration = ./basic-configuration.nix; }