sunsetr icon indicating copy to clipboard operation
sunsetr copied to clipboard

[BUG]: after sleep/suspend, gamma and color temperature is reset

Open MrStickyPiston opened this issue 2 months ago • 10 comments

Im using NixOS stable with the flake. My nix config is the following:

{
  inputs,
  pkgs,
  config,
  ...
}:
let
  package = inputs.sunsetr.packages.${pkgs.system}.sunsetr;
in
{
  # Allow manually changing gamma/temperature
  home.packages = [
    package
  ];

  xdg.configFile."sunsetr/sunsetr.toml".source = ./config.toml;

  systemd.user.services.sunsetr = {
    Install = {
      WantedBy = [ "graphical-session.target" ];
    };

    Unit = {
      ConditionEnvironment = "WAYLAND_DISPLAY";
      After = [ "graphical-session.target" ];
      PartOf = [ "graphical-session.target" ];
      Requires = [ "graphical-session.target" ];
    };

    Service = {
      ExecStart = "${package}/bin/sunsetr";
      Restart = "on-failure";
      RestartSec = "10";
      Slice = "background.slice";
    };
  };
}

My config.toml/sunsetr.toml looks like this:

#[Backend]
backend = "auto"                # Backend to use: "auto", "hyprland", "hyprsunset" or "wayland"
transition_mode = "finish_by"   # Select: "geo", "finish_by", "start_at", "center", "static"

#[Smoothing]
smoothing = true                # Enable smooth transitions during startup and exit
startup_duration = 0.5          # Duration of smooth startup in seconds (0.1-60 | 0 = instant)
shutdown_duration = 0.5         # Duration of smooth shutdown in seconds (0.1-60 | 0 = instant)
adaptive_interval = 1           # Adaptive interval base for smooth transitions (1-1000)ms

#[Time-based config]
night_temp = 1900               # Color temperature during night (1000-20000) Kelvin
day_temp = 6500                 # Color temperature during day (1000-20000) Kelvin
night_gamma = 90                # Gamma percentage for night (10-200%)
day_gamma = 100                 # Gamma percentage for day (10-200%)
update_interval = 60            # Update frequency during transitions in seconds (10-300)

#[Static config]
static_temp = 6500              # Color temperature for static mode (1000-20000) Kelvin
static_gamma = 100              # Gamma percentage for static mode (10-200%)

#[Manual transitions]
sunset = "18:00:00"             # Time for manual sunset calculations (HH:MM:SS)
sunrise = "06:00:00"            # Time for manual sunrise calculations (HH:MM:SS)
transition_duration = 45        # Transition duration in minutes (5-120)

There is an ampty geo.toml file in the config dir, else it would not start without geo section.

This are the logs of the systemd service:

[sticky@NixUSB:~/nixos-config]$ systemctl status --user sunsetr.service
● sunsetr.service
     Loaded: loaded (/home/sticky/.config/systemd/user/sunsetr.service; enabled; preset: ignored)
     Active: active (running) since Tue 2025-11-11 18:18:34 CET; 1min 15s ago
 Invocation: 791d7681792748e389a537b0828e207c
   Main PID: 32872 (sunsetr)
      Tasks: 9 (limit: 38078)
     Memory: 3.1M (peak: 4.3M)
        CPU: 113ms
     CGroup: /user.slice/user-1000.slice/[email protected]/background.slice/sunsetr.service
             └─32872 /nix/store/zxr17ivhdg7cx3p5yp4dqrilvl95m756-sunsetr-0.11.1-6e994ac/bin/sunsetr

nov 11 18:18:34 NixUSB sunsetr[32872]: ┃
nov 11 18:18:34 NixUSB sunsetr[32872]: ┣ Entering night mode <U+F4EE>
nov 11 18:18:34 NixUSB sunsetr[32872]: ┃
nov 11 18:18:34 NixUSB sunsetr[32872]: ┣ Next transition in 10 hours 56 minutes
nov 11 18:19:28 NixUSB sunsetr[32872]: ┃
nov 11 18:19:28 NixUSB sunsetr[32872]: ┣[INFO] System entering sleep/suspend mode
nov 11 18:19:36 NixUSB sunsetr[32872]: ┃
nov 11 18:19:36 NixUSB sunsetr[32872]: ┣[INFO] System resuming from sleep/suspend - reloading
nov 11 18:19:36 NixUSB sunsetr[32872]: ┃
nov 11 18:19:36 NixUSB sunsetr[32872]: ┣[INFO] Configuration reloaded (no state change needed)

MrStickyPiston avatar Nov 11 '25 17:11 MrStickyPiston

Is the temperature/gamma showing day values (when it should be night) after the app resumes from sleep? Is that what you mean when you say it was reset? I realize you're using the automatic backend detection, but what compositor were you using when you experienced this?

There is an ampty geo.toml file in the config dir, else it would not start without geo section.

This should only happen when your transition_mode is set to "geo". Maybe you had it set to "geo" first before you switched to "finish_by". You should be able to remove the geo.toml and the coordinates as they're not needed for "finish_by" mode, only for the geolocation-based transitions.

I am unable to reproduce this issue with the Nix flake (on Arch). I'm not sure what's going on here because I'm not a NixOS user. I've had help from NixOS users with setting up both the nixpkgs package and the Nix flake. Are you running the latest version with the flake?

psi4j avatar Nov 11 '25 18:11 psi4j

Ah! Do you have your computer set to do a DPMS cycle when your system sleeps? If this is the case, you may need to use the restart command in your script for when you resume from sleep. DPMS cycles destroy the backend on Hyprland in particular. We had a user who recently resolved this by adding sunsetr restart to his script.

psi4j avatar Nov 11 '25 18:11 psi4j

I am using hyprland, and tried with the "wayland" backend now but it gave the same result. The flake is on rev 6e994acae6f2f328212f10d7680a7fa481d122df, which should be the latest commit.

I dont think i have configured that. Also the event occurs even when running systemctl suspend, which does not even lock the screen. Restarting does seem like a good fix, i think i can do that with hypridle.

MrStickyPiston avatar Nov 11 '25 18:11 MrStickyPiston

I first tried services.hypridle.settings.general.after_sleep_cmd = "systemctl restart --user sunsetr";. For some reason, that did not work. The service did restart, and from the logs i would have guessed that it is working, but the filter clearly was not applied.

Then i tried services.hypridle.settings.general.after_sleep_cmd = "sleep 2 && systemctl restart --user sunsetr";. It worked, not even a flickering screen visible.

Clearly it depends on something to be ready, but what exactly?

MrStickyPiston avatar Nov 11 '25 18:11 MrStickyPiston

It appears something in your configuration may be destroying the backend's connection to the compositor on Hyprland. This is a known issue (#25) that requires an upstream fix in the compositor itself (doesn't happen on Niri or Sway). The current fix is to add sunsetr restart to your resume logic when resuming from sleep.

I don't use the systemd service file, but I can tell you that if the backend is being destroyed, it will require a full restart, not just a reload of the configuration (which is what the sleep/resume logic does and should do). It is the compositor's responsibility to maintain the state of the display across DPMS cycles as per Wayland protocols, but it appears Hyprland does not do this (and it also can cause issues with workspaces, which you may have noticed if you use multiple monitors).

What needs to be ready is the connection to the compositor, but it shouldn't take 2 full seconds. I don't use hypridle, so I couldn't tell you what it's doing. You may be able to reduce the sleep time and if you want the startup to be quicker use sunsetr restart -i as the command instead of the regular systemctl restart. This uses the restart command with the --instant flag, which bypasses the smooth transition when using the Wayland backend. If you're using the Hyprland backend, you can set render { ctm_animation = 0 } in hyprland.conf to shorten the startup time by eliminating the interpolation from day to night values.

Please let me know if this helps or fixes things.

psi4j avatar Nov 11 '25 18:11 psi4j

I just randomly chose a time and it seemed to work, i did not thoroughly test this.

That issues does seem to do something with dpms actively, i am not doing that because i have had issues with a lock screen with it.

What i think is weird is that i do not see the animation at all. It just shows up like it should. Im pretty sure it is not because of the command taking some time, because the systemd command always finished nearly immediately.

MrStickyPiston avatar Nov 11 '25 19:11 MrStickyPiston

It just shows up like it should. Im pretty sure it is not because of the command taking some time, because the systemd command always finished nearly immediately.

So, when you're resuming from sleep, there are various things starting back up which are happening in parallel, and it may just be that the timing is perfect or just long enough to hide the smooth transition. If it works for you, I would just use your current set up. I am unable to fix the issue of the backend being destroyed because this is not happening at the application layer, it's Hyprland which is not maintaining the state of the display in the manner that other compositors do and should. This issue doesn't exist on Niri or Sway. You can try your luck with them, but from what I've gathered in their discussions, they have no intentions on changing how their DPMS cycling works any time soon.

psi4j avatar Nov 11 '25 19:11 psi4j

So the other issue with this is that Hyprland does not provide a way for applications to detect if a DPMS cycle has occurred. Their IPC doesn't share when the monitors are turned on or off using DPMS, so sunsetr has no way to respond to the event without user intervention. This is why scripting a restart on resume is the only solution until Hyprland implements persisting state across DPMS cycles (if they choose to).

psi4j avatar Nov 11 '25 19:11 psi4j

Thank you for your help!

This fix works good enough for me, albeit being a bit janky it does the trick consistently without any drawbacks observed.

It may be a good idea to include this in the readme, as the main issue at hyprland probably doesn't get solved very quickly.

MrStickyPiston avatar Nov 12 '25 08:11 MrStickyPiston

I'll leave this open for the time being so people have a reference and a solution:

  1. If you're using Hyprland, the compositor breaks the connection to the backend upon a DPMS off signal and loses the state of the display.
  2. To re-initialize the backend, you can use sunsetr restart [--instant] [--background], or systemctl restart --user sunsetr if using the systemd service. You can play around with the timing as needed.

psi4j avatar Nov 12 '25 18:11 psi4j