Build the Panama Hyprland desktop
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
pragma Singleton
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Night light — a thin wrapper around hyprsunset (0.4.0).
|
||||
//
|
||||
// hyprsunset is a daemon: `hyprsunset -t <kelvin>` grabs wlr-gamma-control and
|
||||
// holds it until it exits, and `hyprctl hyprsunset <request>` re-tunes the
|
||||
// running instance over its socket. So the shape here is:
|
||||
// * `active` drives whether the daemon process runs at all,
|
||||
// * temperature changes are pushed to the *running* daemon rather than
|
||||
// restarting it, which would flash the screen back to 6500K.
|
||||
//
|
||||
// Gamma is restored by the compositor when the daemon's gamma-control object
|
||||
// dies, so stopping the Process is a complete "off" — no `-i` pass needed.
|
||||
//
|
||||
// Only works under Hyprland; there is no gamma protocol on GNOME, so the
|
||||
// daemon exits immediately there. That is reported once, not retried.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool initialized: false
|
||||
|
||||
// The manual switch. Ignored while `automatic` is on.
|
||||
property bool enabled: Settings.nightLightEnabledByDefault
|
||||
property int temperature: Settings.nightLightTemperature
|
||||
|
||||
// Follow Settings.nightLightFrom .. nightLightTo instead of the manual
|
||||
// switch. Off by default because GNOME's schedule was disabled.
|
||||
property bool automatic: DesktopPreferences.nightLightAutomatic
|
||||
|
||||
// What is actually applied right now.
|
||||
readonly property bool active: root.automatic ? root.scheduled : root.enabled
|
||||
|
||||
// True while the wall clock is inside the scheduled window.
|
||||
readonly property bool scheduled: root.inWindow(clock.hours + clock.minutes / 60)
|
||||
|
||||
// A manual toggle always wins: it drops out of the schedule rather than
|
||||
// being silently reverted a minute later. Same as GNOME's behaviour when
|
||||
// you flip night light off during a scheduled evening.
|
||||
function toggle(): void {
|
||||
if (root.automatic) {
|
||||
root.automatic = false;
|
||||
root.enabled = !root.scheduled;
|
||||
} else {
|
||||
root.enabled = !root.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// The window wraps midnight (17:00 → 10:00), so the comparison flips when
|
||||
// `from` is later in the day than `to`.
|
||||
function inWindow(hour: real): bool {
|
||||
const from = Settings.nightLightFrom;
|
||||
const to = Settings.nightLightTo;
|
||||
return from <= to ? (hour >= from && hour < to) : (hour >= from || hour < to);
|
||||
}
|
||||
|
||||
// Only ticks while the schedule is in charge — no idle work otherwise.
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Minutes
|
||||
enabled: root.automatic
|
||||
}
|
||||
|
||||
Process {
|
||||
id: daemon
|
||||
command: ["hyprsunset", "-t", String(root.temperature)]
|
||||
running: root.active
|
||||
|
||||
onExited: (code, status) => {
|
||||
if (root.active)
|
||||
console.warn("NightLight: hyprsunset exited with", code, "- is Hyprland running?");
|
||||
}
|
||||
}
|
||||
|
||||
// Re-tune in place; restarting the daemon would flash the display.
|
||||
onTemperatureChanged: {
|
||||
DesktopPreferences.nightLightTemperature = root.temperature;
|
||||
if (daemon.running)
|
||||
Quickshell.execDetached(["hyprctl", "hyprsunset", "temperature", String(root.temperature)]);
|
||||
}
|
||||
|
||||
onEnabledChanged: DesktopPreferences.nightLightEnabled = root.enabled
|
||||
onAutomaticChanged: DesktopPreferences.nightLightAutomatic = root.automatic
|
||||
|
||||
onActiveChanged: {
|
||||
if (!root.initialized)
|
||||
return;
|
||||
StatusEvents.publish({
|
||||
key: "display-night-light",
|
||||
glyph: "\u{F0F31}",
|
||||
title: root.active ? "Night Light on" : "Night Light off",
|
||||
detail: root.active ? String(root.temperature) + " K" : "Display colors restored",
|
||||
tone: root.active ? "warn" : "accent",
|
||||
priority: StatusEvents.ambientPriority
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: Qt.callLater(() => root.initialized = true)
|
||||
}
|
||||
Reference in New Issue
Block a user