diff --git a/.config/gnome-settings/misc.ini b/.config/gnome-settings/misc.ini index d726e5a..c68d2f4 100644 --- a/.config/gnome-settings/misc.ini +++ b/.config/gnome-settings/misc.ini @@ -452,6 +452,7 @@ night-light-schedule-automatic=true night-light-schedule-from=18.0 night-light-schedule-to=6.0 +# The `$_DEFAULT_TEMPERATURE` used in the ~/.local/bin/night-light-* scripts night-light-temperature=uint32 2200 diff --git a/.config/systemd/user/night-light-reset.service b/.config/systemd/user/night-light-reset.service new file mode 100644 index 0000000..5a34b5b --- /dev/null +++ b/.config/systemd/user/night-light-reset.service @@ -0,0 +1,6 @@ +[Unit] +Description=Return "Night Light" to the automatic schedule + +[Service] +Type=oneshot +ExecStart=%h/.local/bin/night-light-reset diff --git a/.config/systemd/user/night-light-reset.timer b/.config/systemd/user/night-light-reset.timer new file mode 100644 index 0000000..64079f1 --- /dev/null +++ b/.config/systemd/user/night-light-reset.timer @@ -0,0 +1,6 @@ +[Timer] +OnCalendar=03:00 +Persistent=false + +[Install] +WantedBy=timers.target diff --git a/.config/systemd/user/restore-gnome.service b/.config/systemd/user/restore-gnome.service index 1651a82..1d2d363 100644 --- a/.config/systemd/user/restore-gnome.service +++ b/.config/systemd/user/restore-gnome.service @@ -1,5 +1,5 @@ [Unit] -Description=Restore the GNOME settings from ~/.config/gnome-settings/*.ini +Description=Restore of the GNOME settings upon login Before=gnome-session-pre.target ConditionPathIsDirectory=%h/.config/gnome-settings diff --git a/.local/bin/install-dotfiles b/.local/bin/install-dotfiles index 4443aa9..2e4dfa9 100755 --- a/.local/bin/install-dotfiles +++ b/.local/bin/install-dotfiles @@ -122,6 +122,7 @@ fi if [ -f "$HOME/.config/systemd/user/restore-gnome.service" ]; then systemctl --user daemon-reload + systemctl --user enable night-light-reset.timer systemctl --user enable restore-gnome.service systemctl --user status --no-pager restore-gnome.service || true fi diff --git a/.local/bin/night-light-make-cooler b/.local/bin/night-light-make-cooler index ccae215..b115687 100755 --- a/.local/bin/night-light-make-cooler +++ b/.local/bin/night-light-make-cooler @@ -4,13 +4,11 @@ # as defined in [org/gnome/settings-daemon/plugins/media-keys] # in ~/.config/gnome-settings/key-bindings.ini # -# This script ensures "Night Light" is forced on -# if it was not yet on by schedule -# and makes the screen a bit cooler than it currently is +# This script makes the screen a bit cooler than it currently is, +# unless it is currently in a ramping phase and not fully tinted # # The default warmth is restored at login by ~/.local/bin/restore-gnome - set -eu @@ -42,9 +40,41 @@ active=$(gdbus call --session \ --method org.freedesktop.DBus.Properties.Get \ org.gnome.SettingsDaemon.Color NightLightActive) +applied=$(gdbus call --session \ + --dest org.gnome.SettingsDaemon.Color \ + --object-path /org/gnome/SettingsDaemon/Color \ + --method org.freedesktop.DBus.Properties.Get \ + org.gnome.SettingsDaemon.Color Temperature \ + | sed -E 's/.*uint32 ([0-9]+).*/\1/') + +automatic=$(gsettings get $Schema night-light-schedule-automatic) current=$(gsettings get $Schema night-light-temperature | awk '{print $2}') +# Cooling never turns "Night Light" on +if [ "$active" = "(,)" ]; then + notify "is not tinting the screen right now (target: ${current}K)" + exit 0 +fi + + +# While the screen is not (fully) tinted, +# stepping the target has no visible effect +# => Only show what is going on +if [ "$automatic" = "true" ] && [ $((applied - current)) -gt 300 ]; then + notify "is still following the schedule's ramp (target: ${current}K)" + exit 0 +fi + + +# Walking past the cool end switches the feature off +if [ "$current" -ge $_MAX_TEMPERATURE ]; then + gsettings set $Schema night-light-enabled false + notify "is now off (stepped past ${_MAX_TEMPERATURE}K)" + exit 0 +fi + + # 500 = (4700 - 1700 + 500) / 7 # => Seven steps spanning more than the range in the GUI, # mainly because we want to allow a bit more warmth (i.e., +500) @@ -56,30 +86,3 @@ fi gsettings set $Schema night-light-temperature "uint32 $new" - - -# Force "Night Light" on, saving a n call, -# with the same settings as in ~/.local/bin/night-light-toggle-schedule -if [ "$active" = "(,)" ]; then - gsettings set $Schema night-light-enabled true - gsettings set $Schema night-light-schedule-automatic false - gsettings set $Schema night-light-schedule-from 0.0 - gsettings set $Schema night-light-schedule-to 24.0 -fi - - -if [ "$current" -ge $_MAX_TEMPERATURE ]; then - - if [ "$active" = "(,)" ]; then - notify "is now forced on and already as cool as it gets (${_MAX_TEMPERATURE}K)" - else - notify "is already as cool as it gets (${_MAX_TEMPERATURE}K)" - fi - -else - - if [ "$active" = "(,)" ]; then - notify "is now forced on at ${new}K" - fi - -fi diff --git a/.local/bin/night-light-make-warmer b/.local/bin/night-light-make-warmer index 43e9a68..67bf3ca 100755 --- a/.local/bin/night-light-make-warmer +++ b/.local/bin/night-light-make-warmer @@ -5,12 +5,10 @@ # in ~/.config/gnome-settings/key-bindings.ini # # This script ensures "Night Light" is forced on -# if it was not yet on by schedule -# and makes the screen a bit warmer than it currently is +# or makes the screen a bit warmer than it currently is # # The default warmth is restored at login by ~/.local/bin/restore-gnome - set -eu @@ -20,6 +18,8 @@ set -eu _MIN_TEMPERATURE=1200 _MAX_TEMPERATURE=4700 +_DEFAULT_TEMPERATURE=2200 + notify() { ID_FILE="${XDG_RUNTIME_DIR}/night-light-notification-id" @@ -42,25 +42,52 @@ active=$(gdbus call --session \ --method org.freedesktop.DBus.Properties.Get \ org.gnome.SettingsDaemon.Color NightLightActive) +applied=$(gdbus call --session \ + --dest org.gnome.SettingsDaemon.Color \ + --object-path /org/gnome/SettingsDaemon/Color \ + --method org.freedesktop.DBus.Properties.Get \ + org.gnome.SettingsDaemon.Color Temperature \ + | sed -E 's/.*uint32 ([0-9]+).*/\1/') + +automatic=$(gsettings get $Schema night-light-schedule-automatic) current=$(gsettings get $Schema night-light-temperature | awk '{print $2}') -# 500 = (4700 - 1700 + 500) / 7 -# => Seven steps spanning more than the range in the GUI, -# mainly because we want to allow a bit more warmth (i.e., +500) -new=$((current - 500)) - -if [ "$new" -lt $_MIN_TEMPERATURE ]; then - new=$_MIN_TEMPERATURE +if [ "$active" = "(,)" ] \ + && { [ "$automatic" = "false" ] || [ $((applied - current)) -le 300 ]; }; then + at_target=true +else + at_target=false fi -gsettings set $Schema night-light-temperature "uint32 $new" +# Step only if the screen already shows the target tint +# while off or ramping in, forcing on below provides the warming already +if [ "$at_target" = "true" ]; then + + # 500 = (4700 - 1700 + 500) / 7 + # => Seven steps spanning more than the range in the GUI, + # mainly because we want to allow a bit more warmth (i.e., +500) + new=$((current - 500)) + + if [ "$new" -lt $_MIN_TEMPERATURE ]; then + new=$_MIN_TEMPERATURE + fi + + gsettings set $Schema night-light-temperature "uint32 $new" + +# Untinted and parked at a cool target +# => Forcing on would barely show otherwise +elif [ "$active" = "(,)" ] && [ "$current" -gt $_DEFAULT_TEMPERATURE ]; then + + gsettings set $Schema night-light-temperature "uint32 $_DEFAULT_TEMPERATURE" + +fi -# Force "Night Light" on, saving a n call, +# Always force "Night Light" on, saving a n call, # with the same settings as in ~/.local/bin/night-light-toggle-schedule -if [ "$active" = "(,)" ]; then +if [ "$active" = "(,)" ] || [ "$automatic" = "true" ]; then gsettings set $Schema night-light-enabled true gsettings set $Schema night-light-schedule-automatic false gsettings set $Schema night-light-schedule-from 0.0 @@ -68,18 +95,8 @@ if [ "$active" = "(,)" ]; then fi -if [ "$current" -le $_MIN_TEMPERATURE ]; then - - if [ "$active" = "(,)" ]; then - notify "is now forced on and already as warm as it gets (${_MIN_TEMPERATURE}K)" - else - notify "is already as warm as it gets (${_MIN_TEMPERATURE}K)" - fi - -else - - if [ "$active" = "(,)" ]; then - notify "is now forced on at ${new}K" - fi - +# Notify only if the press produced no visible change +# (i.e., already at the minimum and not just snapped to full warmth by the force) +if [ "$at_target" = "true" ] && [ "$current" -le $_MIN_TEMPERATURE ]; then + notify "is already as warm as it gets (${_MIN_TEMPERATURE}K)" fi diff --git a/.local/bin/night-light-reset b/.local/bin/night-light-reset new file mode 100755 index 0000000..5224c6d --- /dev/null +++ b/.local/bin/night-light-reset @@ -0,0 +1,25 @@ +#!/bin/sh + +# Ensure "Night Light" is enabled, +# set to run according to the automatic schedule, +# and reverted to the `_DEFAULT_TEMPERATURE` +# +# Intended to be run at 03:00 by the `night-light-reset.timer` systemd +# user unit, so that a forced state does not persist +# +# See ~/.local/bin/night-light-toggle-schedule for detailed documentation + +set -eu + + +_DEFAULT_TEMPERATURE=2200 + + +Schema=org.gnome.settings-daemon.plugins.color + +gsettings set $Schema night-light-enabled true +gsettings set $Schema night-light-schedule-automatic true +gsettings set $Schema night-light-schedule-from 18.0 +gsettings set $Schema night-light-schedule-to 6.0 + +gsettings set $Schema night-light-temperature "uint32 $_DEFAULT_TEMPERATURE" diff --git a/.local/bin/night-light-toggle-enabled b/.local/bin/night-light-toggle-enabled index 4b895cf..77dd6c1 100755 --- a/.local/bin/night-light-toggle-enabled +++ b/.local/bin/night-light-toggle-enabled @@ -8,7 +8,6 @@ # for the other half of the toggling logic # and extensive documentation - set -eu @@ -48,9 +47,17 @@ else # We could start from our default warmth, as defined # in [org/gnome/settings-daemon/plugins/color] # in ~/.config/gnome-settings/misc.ini - # but choose not to do that because the default - # warmth is reset anyways after a reboot - # gsettings set $Schema night-light-temperature "uint32 2200" + # but choose not to do that because this is meant to be + # a plain on/off switch with no side effects + # => Snapping is left to Right, which is about + # warmth rather than about the feature being on or off + # + # _DEFAULT_TEMPERATURE=2200 + # current=$(gsettings get $Schema night-light-temperature | awk '{print $2}') + # + # if [ "$current" -gt $_DEFAULT_TEMPERATURE ]; then + # gsettings set $Schema night-light-temperature "uint32 $_DEFAULT_TEMPERATURE" + # fi # Give the settings daemon a moment to recompute "NightLightActive" sleep 0.1 diff --git a/.local/bin/night-light-toggle-schedule b/.local/bin/night-light-toggle-schedule index 25ae9ca..86a24f9 100755 --- a/.local/bin/night-light-toggle-schedule +++ b/.local/bin/night-light-toggle-schedule @@ -12,28 +12,62 @@ # + "Un-force" the Night Light into the local evening schedule # - n => "if" toggle # Plain on/off switch for the Night Light feature +# - Left => Make the screen cooler +# - Right => Make the screen warmer, and "force" warmness # -# Neither key binding changes what the other controls, so they don't fight. -# -# Making the screen cooler or warmer with Left/Right -# also forces "Night Light" on because adjusting this implies -# that the user wants to use it. # # State machine: -# TARGET STATE -# +--------------------------+--------------------------+ -# CURRENT STATE | nl-toggle-schedule | nl-toggle-enabled | -# +--------------------------+--------------------------+--------------------------+ -# | disabled, automatic | enabled, force | enabled, automatic (*) | -# | disabled, force | enabled, force | enabled, force | -# | enabled, automatic | enabled, force (*) | disabled, automatic (*) | -# | enabled, force | enabled, automatic (*) | disabled, force | -# +--------------------------+--------------------------+--------------------------+ -# (*) There are four cases where a user does not perceive a change on the screen. -# Then, a notification is shown instead. # -# See ~/.local/bin/night-light-toggle-enabled for the other half of the toggling logic - +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | | "IF" toggle | "WHEN" toggle | "make COOLER" | "make WARMER" | +# | Current STATE | n | n | Left | Right | +# | | | | | | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | DISABLED | ENABLE | enabled | still disabled | enabled | +# | + scheduled | + still scheduled | + FORCED on | + still scheduled | + FORCED on | +# | => no tint | => no or set tint | => set tint | => still no tint | => set tint | +# | | based on time N? | | N! | *1 | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | DISABLED | ENABLE | enabled | still disabled | enabled | +# | + forced on | + still forced | + still FORCED on | + still forced | + still FORCED on | +# | => no tint | => set tint | => set tint | => still no tint | => set tint | +# | | | | N! | *1 | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | enabled | DISABLE | still enabled | still enabled | still enabled | +# | + SCHEDULED (day) | + still scheduled | + FORCED on | + still scheduled | + FORCED on | +# | => no tint yet | => still no tint | => set tint | => still no tint | => set tint | +# | | N! | | N! | *1 | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | enabled | DISABLE | still enabled | still enabled | still enabled | +# | + SCHEDULED (ramping) | + still scheduled | + FORCED on | + still scheduled | + FORCED on | +# | => some tint already | => no tint | => set tint | => no change in tint | => set tint | +# | | | | N! | | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | enabled | DISABLE | still enabled | still enabled | still enabled | +# | + SCHEDULED (night) | + still scheduled | + FORCED on | + still scheduled | + FORCED on | +# | => set tint | => no tint | => set tint | => LESS tint | => MORE tint | +# | | | N! | *2 N? | N? | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# | enabled | DISABLE | still enabled | still enabled | still enabled | +# | + FORCED on | + still forced on | + back to SCHEDULED | + still forced on | + still forced on | +# | => set tint | => no tint | => no or set tint | => LESS tint | => MORE tint | +# | | | based on time N? | *2 N? | N? | +# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+ +# Legend: +# - N! => A notification is shown for sure because there is no visible change on the screen +# - N? => A notification is shown if there was no visible change on the screen +# - *1 => The temperature is snapped to 2200K to ensure a visible effect +# - *2 => The tint is turned off entirely when stepping over the maximum temperature +# +# Notes: +# - The main state property or state change is shown in CAPS +# - Steps range from 1200K (warmest) to 4700K (coolest), +# which is a bit more than the 1700K to 4700K in `gnome-control-center` +# - If the range is already exhausted, so that the tint does not change, a notification is shown +# - A 03:00 timer re-enables the Night Light feature and puts it back on the automatic schedule +# with the `$_DEFAULT_TEMPERATURE` set +# set -eu @@ -59,8 +93,16 @@ active_before=$(gdbus call --session \ --method org.freedesktop.DBus.Properties.Get \ org.gnome.SettingsDaemon.Color NightLightActive) +applied=$(gdbus call --session \ + --dest org.gnome.SettingsDaemon.Color \ + --object-path /org/gnome/SettingsDaemon/Color \ + --method org.freedesktop.DBus.Properties.Get \ + org.gnome.SettingsDaemon.Color Temperature \ + | sed -E 's/.*uint32 ([0-9]+).*/\1/') + automatic=$(gsettings get $Schema night-light-schedule-automatic) enabled=$(gsettings get $Schema night-light-enabled) +target=$(gsettings get $Schema night-light-temperature | awk '{print $2}') if [ "$automatic" = "true" ] || [ "$enabled" = "false" ]; then @@ -71,7 +113,8 @@ if [ "$automatic" = "true" ] || [ "$enabled" = "false" ]; then gsettings set $Schema night-light-schedule-from 0.0 gsettings set $Schema night-light-schedule-to 24.0 - if [ "$active_before" = "(,)" ] && [ "$automatic" = "true" ]; then + if [ "$active_before" = "(,)" ] && [ "$automatic" = "true" ] \ + && [ $((applied - target)) -le 300 ]; then notify "is now forced to stay on and no longer on an automatic schedule" fi