mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 07:22: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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user