From 2ae911230db57f94bb7f2087638465bad4c52a74 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sun, 23 Nov 2025 17:29:56 -0500 Subject: [PATCH] osd: try to optimize power profile osd more --- quickshell/DMSShell.qml | 10 +- quickshell/Modules/OSD/PowerProfileOSD.qml | 13 +- quickshell/Services/BatteryService.qml | 188 +++++++++++++-------- 3 files changed, 127 insertions(+), 84 deletions(-) diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index b0b0ce74..ca9d4720 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -558,7 +558,7 @@ Item { LazyLoader { id: powerProfileOSDLoader - active: SettingsData.osdPowerProfileEnabled + active: false Variants { model: SettingsData.getFilteredScreens("osd") @@ -569,6 +569,14 @@ Item { } } + Connections { + target: BatteryService + + function onPowerProfileChanged() { + powerProfileOSDLoader.active = true + } + } + Variants { model: SettingsData.getFilteredScreens("osd") diff --git a/quickshell/Modules/OSD/PowerProfileOSD.qml b/quickshell/Modules/OSD/PowerProfileOSD.qml index a7f4a311..f8a7695f 100644 --- a/quickshell/Modules/OSD/PowerProfileOSD.qml +++ b/quickshell/Modules/OSD/PowerProfileOSD.qml @@ -12,22 +12,19 @@ DankOSD { autoHideInterval: 2000 enableMouseInteraction: false - property int lastProfile: -1 - Connections { - target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null + target: BatteryService - function onProfileChanged() { - if (lastProfile !== -1 && lastProfile !== PowerProfiles.profile && SettingsData.osdPowerProfileEnabled) { + function onPowerProfileChanged() { + if (SettingsData.osdPowerProfileEnabled) { root.show() } - lastProfile = PowerProfiles.profile } } Component.onCompleted: { - if (typeof PowerProfiles !== "undefined") { - lastProfile = PowerProfiles.profile + if (SettingsData.osdPowerProfileEnabled) { + root.show() } } diff --git a/quickshell/Services/BatteryService.qml b/quickshell/Services/BatteryService.qml index 6a94a1f0..2d6355d6 100644 --- a/quickshell/Services/BatteryService.qml +++ b/quickshell/Services/BatteryService.qml @@ -1,10 +1,8 @@ pragma Singleton - pragma ComponentBehavior: Bound import QtQuick import Quickshell -import Quickshell.Io import Quickshell.Services.UPower import qs.Common @@ -13,6 +11,10 @@ Singleton { property bool suppressSound: true property bool previousPluggedState: false + property int currentPowerProfile: -1 + property int previousPowerProfile: -1 + + signal powerProfileChanged Timer { id: startupTimer @@ -22,6 +24,27 @@ Singleton { onTriggered: root.suppressSound = false } + Connections { + target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null + + function onProfileChanged() { + if (typeof PowerProfiles !== "undefined") { + root.previousPowerProfile = root.currentPowerProfile; + root.currentPowerProfile = PowerProfiles.profile; + if (root.previousPowerProfile !== -1) { + root.powerProfileChanged(); + } + } + } + } + + Component.onCompleted: { + if (typeof PowerProfiles !== "undefined") { + root.currentPowerProfile = PowerProfiles.profile; + root.previousPowerProfile = PowerProfiles.profile; + } + } + readonly property string preferredBatteryOverride: Quickshell.env("DMS_PREFERRED_BATTERY") // List of laptop batteries @@ -31,25 +54,28 @@ Singleton { // Main battery (for backward compatibility) readonly property UPowerDevice device: { - var preferredDev + var preferredDev; if (usePreferred) { - preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase())) + preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase())); } - return preferredDev || batteries[0] || null + return preferredDev || batteries[0] || null; } // Whether at least one battery is available readonly property bool batteryAvailable: batteries.length > 0 // Aggregated charge level (percentage) readonly property real batteryLevel: { - if (!batteryAvailable) return 0 + if (!batteryAvailable) + return 0; if (batteryCapacity === 0) { - if (usePreferred && device && device.ready) return Math.round(device.percentage * 100) - const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0) - if (validBatteries.length === 0) return 0 - const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length - return Math.round(avgPercentage * 100) + if (usePreferred && device && device.ready) + return Math.round(device.percentage * 100); + const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0); + if (validBatteries.length === 0) + return 0; + const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length; + return Math.round(avgPercentage * 100); } - return Math.round((batteryEnergy * 100) / batteryCapacity) + return Math.round((batteryEnergy * 100) / batteryCapacity); } readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging) @@ -59,170 +85,182 @@ Singleton { onIsPluggedInChanged: { if (suppressSound || !batteryAvailable) { - previousPluggedState = isPluggedIn - return + previousPluggedState = isPluggedIn; + return; } if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) { if (isPluggedIn && !previousPluggedState) { - AudioService.playPowerPlugSound() + AudioService.playPowerPlugSound(); } else if (!isPluggedIn && previousPluggedState) { - AudioService.playPowerUnplugSound() + AudioService.playPowerUnplugSound(); } } - previousPluggedState = isPluggedIn + previousPluggedState = isPluggedIn; } // Aggregated charge/discharge rate readonly property real changeRate: { - if (!batteryAvailable) return 0 - if (usePreferred && device && device.ready) return device.changeRate - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0 + if (!batteryAvailable) + return 0; + if (usePreferred && device && device.ready) + return device.changeRate; + return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0; } // Aggregated battery health readonly property string batteryHealth: { - if (!batteryAvailable) return "N/A" + if (!batteryAvailable) + return "N/A"; // If a preferred battery is selected and ready - if (usePreferred && device && device.ready && device.healthSupported) return `${Math.round(device.healthPercentage)}%` + if (usePreferred && device && device.ready && device.healthSupported) + return `${Math.round(device.healthPercentage)}%`; // Otherwise, calculate the average health of all laptop batteries - const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0) - if (validBatteries.length === 0) return "N/A" + const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0); + if (validBatteries.length === 0) + return "N/A"; - const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length - return `${Math.round(avgHealth)}%` + const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length; + return `${Math.round(avgHealth)}%`; } readonly property real batteryEnergy: { - if (!batteryAvailable) return 0 - if (usePreferred && device && device.ready) return device.energy - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0 + if (!batteryAvailable) + return 0; + if (usePreferred && device && device.ready) + return device.energy; + return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0; } // Total battery capacity (Wh) readonly property real batteryCapacity: { - if (!batteryAvailable) return 0 - if (usePreferred && device && device.ready) return device.energyCapacity - return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0 + if (!batteryAvailable) + return 0; + if (usePreferred && device && device.ready) + return device.energyCapacity; + return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0; } // Aggregated battery status readonly property string batteryStatus: { if (!batteryAvailable) { - return "No Battery" + return "No Battery"; } - if (isCharging && !batteries.some(b => b.changeRate > 0)) return "Plugged In" + if (isCharging && !batteries.some(b => b.changeRate > 0)) + return "Plugged In"; - const states = batteries.map(b => b.state) - if (states.every(s => s === states[0])) return UPowerDeviceState.toString(states[0]) + const states = batteries.map(b => b.state); + if (states.every(s => s === states[0])) + return UPowerDeviceState.toString(states[0]); - return isCharging ? "Charging" : (isPluggedIn ? "Plugged In" : "Discharging") + return isCharging ? "Charging" : (isPluggedIn ? "Plugged In" : "Discharging"); } readonly property bool suggestPowerSaver: batteryAvailable && isLowBattery && UPower.onBattery && (typeof PowerProfiles !== "undefined" && PowerProfiles.profile !== PowerProfile.PowerSaver) readonly property var bluetoothDevices: { - const btDevices = [] - const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers] + const btDevices = []; + const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers]; for (var i = 0; i < UPower.devices.count; i++) { - const dev = UPower.devices.get(i) + const dev = UPower.devices.get(i); if (dev && dev.ready && bluetoothTypes.includes(dev.type)) { btDevices.push({ - "name": dev.model || UPowerDeviceType.toString(dev.type), - "percentage": Math.round(dev.percentage * 100), - "type": dev.type - }) + "name": dev.model || UPowerDeviceType.toString(dev.type), + "percentage": Math.round(dev.percentage * 100), + "type": dev.type + }); } } - return btDevices + return btDevices; } // Format time remaining for charge/discharge function formatTimeRemaining() { if (!batteryAvailable) { - return "Unknown" + return "Unknown"; } - let totalTime = 0 - totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate) - const avgTime = Math.abs(totalTime * 3600) - if (!avgTime || avgTime <= 0 || avgTime > 86400) return "Unknown" + let totalTime = 0; + totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate); + const avgTime = Math.abs(totalTime * 3600); + if (!avgTime || avgTime <= 0 || avgTime > 86400) + return "Unknown"; - const hours = Math.floor(avgTime / 3600) - const minutes = Math.floor((avgTime % 3600) / 60) - return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m` + const hours = Math.floor(avgTime / 3600); + const minutes = Math.floor((avgTime % 3600) / 60); + return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`; } function getBatteryIcon() { if (!batteryAvailable) { - return "power" + return "power"; } if (isCharging) { if (batteryLevel >= 90) { - return "battery_charging_full" + return "battery_charging_full"; } if (batteryLevel >= 80) { - return "battery_charging_90" + return "battery_charging_90"; } if (batteryLevel >= 60) { - return "battery_charging_80" + return "battery_charging_80"; } if (batteryLevel >= 50) { - return "battery_charging_60" + return "battery_charging_60"; } if (batteryLevel >= 30) { - return "battery_charging_50" + return "battery_charging_50"; } if (batteryLevel >= 20) { - return "battery_charging_30" + return "battery_charging_30"; } - return "battery_charging_20" + return "battery_charging_20"; } if (isPluggedIn) { if (batteryLevel >= 90) { - return "battery_charging_full" + return "battery_charging_full"; } if (batteryLevel >= 80) { - return "battery_charging_90" + return "battery_charging_90"; } if (batteryLevel >= 60) { - return "battery_charging_80" + return "battery_charging_80"; } if (batteryLevel >= 50) { - return "battery_charging_60" + return "battery_charging_60"; } if (batteryLevel >= 30) { - return "battery_charging_50" + return "battery_charging_50"; } if (batteryLevel >= 20) { - return "battery_charging_30" + return "battery_charging_30"; } - return "battery_charging_20" + return "battery_charging_20"; } if (batteryLevel >= 95) { - return "battery_full" + return "battery_full"; } if (batteryLevel >= 85) { - return "battery_6_bar" + return "battery_6_bar"; } if (batteryLevel >= 70) { - return "battery_5_bar" + return "battery_5_bar"; } if (batteryLevel >= 55) { - return "battery_4_bar" + return "battery_4_bar"; } if (batteryLevel >= 40) { - return "battery_3_bar" + return "battery_3_bar"; } if (batteryLevel >= 25) { - return "battery_2_bar" + return "battery_2_bar"; } - return "battery_1_bar" + return "battery_1_bar"; } }