diff --git a/modules/services/hyprsunset.nix b/modules/services/hyprsunset.nix index 811d3117d..7c2c62891 100644 --- a/modules/services/hyprsunset.nix +++ b/modules/services/hyprsunset.nix @@ -22,7 +22,7 @@ in default = [ ]; description = "Additional command-line arguments to pass to `hyprsunset`."; example = [ - "--identity" + "--verbose" ]; }; @@ -69,89 +69,166 @@ in } ''; }; + + settings = lib.mkOption { + type = + with lib.types; + let + valueType = + nullOr (oneOf [ + bool + int + float + str + path + (attrsOf valueType) + (listOf valueType) + ]) + // { + description = "Hyprsunset configuration value"; + }; + in + valueType; + default = { }; + description = '' + Hyprsunset configuration written in Nix. Entries with the same key + should be written as lists. Variables' and colors' names should be + quoted. See for more examples. + ''; + example = lib.literalExpression '' + { + max-gamma = 150; + + profile = [ + { + time = "7:30"; + identity = true; + } + { + time = "21:00"; + temperature = 5000; + gamma = 0.8; + } + ]; + }; + ''; + }; + + importantPrefixes = lib.mkOption { + type = with lib.types; listOf str; + default = [ "$" ]; + example = [ "$" ]; + description = '' + List of prefix of attributes to source at the top of the config. + ''; + }; + + systemdTarget = lib.mkOption { + type = lib.types.str; + default = config.wayland.systemd.target; + defaultText = lib.literalExpression "config.wayland.systemd.target"; + example = "hyprland-session.target"; + description = "Systemd target to bind to."; + }; }; config = lib.mkIf cfg.enable { assertions = [ { - assertion = (config.wayland.windowManager.hyprland.package != null); + assertion = (config.wayland.windowManager.hyprland.package != null || cfg.transitions == { }); message = '' - Can't set services.hyprsunset.enable if wayland.windowManager.hyprland.package - is set to null. If you are using Hyprland's upstream flake, see: + Can't set services.hyprsunset.enable when using the deprecated option + services.hyprsunset.transitions if wayland.windowManager.hyprland.package + is set to null. Either migrate your configuration to use services.hyprsunset.settings + or, if you are using Hyprland's upstream flake, see: . ''; } ]; - systemd.user = lib.mkIf (config.wayland.windowManager.hyprland.package != null) ( - 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 requests 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" ]; - }; + xdg.configFile."hypr/hyprsunset.conf" = lib.mkIf (cfg.settings != { }) { + text = lib.hm.generators.toHyprconf { + attrs = cfg.settings; + inherit (cfg) importantPrefixes; + }; + }; - Service = { - Type = "oneshot"; - # Execute multiple requests sequentially - ExecStart = lib.concatMapStringsSep " && " ( - cmd: - "${lib.getExe' config.wayland.windowManager.hyprland.package "hyprctl"} hyprsunset ${lib.escapeShellArgs cmd}" - ) transitionCfg.requests; - }; + systemd.user = + lib.mkIf (config.wayland.windowManager.hyprland.package != null || cfg.transitions == { }) + ( + let + # Handle deprecated transitions option + # If this is unused, no additional services will be created as transitions will be empty + # Create a service for each transition in the transitions configuration + # These services will send requests 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 = { + Type = "oneshot"; + # Execute multiple requests sequentially + ExecStart = lib.concatMapStringsSep " && " ( + cmd: + "${lib.getExe' config.wayland.windowManager.hyprland.package "hyprctl"} hyprsunset ${lib.escapeShellArgs cmd}" + ) transitionCfg.requests; + }; + } + ) cfg.transitions; + in + { + services = { + hyprsunset = { + Install = { + WantedBy = [ cfg.systemdTarget ]; + }; + + Unit = { + ConditionEnvironment = "WAYLAND_DISPLAY"; + Description = "hyprsunset - Hyprland's blue-light filter"; + After = [ config.wayland.systemd.target ]; + PartOf = [ config.wayland.systemd.target ]; + X-Restart-Triggers = lib.mkIf (cfg.settings != { }) [ + "${config.xdg.configFile."hypr/hyprsunset.conf".source}" + ]; + }; + + 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; } - ) 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; - } - ); + ); }; }