2026-08-03 14:30:55 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
|
|
# Triggered by <Control><Alt>n
|
|
|
|
|
# as defined in [org/gnome/settings-daemon/plugins/media-keys]
|
|
|
|
|
# in ~/.config/gnome-settings/key-bindings.ini
|
|
|
|
|
#
|
|
|
|
|
# Night Light control:
|
|
|
|
|
#
|
|
|
|
|
# - <Control><Alt>n => "when" toggle
|
|
|
|
|
# + "Force" the screen to be warm right now!
|
|
|
|
|
# (Turns Night Light on if it was off, and keeps it on all day)
|
|
|
|
|
# + "Un-force" the Night Light into the local evening schedule
|
|
|
|
|
# - <Alt><Shift>n => "if" toggle
|
|
|
|
|
# Plain on/off switch for the Night Light feature
|
2026-08-14 20:45:34 +02:00
|
|
|
# - <Alt><Shift>Left => Make the screen cooler
|
|
|
|
|
# - <Alt><Shift>Right => Make the screen warmer, and "force" warmness
|
2026-08-03 14:30:55 +02:00
|
|
|
#
|
|
|
|
|
#
|
|
|
|
|
# State machine:
|
|
|
|
|
#
|
2026-08-14 20:45:34 +02:00
|
|
|
# +-----------------------+-----------------------+-----------------------+-----------------------+-----------------------+
|
|
|
|
|
# | | "IF" toggle | "WHEN" toggle | "make COOLER" | "make WARMER" |
|
|
|
|
|
# | Current STATE | <Alt><Shift>n | <Control><Alt>n | <Alt><Shift>Left | <Alt><Shift>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
|
|
|
|
|
#
|
2026-08-03 14:30:55 +02:00
|
|
|
|
|
|
|
|
set -eu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notify() {
|
|
|
|
|
ID_FILE="${XDG_RUNTIME_DIR}/night-light-notification-id"
|
|
|
|
|
_id=$(cat "$ID_FILE" 2>/dev/null || true)
|
|
|
|
|
|
|
|
|
|
if [ -n "$_id" ]; then
|
|
|
|
|
notify-send -p -t 5000 --replace-id="$_id" "Night Light" "$1" > "$ID_FILE" || rm -f "$ID_FILE"
|
|
|
|
|
else
|
|
|
|
|
notify-send -p -t 5000 "Night Light" "$1" > "$ID_FILE" || rm -f "$ID_FILE"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Schema=org.gnome.settings-daemon.plugins.color
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
active_before=$(gdbus call --session \
|
|
|
|
|
--dest org.gnome.SettingsDaemon.Color \
|
|
|
|
|
--object-path /org/gnome/SettingsDaemon/Color \
|
|
|
|
|
--method org.freedesktop.DBus.Properties.Get \
|
|
|
|
|
org.gnome.SettingsDaemon.Color NightLightActive)
|
|
|
|
|
|
2026-08-14 20:45:34 +02:00
|
|
|
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/')
|
|
|
|
|
|
2026-08-03 14:30:55 +02:00
|
|
|
automatic=$(gsettings get $Schema night-light-schedule-automatic)
|
|
|
|
|
enabled=$(gsettings get $Schema night-light-enabled)
|
2026-08-14 20:45:34 +02:00
|
|
|
target=$(gsettings get $Schema night-light-temperature | awk '{print $2}')
|
2026-08-03 14:30:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$automatic" = "true" ] || [ "$enabled" = "false" ]; then
|
|
|
|
|
|
|
|
|
|
# Force "Night Light" enabled, enabling it if needed
|
|
|
|
|
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
|
|
|
|
|
|
2026-08-14 20:45:34 +02:00
|
|
|
if [ "$active_before" = "(<true>,)" ] && [ "$automatic" = "true" ] \
|
|
|
|
|
&& [ $((applied - target)) -le 300 ]; then
|
2026-08-03 14:30:55 +02:00
|
|
|
notify "is now forced to stay on and no longer on an automatic schedule"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
# Back to the live location's schedule
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
if [ "$active_before" = "(<true>,)" ]; then
|
|
|
|
|
|
|
|
|
|
# Give the settings daemon a moment to recompute "NightLightActive"
|
|
|
|
|
sleep 0.1
|
|
|
|
|
|
|
|
|
|
active_after=$(gdbus call --session \
|
|
|
|
|
--dest org.gnome.SettingsDaemon.Color \
|
|
|
|
|
--object-path /org/gnome/SettingsDaemon/Color \
|
|
|
|
|
--method org.freedesktop.DBus.Properties.Get \
|
|
|
|
|
org.gnome.SettingsDaemon.Color NightLightActive)
|
|
|
|
|
|
|
|
|
|
if [ "$active_after" = "(<true>,)" ]; then
|
|
|
|
|
notify "is still on because of an automatic schedule"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
fi
|