mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-11 07:52:50 -05:00
night mode repairs
This commit is contained in:
@@ -5,7 +5,6 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
@@ -33,7 +32,18 @@ Singleton {
|
||||
signal brightnessChanged
|
||||
signal deviceSwitched
|
||||
|
||||
property bool nightModeActive: false
|
||||
property bool nightModeActive: nightModeEnabled
|
||||
|
||||
// Night Mode Properties
|
||||
property bool nightModeEnabled: false
|
||||
property bool automationAvailable: false
|
||||
property bool geoclueAvailable: false
|
||||
property bool isAutomaticNightTime: false
|
||||
|
||||
function buildGammastepCommand(gammastepArgs) {
|
||||
const commandStr = "pkill gammastep; " + ["gammastep"].concat(gammastepArgs).join(" ")
|
||||
return ["sh", "-c", commandStr]
|
||||
}
|
||||
|
||||
function setBrightnessInternal(percentage, device) {
|
||||
const clampedValue = Math.max(1, Math.min(100, percentage))
|
||||
@@ -214,58 +224,211 @@ Singleton {
|
||||
ddcInitialBrightnessProcess.running = true
|
||||
}
|
||||
|
||||
// Night Mode Functions - Simplified
|
||||
function enableNightMode() {
|
||||
if (nightModeActive)
|
||||
if (!automationAvailable) {
|
||||
gammaStepTestProcess.running = true
|
||||
return
|
||||
}
|
||||
|
||||
// Test if gammastep exists before enabling
|
||||
gammaStepTestProcess.running = true
|
||||
}
|
||||
|
||||
function updateNightModeTemperature(temperature) {
|
||||
SessionData.setNightModeTemperature(temperature)
|
||||
|
||||
// If night mode is active, restart it with new temperature
|
||||
if (nightModeActive) {
|
||||
// Temporarily disable and re-enable to restart with new temp
|
||||
nightModeActive = false
|
||||
Qt.callLater(() => {
|
||||
if (SessionData.nightModeEnabled) {
|
||||
nightModeActive = true
|
||||
}
|
||||
})
|
||||
nightModeEnabled = true
|
||||
SessionData.setNightModeEnabled(true)
|
||||
|
||||
// Apply immediately or start automation
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
} else {
|
||||
applyNightModeDirectly()
|
||||
}
|
||||
}
|
||||
|
||||
function disableNightMode() {
|
||||
nightModeActive = false
|
||||
nightModeEnabled = false
|
||||
SessionData.setNightModeEnabled(false)
|
||||
|
||||
// Also kill any stray gammastep processes
|
||||
Quickshell.execDetached(["pkill", "gammastep"])
|
||||
stopAutomation()
|
||||
// Nuclear approach - kill ALL gammastep processes multiple times
|
||||
Quickshell.execDetached(["pkill", "-f", "gammastep"])
|
||||
Quickshell.execDetached(["pkill", "-9", "gammastep"])
|
||||
Quickshell.execDetached(["killall", "gammastep"])
|
||||
// Also stop all related processes
|
||||
gammaStepProcess.running = false
|
||||
automationProcess.running = false
|
||||
gammaStepTestProcess.running = false
|
||||
}
|
||||
|
||||
function toggleNightMode() {
|
||||
// Check if automation is active - show warning if trying to manually toggle
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
ToastService.showWarning("Night mode is in automatic mode. Disable automation in settings to control manually.")
|
||||
return
|
||||
}
|
||||
|
||||
if (nightModeActive) {
|
||||
if (nightModeEnabled) {
|
||||
disableNightMode()
|
||||
} else {
|
||||
enableNightMode()
|
||||
}
|
||||
}
|
||||
|
||||
function applyNightModeDirectly() {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-O", String(temperature)
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
}
|
||||
|
||||
function resetToNormalMode() {
|
||||
// Just kill gammastep to return to normal display temperature
|
||||
Quickshell.execDetached(["pkill", "gammastep"])
|
||||
}
|
||||
|
||||
function startAutomation() {
|
||||
if (!automationAvailable) return
|
||||
|
||||
const mode = SessionData.nightModeAutoMode || "time"
|
||||
|
||||
switch (mode) {
|
||||
case "time":
|
||||
startTimeBasedMode()
|
||||
break
|
||||
case "location":
|
||||
startLocationBasedMode()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function stopAutomation() {
|
||||
automationProcess.running = false
|
||||
gammaStepProcess.running = false
|
||||
isAutomaticNightTime = false
|
||||
// Nuclear approach - kill ALL gammastep processes multiple times
|
||||
Quickshell.execDetached(["pkill", "-f", "gammastep"])
|
||||
Quickshell.execDetached(["pkill", "-9", "gammastep"])
|
||||
Quickshell.execDetached(["killall", "gammastep"])
|
||||
}
|
||||
|
||||
function startTimeBasedMode() {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
|
||||
function startLocationBasedMode() {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
automationProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-l", `${SessionData.latitude.toFixed(6)}:${SessionData.longitude.toFixed(6)}`,
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
])
|
||||
automationProcess.running = true
|
||||
return
|
||||
}
|
||||
|
||||
if (SessionData.nightModeLocationProvider === "geoclue2") {
|
||||
automationProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
])
|
||||
automationProcess.running = true
|
||||
return
|
||||
}
|
||||
|
||||
console.warn("DisplayService: Location mode selected but no coordinates or geoclue provider set")
|
||||
}
|
||||
|
||||
function checkTimeBasedMode() {
|
||||
if (!nightModeEnabled || !SessionData.nightModeAutoEnabled || SessionData.nightModeAutoMode !== "time") {
|
||||
return
|
||||
}
|
||||
|
||||
const now = new Date()
|
||||
const currentTime = now.getHours() * 60 + now.getMinutes()
|
||||
|
||||
const startMinutes = SessionData.nightModeStartHour * 60 + SessionData.nightModeStartMinute
|
||||
const endMinutes = SessionData.nightModeEndHour * 60 + SessionData.nightModeEndMinute
|
||||
|
||||
let shouldBeNight = false
|
||||
|
||||
if (startMinutes > endMinutes) {
|
||||
shouldBeNight = (currentTime >= startMinutes) || (currentTime < endMinutes)
|
||||
} else {
|
||||
shouldBeNight = (currentTime >= startMinutes) && (currentTime < endMinutes)
|
||||
}
|
||||
|
||||
if (shouldBeNight !== isAutomaticNightTime) {
|
||||
isAutomaticNightTime = shouldBeNight
|
||||
|
||||
if (shouldBeNight) {
|
||||
applyNightModeDirectly()
|
||||
} else {
|
||||
resetToNormalMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function detectLocationProviders() {
|
||||
geoclueDetectionProcess.running = true
|
||||
}
|
||||
|
||||
function setNightModeAutomationMode(mode) {
|
||||
console.log("DisplayService: Setting night mode automation mode to:", mode)
|
||||
SessionData.setNightModeAutoMode(mode)
|
||||
}
|
||||
|
||||
function evaluateNightMode() {
|
||||
console.log("DisplayService: Evaluating night mode state - enabled:", nightModeEnabled, "auto:", SessionData.nightModeAutoEnabled)
|
||||
|
||||
// Always stop all processes first to clean slate
|
||||
stopAutomation()
|
||||
|
||||
if (!nightModeEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
restartTimer.nextAction = "automation"
|
||||
restartTimer.start()
|
||||
} else {
|
||||
restartTimer.nextAction = "direct"
|
||||
restartTimer.start()
|
||||
}
|
||||
}
|
||||
|
||||
function checkNightModeAvailability() {
|
||||
gammastepAvailabilityProcess.running = true
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: restartTimer
|
||||
property string nextAction: ""
|
||||
interval: 100
|
||||
repeat: false
|
||||
|
||||
onTriggered: {
|
||||
if (nextAction === "automation") {
|
||||
startAutomation()
|
||||
} else if (nextAction === "direct") {
|
||||
applyNightModeDirectly()
|
||||
}
|
||||
nextAction = ""
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
ddcDetectionProcess.running = true
|
||||
refreshDevices()
|
||||
checkNightModeAvailability()
|
||||
|
||||
// Check if night mode was enabled on startup
|
||||
if (SessionData.nightModeEnabled) {
|
||||
enableNightMode()
|
||||
// Initialize night mode state from session
|
||||
nightModeEnabled = SessionData.nightModeEnabled
|
||||
}
|
||||
|
||||
SystemClock {
|
||||
precision: SystemClock.Minutes
|
||||
onDateChanged: {
|
||||
if (nightModeEnabled && SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,27 +556,11 @@ Singleton {
|
||||
"max": parseInt(parts[4])
|
||||
})
|
||||
}
|
||||
// Store brightnessctl devices separately, will be combined with DDC
|
||||
const brightnessCtlDevices = newDevices
|
||||
devices = brightnessCtlDevices
|
||||
|
||||
// If we have DDC devices, combine them
|
||||
if (ddcDevices.length > 0) {
|
||||
refreshDevicesInternal()
|
||||
} else if (devices.length > 0 && !currentDevice) {
|
||||
// Try to restore last selected device, fallback to first device
|
||||
const lastDevice = SessionData.lastBrightnessDevice || ""
|
||||
const deviceExists = devices.some(
|
||||
d => d.name === lastDevice)
|
||||
if (deviceExists) {
|
||||
setCurrentDevice(lastDevice, false)
|
||||
} else {
|
||||
const nonKbdDevice = devices.find(
|
||||
d => !d.name.includes("kbd"))
|
||||
|| devices[0]
|
||||
setCurrentDevice(nonKbdDevice.name, false)
|
||||
}
|
||||
}
|
||||
// Store brightnessctl devices separately
|
||||
devices = newDevices
|
||||
|
||||
// Always refresh to combine with DDC devices and set up device selection
|
||||
refreshDevicesInternal()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,46 +711,108 @@ Singleton {
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepTestProcess
|
||||
id: gammastepAvailabilityProcess
|
||||
command: ["which", "gammastep"]
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
automationAvailable = (exitCode === 0)
|
||||
if (automationAvailable) {
|
||||
console.log("DisplayService: gammastep available")
|
||||
detectLocationProviders()
|
||||
|
||||
// If night mode should be enabled on startup
|
||||
if (nightModeEnabled && SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
} else if (nightModeEnabled) {
|
||||
applyNightModeDirectly()
|
||||
}
|
||||
} else {
|
||||
console.log("DisplayService: gammastep not available")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: geoclueDetectionProcess
|
||||
command: ["sh", "-c", "busctl --system list | grep -qF org.freedesktop.GeoClue2"]
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
geoclueAvailable = (exitCode === 0)
|
||||
console.log("DisplayService: geoclue available:", geoclueAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepTestProcess
|
||||
command: ["which", "gammastep"]
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode === 0) {
|
||||
// gammastep exists, enable night mode
|
||||
nightModeActive = true
|
||||
automationAvailable = true
|
||||
nightModeEnabled = true
|
||||
SessionData.setNightModeEnabled(true)
|
||||
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
} else {
|
||||
applyNightModeDirectly()
|
||||
}
|
||||
} else {
|
||||
// gammastep not found
|
||||
console.warn("DisplayService: gammastep not found")
|
||||
ToastService.showWarning(
|
||||
"Night mode failed: gammastep not found")
|
||||
ToastService.showWarning("Night mode failed: gammastep not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepProcess
|
||||
|
||||
command: {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
return ["gammastep", "-m", "wayland", "-O", String(temperature)]
|
||||
}
|
||||
running: nightModeActive
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
// If process exits with non-zero code while we think it should be running
|
||||
if (nightModeActive && exitCode !== 0) {
|
||||
console.warn("DisplayService: Night mode process crashed with exit code:",
|
||||
exitCode)
|
||||
nightModeActive = false
|
||||
SessionData.setNightModeEnabled(false)
|
||||
ToastService.showWarning("Night mode failed: process crashed")
|
||||
if (nightModeEnabled && exitCode !== 0 && exitCode !== 15) {
|
||||
console.warn("DisplayService: Night mode process failed:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: automationProcess
|
||||
running: false
|
||||
property string processType: "automation"
|
||||
|
||||
onExited: function (exitCode) {
|
||||
if (nightModeEnabled && SessionData.nightModeAutoEnabled && exitCode !== 0 && exitCode !== 15) {
|
||||
console.warn("DisplayService: Night mode automation failed:", exitCode)
|
||||
// Location mode failed
|
||||
console.warn("DisplayService: Location-based night mode failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Session Data Connections
|
||||
Connections {
|
||||
target: SessionData
|
||||
|
||||
function onNightModeEnabledChanged() {
|
||||
nightModeEnabled = SessionData.nightModeEnabled
|
||||
evaluateNightMode()
|
||||
}
|
||||
|
||||
function onNightModeAutoEnabledChanged() { evaluateNightMode() }
|
||||
function onNightModeAutoModeChanged() { evaluateNightMode() }
|
||||
function onNightModeStartHourChanged() { evaluateNightMode() }
|
||||
function onNightModeStartMinuteChanged() { evaluateNightMode() }
|
||||
function onNightModeEndHourChanged() { evaluateNightMode() }
|
||||
function onNightModeEndMinuteChanged() { evaluateNightMode() }
|
||||
function onNightModeTemperatureChanged() { evaluateNightMode() }
|
||||
function onLatitudeChanged() { evaluateNightMode() }
|
||||
function onLongitudeChanged() { evaluateNightMode() }
|
||||
function onNightModeLocationProviderChanged() { evaluateNightMode() }
|
||||
}
|
||||
|
||||
// IPC Handler for external control
|
||||
IpcHandler {
|
||||
function set(percentage: string, device: string): string {
|
||||
@@ -702,9 +911,9 @@ Singleton {
|
||||
if (!root.brightnessAvailable)
|
||||
return "No brightness devices available"
|
||||
|
||||
let result = "Available devices:\n"
|
||||
let result = "Available devices:\\n"
|
||||
for (const device of root.devices) {
|
||||
result += device.name + " (" + device.class + ")\n"
|
||||
result += device.name + " (" + device.class + ")\\n"
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -716,7 +925,7 @@ Singleton {
|
||||
IpcHandler {
|
||||
function toggle(): string {
|
||||
root.toggleNightMode()
|
||||
return root.nightModeActive ? "Night mode enabled" : "Night mode disabled"
|
||||
return root.nightModeEnabled ? "Night mode enabled" : "Night mode disabled"
|
||||
}
|
||||
|
||||
function enable(): string {
|
||||
@@ -730,7 +939,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
return root.nightModeActive ? "Night mode is enabled" : "Night mode is disabled"
|
||||
return root.nightModeEnabled ? "Night mode is enabled" : "Night mode is disabled"
|
||||
}
|
||||
|
||||
function temperature(value: string): string {
|
||||
@@ -753,12 +962,13 @@ Singleton {
|
||||
|
||||
SessionData.setNightModeTemperature(rounded)
|
||||
|
||||
// If night mode is active, restart it with new temperature
|
||||
if (root.nightModeActive) {
|
||||
root.nightModeActive = false
|
||||
Qt.callLater(() => {
|
||||
root.nightModeActive = true
|
||||
})
|
||||
// Restart night mode with new temperature if active
|
||||
if (root.nightModeEnabled) {
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
root.startAutomation()
|
||||
} else {
|
||||
root.applyNightModeDirectly()
|
||||
}
|
||||
}
|
||||
|
||||
if (rounded !== temp) {
|
||||
@@ -770,4 +980,4 @@ Singleton {
|
||||
|
||||
target: "night"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,505 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool automationAvailable: false
|
||||
property bool locationProviderAvailable: false
|
||||
property var availableProviders: []
|
||||
property string currentProvider: ""
|
||||
property bool isAutomaticNightTime: false
|
||||
property string currentLocation: ""
|
||||
property real latitude: 0.0
|
||||
property real longitude: 0.0
|
||||
|
||||
function testGeoclueConnection() {
|
||||
geoclueTestProcess.running = false
|
||||
geoclueTestProcess.command = [
|
||||
"timeout", "32",
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-O", "6500",
|
||||
"-v"
|
||||
]
|
||||
geoclueTestProcess.running = true
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
checkAvailability()
|
||||
updateFromSessionData()
|
||||
|
||||
if (typeof globalThis !== 'undefined') {
|
||||
globalThis.testNightMode = manualNightModeTest
|
||||
globalThis.resetNightMode = manualResetTest
|
||||
globalThis.clearNightModeLocation = clearLocation
|
||||
globalThis.nightModeService = root
|
||||
}
|
||||
}
|
||||
|
||||
function checkAvailability() {
|
||||
gammaStepTestProcess.running = true
|
||||
}
|
||||
|
||||
function startAutomation() {
|
||||
if (!automationAvailable) {
|
||||
console.warn("NightModeAutomationService: Gammastep not available")
|
||||
return
|
||||
}
|
||||
|
||||
// Stop any existing automation processes first
|
||||
stopAutomation()
|
||||
|
||||
const mode = SessionData.nightModeAutoMode || "manual"
|
||||
|
||||
switch (mode) {
|
||||
case "time":
|
||||
startTimeBasedMode()
|
||||
break
|
||||
case "location":
|
||||
startLocationBasedMode()
|
||||
break
|
||||
case "manual":
|
||||
default:
|
||||
stopAutomation()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function stopAutomation() {
|
||||
|
||||
// Stop the unified process
|
||||
gammaStepProcess.running = false
|
||||
|
||||
isAutomaticNightTime = false
|
||||
}
|
||||
|
||||
function startTimeBasedMode() {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
|
||||
function startLocationBasedMode() {
|
||||
gammaStepProcess.running = false
|
||||
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
|
||||
if (latitude !== 0.0 && longitude !== 0.0) {
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-l", `${latitude.toFixed(6)}:${longitude.toFixed(6)}`,
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
return
|
||||
}
|
||||
|
||||
// Check if location providers are available
|
||||
if (!locationProviderAvailable) {
|
||||
console.warn("NightModeAutomationService: No location provider available, falling back to time-based mode")
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
return
|
||||
}
|
||||
|
||||
if (currentProvider === "geoclue2") {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
return
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: No working location provider, falling back to time-based mode")
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function checkTimeBasedMode() {
|
||||
if (!SessionData.nightModeAutoEnabled || SessionData.nightModeAutoMode !== "time") {
|
||||
return
|
||||
}
|
||||
|
||||
const now = new Date()
|
||||
const currentHour = now.getHours()
|
||||
const currentMinute = now.getMinutes()
|
||||
const currentTime = currentHour * 60 + currentMinute
|
||||
|
||||
const startTime = SessionData.nightModeStartTime || "20:00"
|
||||
const endTime = SessionData.nightModeEndTime || "06:00"
|
||||
|
||||
const startParts = startTime.split(":")
|
||||
const endParts = endTime.split(":")
|
||||
|
||||
const startMinutes = parseInt(startParts[0]) * 60 + parseInt(startParts[1])
|
||||
const endMinutes = parseInt(endParts[0]) * 60 + parseInt(endParts[1])
|
||||
|
||||
let shouldBeNight = false
|
||||
|
||||
if (startMinutes > endMinutes) {
|
||||
shouldBeNight = (currentTime >= startMinutes) || (currentTime < endMinutes)
|
||||
} else {
|
||||
shouldBeNight = (currentTime >= startMinutes) && (currentTime < endMinutes)
|
||||
}
|
||||
|
||||
if (shouldBeNight !== isAutomaticNightTime) {
|
||||
isAutomaticNightTime = shouldBeNight
|
||||
|
||||
if (shouldBeNight) {
|
||||
requestNightModeActivation()
|
||||
} else {
|
||||
requestNightModeDeactivation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function requestNightModeActivation() {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
|
||||
gammaStepProcess.running = false
|
||||
gammaStepProcess.processType = "activate"
|
||||
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-O", String(temperature)
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode !== "manual") {
|
||||
SessionData.setNightModeEnabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
function requestNightModeDeactivation() {
|
||||
gammaStepProcess.running = false
|
||||
|
||||
gammaStepProcess.processType = "reset"
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-O", "6500"
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode !== "manual") {
|
||||
SessionData.setNightModeEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
function setLocation(lat, lon) {
|
||||
latitude = lat
|
||||
longitude = lon
|
||||
currentLocation = `${lat.toFixed(6)},${lon.toFixed(6)}`
|
||||
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
startLocationBasedMode()
|
||||
}
|
||||
}
|
||||
|
||||
function clearLocation() {
|
||||
latitude = 0.0
|
||||
longitude = 0.0
|
||||
currentLocation = ""
|
||||
|
||||
SessionData.setLatitude(0.0)
|
||||
SessionData.setLongitude(0.0)
|
||||
SessionData.saveSettings()
|
||||
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
startLocationBasedMode()
|
||||
}
|
||||
}
|
||||
|
||||
function buildGammastepCommand(gammastepArgs) {
|
||||
const commandStr = "pkill gammastep; " + ["gammastep"].concat(gammastepArgs).join(" ")
|
||||
return ["sh", "-c", commandStr]
|
||||
}
|
||||
|
||||
|
||||
function updateFromSessionData() {
|
||||
if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
setLocation(SessionData.latitude, SessionData.longitude)
|
||||
} else {
|
||||
latitude = 0.0
|
||||
longitude = 0.0
|
||||
currentLocation = ""
|
||||
}
|
||||
}
|
||||
|
||||
function detectLocationProviders() {
|
||||
locationProviderDetectionProcess.running = true
|
||||
}
|
||||
|
||||
|
||||
function manualNightModeTest() {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
|
||||
gammaStepProcess.running = false
|
||||
gammaStepProcess.processType = "test"
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-O", String(temperature)
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
|
||||
testFeedbackTimer.interval = 2000
|
||||
testFeedbackTimer.feedbackMessage = "Night mode test applied"
|
||||
testFeedbackTimer.start()
|
||||
}
|
||||
|
||||
function manualResetTest() {
|
||||
gammaStepProcess.running = false
|
||||
gammaStepProcess.processType = "test"
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-O", "6500"
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
|
||||
testFeedbackTimer.interval = 2000
|
||||
testFeedbackTimer.feedbackMessage = "Screen reset to normal temperature"
|
||||
testFeedbackTimer.start()
|
||||
}
|
||||
|
||||
SystemClock {
|
||||
id: systemClock
|
||||
precision: SystemClock.Minutes
|
||||
onDateChanged: {
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepTestProcess
|
||||
command: ["which", "gammastep"]
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
automationAvailable = (exitCode === 0)
|
||||
if (automationAvailable) {
|
||||
detectLocationProviders()
|
||||
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: locationProviderDetectionProcess
|
||||
command: ["gammastep", "-l", "list"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim()) {
|
||||
// Parse provider names - they start with whitespace and are single words
|
||||
const lines = text.trim().split('\n')
|
||||
const providers = lines.filter(line => {
|
||||
const trimmed = line.trim()
|
||||
// Provider names are single words that start with whitespace in original line
|
||||
return line.startsWith(' ') &&
|
||||
trimmed.length > 0 &&
|
||||
!trimmed.includes(' ') &&
|
||||
!trimmed.includes(':') &&
|
||||
!trimmed.includes('.')
|
||||
}).map(line => line.trim())
|
||||
|
||||
availableProviders = providers
|
||||
locationProviderAvailable = providers.length > 0
|
||||
|
||||
if (locationProviderAvailable && !currentProvider) {
|
||||
currentProvider = providers[0]
|
||||
}
|
||||
|
||||
// Providers detected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
locationProviderAvailable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: geoclueTestProcess
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (exitCode === 0) {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
gammaStepProcess.command = buildGammastepCommand([
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
])
|
||||
gammaStepProcess.running = true
|
||||
} else {
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepProcess
|
||||
running: false
|
||||
|
||||
property string processType: "" // "automation", "activate", "reset", "test"
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {}
|
||||
}
|
||||
|
||||
onRunningChanged: {
|
||||
if (running) {
|
||||
// Start timeout only for test commands - automation, activate, and reset should not timeout
|
||||
if (processType === "test") {
|
||||
processTimeoutTimer.start()
|
||||
}
|
||||
} else {
|
||||
// Stop timeout when process ends
|
||||
processTimeoutTimer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
onExited: function(exitCode) {
|
||||
processTimeoutTimer.stop()
|
||||
|
||||
const isSuccessfulCompletion = (exitCode === 0) ||
|
||||
((processType === "activate" || processType === "reset") && exitCode === 15)
|
||||
|
||||
if (!isSuccessfulCompletion) {
|
||||
switch(processType) {
|
||||
case "automation":
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
if (exitCode === 15 || exitCode === 124) {
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
} else {
|
||||
restartTimer.start()
|
||||
}
|
||||
} else if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
restartTimer.start()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: processTimeoutTimer
|
||||
interval: 30000 // 30 second timeout (increased from 10s for one-shot commands)
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (gammaStepProcess.running) {
|
||||
console.warn("NightModeAutomationService: Test process timed out, killing process")
|
||||
// Only kill test processes that have timed out
|
||||
if (gammaStepProcess.processType === "test") {
|
||||
gammaStepProcess.running = false
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: Non-test process still running after timeout, but not killing")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: restartTimer
|
||||
interval: 10000
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
startLocationBasedMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: testFeedbackTimer
|
||||
interval: 2000
|
||||
running: false
|
||||
repeat: false
|
||||
property string feedbackMessage: ""
|
||||
onTriggered: {
|
||||
if (feedbackMessage.length > 0) {
|
||||
console.log(feedbackMessage)
|
||||
feedbackMessage = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
console.log("NightModeAutomationService: Auto enabled changed to", SessionData.nightModeAutoEnabled)
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
} else {
|
||||
stopAutomation()
|
||||
}
|
||||
}
|
||||
function onNightModeAutoModeChanged() {
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
}
|
||||
}
|
||||
function onNightModeStartTimeChanged() {
|
||||
console.log("NightModeAutomationService: Start time changed to", SessionData.nightModeStartTime)
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
}
|
||||
function onNightModeEndTimeChanged() {
|
||||
console.log("NightModeAutomationService: End time changed to", SessionData.nightModeEndTime)
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
}
|
||||
function onNightModeTemperatureChanged() {
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
startAutomation()
|
||||
}
|
||||
}
|
||||
function onLatitudeChanged() {
|
||||
updateFromSessionData()
|
||||
}
|
||||
function onLongitudeChanged() {
|
||||
updateFromSessionData()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user