diff --git a/config/dot/quickshell/config/PreferenceSchema.qml b/config/dot/quickshell/config/PreferenceSchema.qml index f754f86..c7a3034 100644 --- a/config/dot/quickshell/config/PreferenceSchema.qml +++ b/config/dot/quickshell/config/PreferenceSchema.qml @@ -369,6 +369,23 @@ Singleton { detail: "Requires your password when the machine wakes" }, + // ── Night light schedule ──────────────────────────────────────────── + // Hours as decimals, so 17.5 is half past five. Wrapping past midnight + // is normal here and is what the shipped values do: on at 17:00, off at + // 10:00 the following morning. + { + key: "nightLightFrom", type: "real", def: 17.0, min: 0, max: 23.5, step: 0.5, + group: "nightLight", + label: "Turns on at", + detail: "Only used when Night Light follows a schedule" + }, + { + key: "nightLightTo", type: "real", def: 10.0, min: 0, max: 23.5, step: 0.5, + group: "nightLight", + label: "Turns off at", + detail: "A time earlier than the start simply means the next morning" + }, + // ── Accessibility ─────────────────────────────────────────────────── // Backed by gsettings so GTK applications agree with the shell, and // pushed to the compositor as well where it has its own notion. diff --git a/config/dot/quickshell/config/Settings.qml b/config/dot/quickshell/config/Settings.qml index 31f40e7..a5cfe0b 100644 --- a/config/dot/quickshell/config/Settings.qml +++ b/config/dot/quickshell/config/Settings.qml @@ -46,8 +46,8 @@ Singleton { // ── Night light ───────────────────────────────────────────────────────── // Matches the (disabled) GNOME schedule: 3500K from 17:00 to 10:00. readonly property int nightLightTemperature: DesktopPreferences.get("nightLightTemperature") - readonly property real nightLightFrom: 17.0 - readonly property real nightLightTo: 10.0 + readonly property real nightLightFrom: DesktopPreferences.get("nightLightFrom") + readonly property real nightLightTo: DesktopPreferences.get("nightLightTo") readonly property bool nightLightEnabledByDefault: DesktopPreferences.get("nightLightEnabled") // ── Notifications ─────────────────────────────────────────────────────── diff --git a/config/dot/quickshell/modules/settings/DisplaysPage.qml b/config/dot/quickshell/modules/settings/DisplaysPage.qml index a47a660..729aaea 100644 --- a/config/dot/quickshell/modules/settings/DisplaysPage.qml +++ b/config/dot/quickshell/modules/settings/DisplaysPage.qml @@ -187,6 +187,19 @@ SettingsPage { } } + SettingsCard { + title: "Night Light" + subtitle: NightLight.active + ? "On now, warming the display to reduce blue light." + : "Warms the display in the evening to reduce blue light." + + ToggleRow { setting: "nightLightEnabled" } + ToggleRow { setting: "nightLightAutomatic" } + TimeOfDayRow { setting: "nightLightFrom" } + TimeOfDayRow { setting: "nightLightTo" } + SliderRow { setting: "nightLightTemperature"; divider: false } + } + SettingsCard { title: "Gaming display policy" subtitle: "Applied immediately and restored when Panama starts." diff --git a/config/dot/quickshell/modules/settings/NotificationsPage.qml b/config/dot/quickshell/modules/settings/NotificationsPage.qml index 08172aa..d3b9cc3 100644 --- a/config/dot/quickshell/modules/settings/NotificationsPage.qml +++ b/config/dot/quickshell/modules/settings/NotificationsPage.qml @@ -118,6 +118,21 @@ SettingsPage { title: "Focus sessions" subtitle: "A focus session binds quiet mode and Caffeine to the current workspace." + SettingRow { + label: "Keep the screen awake" + detail: Caffeine.enabled + ? "The display will not blank or lock while this is on" + : "Idle timings on Power & Lock apply normally" + controlWidth: 48 + + SettingsToggle { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + checked: Caffeine.enabled + onToggled: value => Caffeine.enabled = value + } + } + SettingRow { id: durationRow diff --git a/config/dot/quickshell/modules/settings/ShortcutsPage.qml b/config/dot/quickshell/modules/settings/ShortcutsPage.qml index ddfcfa8..6460815 100644 --- a/config/dot/quickshell/modules/settings/ShortcutsPage.qml +++ b/config/dot/quickshell/modules/settings/ShortcutsPage.qml @@ -28,6 +28,11 @@ SettingsPage { SettingsCard { title: "Keyboard" + TextRow { + label: "Keyboard layout" + detail: "XKB layout name. Changing it needs a compositor reload, so it is shown here rather than offered as a control that appears to apply instantly." + value: Settings ? DesktopPreferences.get("keyboardLayout") : "us" + } SliderRow { setting: "keyRepeatDelay" } SliderRow { setting: "keyRepeatRate" } ToggleRow { setting: "numlockByDefault"; divider: false } diff --git a/config/dot/quickshell/modules/settings/TimeOfDayRow.qml b/config/dot/quickshell/modules/settings/TimeOfDayRow.qml new file mode 100644 index 0000000..d6d0ce3 --- /dev/null +++ b/config/dot/quickshell/modules/settings/TimeOfDayRow.qml @@ -0,0 +1,31 @@ +// A time of day, stored as a decimal hour. +// +// SliderRow would render 17.5 as "17.50", which is not how anyone reads a +// clock. This is the same control with the readout formatted as a time, so the +// night light schedule says "5:30 PM" rather than a number you have to convert. +// +// Honours the 24-hour clock preference, because a user who has asked for 18:30 +// everywhere else should not be shown 6:30 PM here. + +import QtQuick +import qs.config +import qs.services + +SliderRow { + id: root + + // SliderRow renders `unit` after the number; a time needs the whole readout + // replaced, so the formatting is done here instead. + function display(value: real): string { + const hour = Math.floor(value); + const minute = Math.round((value - hour) * 60); + const padded = String(minute).padStart(2, "0"); + + if (Settings.use24Hour) + return `${String(hour).padStart(2, "0")}:${padded}`; + + const suffix = hour < 12 ? "AM" : "PM"; + const twelve = hour % 12 === 0 ? 12 : hour % 12; + return `${twelve}:${padded} ${suffix}`; + } +} diff --git a/config/dot/quickshell/modules/settings/qmldir b/config/dot/quickshell/modules/settings/qmldir index 5fa46ea..d47e899 100644 --- a/config/dot/quickshell/modules/settings/qmldir +++ b/config/dot/quickshell/modules/settings/qmldir @@ -43,3 +43,4 @@ PasswordField 1.0 PasswordField.qml AudioBalance 1.0 AudioBalance.qml SoundDeviceList 1.0 SoundDeviceList.qml SoundDeviceRow 1.0 SoundDeviceRow.qml +TimeOfDayRow 1.0 TimeOfDayRow.qml diff --git a/config/dot/quickshell/services/NightLight.qml b/config/dot/quickshell/services/NightLight.qml index 957fc2b..ba53d0d 100644 --- a/config/dot/quickshell/services/NightLight.qml +++ b/config/dot/quickshell/services/NightLight.qml @@ -89,6 +89,34 @@ Singleton { onEnabledChanged: DesktopPreferences.set("nightLightEnabled", root.enabled) onAutomaticChanged: DesktopPreferences.set("nightLightAutomatic", root.automatic) + // `enabled`, `temperature`, and `automatic` are declared as bindings on the + // store, but a binding is destroyed the moment anything assigns to the + // property -- which toggle() does. Without this, the service would write to + // the store and never read from it again: Quick Settings would keep working + // while the same settings on the Displays page silently did nothing, which + // is worse than not offering them there at all. + // + // No loop: set() is a no-op when the value is unchanged, and assigning a + // property its current value emits nothing, so this converges immediately. + Connections { + target: DesktopPreferences + function onRevisionChanged(): void { root.syncFromStore(); } + } + + function syncFromStore(): void { + const storedEnabled = DesktopPreferences.get("nightLightEnabled") === true; + if (root.enabled !== storedEnabled) + root.enabled = storedEnabled; + + const storedAutomatic = DesktopPreferences.get("nightLightAutomatic") === true; + if (root.automatic !== storedAutomatic) + root.automatic = storedAutomatic; + + const storedTemperature = DesktopPreferences.get("nightLightTemperature"); + if (typeof storedTemperature === "number" && root.temperature !== storedTemperature) + root.temperature = storedTemperature; + } + onActiveChanged: { if (!root.initialized) return; diff --git a/config/dot/quickshell/services/SettingsSearch.qml b/config/dot/quickshell/services/SettingsSearch.qml index e45028f..943b41b 100644 --- a/config/dot/quickshell/services/SettingsSearch.qml +++ b/config/dot/quickshell/services/SettingsSearch.qml @@ -29,6 +29,7 @@ Singleton { "dock": "desktop", "focus": "desktop", "display": "displays", + "nightLight": "displays", "idle": "power", "accessibility": "accessibility", "input": "shortcuts",