diff --git a/modules/modules.nix b/modules/modules.nix index eebcbdbe..fa4fb734 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -350,6 +350,7 @@ let ./services/hypridle.nix ./services/hyprpaper.nix ./services/hyprpolkitagent.nix + ./services/hyprsunset.nix ./services/imapnotify.nix ./services/jankyborders.nix ./services/kanshi.nix diff --git a/modules/services/hyprsunset.nix b/modules/services/hyprsunset.nix new file mode 100644 index 00000000..b4ff7ea0 --- /dev/null +++ b/modules/services/hyprsunset.nix @@ -0,0 +1,133 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.hyprsunset; +in +{ + meta.maintainers = with lib.maintainers; [ + khaneliman + ]; + + options.services.hyprsunset = { + enable = lib.mkEnableOption "Hyprsunset, Hyprland's blue-light filter"; + + package = lib.mkPackageOption pkgs "hyprsunset" { }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Additional command-line arguments to pass to `hyprsunset`."; + example = [ + "--identity" + ]; + }; + + transitions = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + calendar = lib.mkOption { + type = lib.types.str; + description = "Systemd calendar expression for when to run this transition."; + example = "*-*-* 06:00:00"; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Additional command-line arguments to pass to `hyprctl hyprsunset` for this transition."; + example = [ + "temperature 3500" + ]; + }; + }; + } + ); + default = { }; + description = "Set of transitions for different times of day (e.g., sunrise, sunset)"; + example = lib.literalExpression '' + { + sunrise = { + calendar = "*-*-* 06:00:00"; + extraArgs = [ "temperature" "6500" ]; + }; + sunset = { + calendar = "*-*-* 19:00:00"; + extraArgs = [ "temperature" "3500" ]; + }; + } + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.user = + let + # Create the main persistent service that maintains the IPC socket + # Create a service for each transition in the transitions configuration + # These services will send commands to the persistent service via IPC + transitionServices = lib.mapAttrs' ( + name: transitionCfg: + lib.nameValuePair "hyprsunset-${name}" { + Install = { }; + + Unit = { + ConditionEnvironment = "WAYLAND_DISPLAY"; + Description = "hyprsunset transition for ${name}"; + After = [ "hyprsunset.service" ]; + Requires = [ "hyprsunset.service" ]; + }; + + Service = { + ExecStart = "${lib.getExe' config.wayland.windowManager.hyprland.package "hyprctl"} hyprsunset ${lib.escapeShellArgs transitionCfg.extraArgs}"; + Type = "oneshot"; + }; + } + ) cfg.transitions; + in + { + services = { + hyprsunset = { + Install = { + WantedBy = [ config.wayland.systemd.target ]; + }; + + Unit = { + ConditionEnvironment = "WAYLAND_DISPLAY"; + Description = "hyprsunset - Hyprland's blue-light filter"; + After = [ config.wayland.systemd.target ]; + PartOf = [ config.wayland.systemd.target ]; + }; + + Service = { + ExecStart = "${lib.getExe cfg.package} ${lib.escapeShellArgs cfg.extraArgs}"; + Restart = "always"; + RestartSec = "10"; + }; + }; + } // transitionServices; + + timers = lib.mapAttrs' ( + name: transitionCfg: + lib.nameValuePair "hyprsunset-${name}" { + Install = { + WantedBy = [ config.wayland.systemd.target ]; + }; + + Unit = { + Description = "Timer for hyprsunset transition (${name})"; + }; + + Timer = { + OnCalendar = transitionCfg.calendar; + Persistent = true; + }; + } + ) cfg.transitions; + }; + }; +} diff --git a/tests/default.nix b/tests/default.nix index ef73d894..07f5a134 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -579,6 +579,7 @@ import nmtSrc { ./modules/services/hypridle ./modules/services/hyprpaper ./modules/services/hyprpolkitagent + ./modules/services/hyprsunset ./modules/services/imapnotify ./modules/services/kanshi ./modules/services/lieer diff --git a/tests/modules/services/hyprsunset/basic-configuration.nix b/tests/modules/services/hyprsunset/basic-configuration.nix new file mode 100644 index 00000000..a0ce02ab --- /dev/null +++ b/tests/modules/services/hyprsunset/basic-configuration.nix @@ -0,0 +1,44 @@ +{ + services.hyprsunset = { + enable = true; + extraArgs = [ "--identity" ]; + + transitions = { + sunrise = { + calendar = "*-*-* 06:30:00"; + extraArgs = [ "temperature 6500" ]; + }; + + sunset = { + calendar = "*-*-* 19:30:00"; + extraArgs = [ "temperature 3500" ]; + }; + }; + }; + + nmt.script = '' + # Check that the main service exists + mainService=home-files/.config/systemd/user/hyprsunset.service + assertFileExists $mainService + + # Check that the transition services exist + sunriseService=home-files/.config/systemd/user/hyprsunset-sunrise.service + sunsetService=home-files/.config/systemd/user/hyprsunset-sunset.service + assertFileExists $sunriseService + assertFileExists $sunsetService + + # Check that the timers exist + sunriseTimer=home-files/.config/systemd/user/hyprsunset-sunrise.timer + sunsetTimer=home-files/.config/systemd/user/hyprsunset-sunset.timer + assertFileExists $sunriseTimer + assertFileExists $sunsetTimer + + # Verify timer configurations + assertFileContains $sunriseTimer "OnCalendar=*-*-* 06:30:00" + assertFileContains $sunsetTimer "OnCalendar=*-*-* 19:30:00" + + # Verify service configurations + assertFileContains $sunriseService "ExecStart=@hyprland@/bin/hyprctl hyprsunset 'temperature 6500'" + assertFileContains $sunsetService "ExecStart=@hyprland@/bin/hyprctl hyprsunset 'temperature 3500'" + ''; +} diff --git a/tests/modules/services/hyprsunset/default.nix b/tests/modules/services/hyprsunset/default.nix new file mode 100644 index 00000000..50d3c2a6 --- /dev/null +++ b/tests/modules/services/hyprsunset/default.nix @@ -0,0 +1,3 @@ +{ + hyprsunset-basic-configuration = ./basic-configuration.nix; +}