mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 23:42:51 -05:00
brightness: remove brightnessctl + ddcutil dependencies
- Switches to DMS API v13+ dependency
This commit is contained in:
@@ -47,6 +47,16 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const backlight = DisplayService.devices.find(d => d.class === "backlight")
|
||||||
|
if (backlight) {
|
||||||
|
return backlight.name
|
||||||
|
}
|
||||||
|
|
||||||
|
const ddc = DisplayService.devices.find(d => d.class === "ddc")
|
||||||
|
if (ddc) {
|
||||||
|
return ddc.name
|
||||||
|
}
|
||||||
|
|
||||||
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
|
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,8 +234,10 @@ Rectangle {
|
|||||||
|
|
||||||
if (deviceClass === "backlight" || deviceClass === "ddc") {
|
if (deviceClass === "backlight" || deviceClass === "ddc") {
|
||||||
const brightness = DisplayService.getDeviceBrightness(modelData.name)
|
const brightness = DisplayService.getDeviceBrightness(modelData.name)
|
||||||
if (brightness <= 33) return "brightness_low"
|
if (brightness <= 33)
|
||||||
if (brightness <= 66) return "brightness_medium"
|
return "brightness_low"
|
||||||
|
if (brightness <= 66)
|
||||||
|
return "brightness_medium"
|
||||||
return "brightness_high"
|
return "brightness_high"
|
||||||
} else if (deviceName.includes("kbd")) {
|
} else if (deviceName.includes("kbd")) {
|
||||||
return "keyboard"
|
return "keyboard"
|
||||||
@@ -277,9 +289,12 @@ Rectangle {
|
|||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
const deviceClass = modelData.class || ""
|
const deviceClass = modelData.class || ""
|
||||||
if (deviceClass === "backlight") return "Backlight device"
|
if (deviceClass === "backlight")
|
||||||
if (deviceClass === "ddc") return "DDC/CI monitor"
|
return "Backlight device"
|
||||||
if (deviceClass === "leds") return "LED device"
|
if (deviceClass === "ddc")
|
||||||
|
return "DDC/CI monitor"
|
||||||
|
if (deviceClass === "leds")
|
||||||
|
return "LED device"
|
||||||
return deviceClass
|
return deviceClass
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
@@ -299,7 +314,6 @@ Rectangle {
|
|||||||
deviceNameChanged(modelData.name)
|
deviceNameChanged(modelData.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Row {
|
|||||||
property string screenName: ""
|
property string screenName: ""
|
||||||
property var parentScreen: null
|
property var parentScreen: null
|
||||||
|
|
||||||
signal iconClicked()
|
signal iconClicked
|
||||||
|
|
||||||
height: 40
|
height: 40
|
||||||
spacing: 0
|
spacing: 0
|
||||||
@@ -36,13 +36,27 @@ Row {
|
|||||||
|
|
||||||
if (deviceName && deviceName.length > 0) {
|
if (deviceName && deviceName.length > 0) {
|
||||||
const found = DisplayService.devices.find(dev => dev.name === deviceName)
|
const found = DisplayService.devices.find(dev => dev.name === deviceName)
|
||||||
return found ? found.name : ""
|
if (found) {
|
||||||
|
return found.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentDeviceName = DisplayService.currentDevice
|
const currentDeviceName = DisplayService.currentDevice
|
||||||
if (currentDeviceName) {
|
if (currentDeviceName) {
|
||||||
const found = DisplayService.devices.find(dev => dev.name === currentDeviceName)
|
const found = DisplayService.devices.find(dev => dev.name === currentDeviceName)
|
||||||
return found ? found.name : ""
|
if (found) {
|
||||||
|
return found.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const backlight = DisplayService.devices.find(d => d.class === "backlight")
|
||||||
|
if (backlight) {
|
||||||
|
return backlight.name
|
||||||
|
}
|
||||||
|
|
||||||
|
const ddc = DisplayService.devices.find(d => d.class === "ddc")
|
||||||
|
if (ddc) {
|
||||||
|
return ddc.name
|
||||||
}
|
}
|
||||||
|
|
||||||
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
|
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
|
||||||
@@ -69,9 +83,7 @@ Row {
|
|||||||
height: Theme.iconSize + Theme.spacingS * 2
|
height: Theme.iconSize + Theme.spacingS * 2
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||||
color: iconArea.containsMouse
|
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||||
? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
|
||||||
: Theme.withAlpha(Theme.primary, 0)
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: iconArea
|
id: iconArea
|
||||||
@@ -112,8 +124,10 @@ Row {
|
|||||||
|
|
||||||
if (targetDevice.class === "backlight" || targetDevice.class === "ddc") {
|
if (targetDevice.class === "backlight" || targetDevice.class === "ddc") {
|
||||||
const brightness = targetBrightness
|
const brightness = targetBrightness
|
||||||
if (brightness <= 33) return "brightness_low"
|
if (brightness <= 33)
|
||||||
if (brightness <= 66) return "brightness_medium"
|
return "brightness_low"
|
||||||
|
if (brightness <= 66)
|
||||||
|
return "brightness_medium"
|
||||||
return "brightness_high"
|
return "brightness_high"
|
||||||
} else if (targetDevice.name.includes("kbd")) {
|
} else if (targetDevice.name.includes("kbd")) {
|
||||||
return "keyboard"
|
return "keyboard"
|
||||||
@@ -134,7 +148,7 @@ Row {
|
|||||||
minimum: 1
|
minimum: 1
|
||||||
maximum: 100
|
maximum: 100
|
||||||
value: targetBrightness
|
value: targetBrightness
|
||||||
onSliderValueChanged: function(newValue) {
|
onSliderValueChanged: function (newValue) {
|
||||||
if (DisplayService.brightnessAvailable && targetDeviceName) {
|
if (DisplayService.brightnessAvailable && targetDeviceName) {
|
||||||
DisplayService.setBrightness(newValue, targetDeviceName, true)
|
DisplayService.setBrightness(newValue, targetDeviceName, true)
|
||||||
}
|
}
|
||||||
@@ -148,4 +162,4 @@ Row {
|
|||||||
active: false
|
active: false
|
||||||
sourceComponent: DankTooltip {}
|
sourceComponent: DankTooltip {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -34,16 +34,17 @@ Singleton {
|
|||||||
signal searchResultsReceived(var plugins)
|
signal searchResultsReceived(var plugins)
|
||||||
signal operationSuccess(string message)
|
signal operationSuccess(string message)
|
||||||
signal operationError(string error)
|
signal operationError(string error)
|
||||||
signal connectionStateChanged()
|
signal connectionStateChanged
|
||||||
|
|
||||||
signal networkStateUpdate(var data)
|
signal networkStateUpdate(var data)
|
||||||
signal cupsStateUpdate(var data)
|
signal cupsStateUpdate(var data)
|
||||||
signal loginctlStateUpdate(var data)
|
signal loginctlStateUpdate(var data)
|
||||||
signal loginctlEvent(var event)
|
signal loginctlEvent(var event)
|
||||||
signal capabilitiesReceived()
|
signal capabilitiesReceived
|
||||||
signal credentialsRequest(var data)
|
signal credentialsRequest(var data)
|
||||||
signal bluetoothPairingRequest(var data)
|
signal bluetoothPairingRequest(var data)
|
||||||
signal dwlStateUpdate(var data)
|
signal dwlStateUpdate(var data)
|
||||||
|
signal brightnessStateUpdate(var data)
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (socketPath && socketPath.length > 0) {
|
if (socketPath && socketPath.length > 0) {
|
||||||
@@ -227,11 +228,7 @@ Singleton {
|
|||||||
if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
|
if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
|
||||||
if (!shownOutdatedError) {
|
if (!shownOutdatedError) {
|
||||||
console.error("DMSService: Server does not support subscribe method")
|
console.error("DMSService: Server does not support subscribe method")
|
||||||
ToastService.showError(
|
ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand)
|
||||||
I18n.tr("DMS out of date"),
|
|
||||||
I18n.tr("To update, run the following command:"),
|
|
||||||
updateCommand
|
|
||||||
)
|
|
||||||
shownOutdatedError = true
|
shownOutdatedError = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -272,6 +269,8 @@ Singleton {
|
|||||||
cupsStateUpdate(data)
|
cupsStateUpdate(data)
|
||||||
} else if (service === "dwl") {
|
} else if (service === "dwl") {
|
||||||
dwlStateUpdate(data)
|
dwlStateUpdate(data)
|
||||||
|
} else if (service === "brightness") {
|
||||||
|
brightnessStateUpdate(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +279,8 @@ Singleton {
|
|||||||
console.warn("DMSService.sendRequest: Not connected, method:", method)
|
console.warn("DMSService.sendRequest: Not connected, method:", method)
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback({
|
callback({
|
||||||
"error": "not connected to DMS socket"
|
"error": "not connected to DMS socket"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
@@ -12,14 +12,9 @@ Singleton {
|
|||||||
|
|
||||||
property bool brightnessAvailable: devices.length > 0
|
property bool brightnessAvailable: devices.length > 0
|
||||||
property var devices: []
|
property var devices: []
|
||||||
property var ddcDevices: []
|
|
||||||
property var deviceBrightness: ({})
|
property var deviceBrightness: ({})
|
||||||
property var ddcPendingInit: ({})
|
|
||||||
property string currentDevice: ""
|
property string currentDevice: ""
|
||||||
property string lastIpcDevice: ""
|
property string lastIpcDevice: ""
|
||||||
property bool ddcAvailable: false
|
|
||||||
property var ddcInitQueue: []
|
|
||||||
property bool skipDdcRead: false
|
|
||||||
property int brightnessLevel: {
|
property int brightnessLevel: {
|
||||||
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice)
|
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice)
|
||||||
if (!deviceToUse) {
|
if (!deviceToUse) {
|
||||||
@@ -40,36 +35,75 @@ Singleton {
|
|||||||
property bool automationAvailable: false
|
property bool automationAvailable: false
|
||||||
property bool gammaControlAvailable: false
|
property bool gammaControlAvailable: false
|
||||||
|
|
||||||
function setBrightnessInternal(percentage, device) {
|
function updateFromBrightnessState(state) {
|
||||||
const clampedValue = Math.max(1, Math.min(100, percentage))
|
if (!state || !state.devices) {
|
||||||
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice())
|
return
|
||||||
|
|
||||||
if (actualDevice) {
|
|
||||||
const newBrightness = Object.assign({}, deviceBrightness)
|
|
||||||
newBrightness[actualDevice] = clampedValue
|
|
||||||
deviceBrightness = newBrightness
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceInfo = getCurrentDeviceInfoByName(actualDevice)
|
devices = state.devices.map(d => ({
|
||||||
|
"id": d.id,
|
||||||
|
"name": d.id,
|
||||||
|
"class": d.class,
|
||||||
|
"current": d.current,
|
||||||
|
"percentage": d.currentPercent,
|
||||||
|
"max": d.max,
|
||||||
|
"backend": d.backend
|
||||||
|
}))
|
||||||
|
|
||||||
if (deviceInfo && deviceInfo.class === "ddc") {
|
const newBrightness = {}
|
||||||
ddcBrightnessSetProcess.command = ["ddcutil", "setvcp", "-d", String(deviceInfo.ddcDisplay), "10", String(clampedValue)]
|
for (const device of state.devices) {
|
||||||
ddcBrightnessSetProcess.running = true
|
newBrightness[device.id] = device.currentPercent
|
||||||
} else {
|
}
|
||||||
if (device) {
|
deviceBrightness = newBrightness
|
||||||
brightnessSetProcess.command = ["brightnessctl", "-d", device, "set", `${clampedValue}%`]
|
|
||||||
|
brightnessAvailable = devices.length > 0
|
||||||
|
|
||||||
|
if (devices.length > 0 && !currentDevice) {
|
||||||
|
const lastDevice = SessionData.lastBrightnessDevice || ""
|
||||||
|
const deviceExists = devices.some(d => d.id === lastDevice)
|
||||||
|
if (deviceExists) {
|
||||||
|
setCurrentDevice(lastDevice, false)
|
||||||
} else {
|
} else {
|
||||||
brightnessSetProcess.command = ["brightnessctl", "set", `${clampedValue}%`]
|
const backlight = devices.find(d => d.class === "backlight")
|
||||||
|
const nonKbdDevice = devices.find(d => !d.id.includes("kbd"))
|
||||||
|
const defaultDevice = backlight || nonKbdDevice || devices[0]
|
||||||
|
setCurrentDevice(defaultDevice.id, false)
|
||||||
}
|
}
|
||||||
brightnessSetProcess.running = true
|
}
|
||||||
|
|
||||||
|
if (!brightnessInitialized) {
|
||||||
|
brightnessInitialized = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBrightness(percentage, device, suppressOsd) {
|
function setBrightness(percentage, device, suppressOsd) {
|
||||||
setBrightnessInternal(percentage, device)
|
const clampedValue = Math.max(1, Math.min(100, percentage))
|
||||||
if (!suppressOsd) {
|
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice())
|
||||||
brightnessChanged()
|
|
||||||
|
if (!actualDevice) {
|
||||||
|
console.warn("DisplayService: No device selected for brightness change")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!DMSService.isConnected) {
|
||||||
|
console.warn("DisplayService: Not connected to DMS")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DMSService.sendRequest("brightness.setBrightness", {
|
||||||
|
"device": actualDevice,
|
||||||
|
"percent": clampedValue
|
||||||
|
}, response => {
|
||||||
|
if (response.error) {
|
||||||
|
console.error("DisplayService: Failed to set brightness:", response.error)
|
||||||
|
ToastService.showError("Failed to set brightness: " + response.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!suppressOsd) {
|
||||||
|
brightnessChanged()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCurrentDevice(deviceName, saveToSession = false) {
|
function setCurrentDevice(deviceName, saveToSession = false) {
|
||||||
@@ -85,79 +119,27 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deviceSwitched()
|
deviceSwitched()
|
||||||
|
|
||||||
const deviceInfo = getCurrentDeviceInfoByName(deviceName)
|
|
||||||
if (deviceInfo && deviceInfo.class === "ddc") {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
brightnessGetProcess.command = ["brightnessctl", "-m", "-d", deviceName, "get"]
|
|
||||||
brightnessGetProcess.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshDevices() {
|
|
||||||
deviceListProcess.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshDevicesInternal() {
|
|
||||||
const allDevices = [...devices, ...ddcDevices]
|
|
||||||
|
|
||||||
allDevices.sort((a, b) => {
|
|
||||||
if (a.class === "backlight" && b.class !== "backlight") {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if (a.class !== "backlight" && b.class === "backlight") {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.class === "ddc" && b.class !== "ddc" && b.class !== "backlight") {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if (a.class !== "ddc" && b.class === "ddc" && a.class !== "backlight") {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.name.localeCompare(b.name)
|
|
||||||
})
|
|
||||||
|
|
||||||
devices = allDevices
|
|
||||||
|
|
||||||
if (devices.length > 0 && !currentDevice) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeviceBrightness(deviceName) {
|
function getDeviceBrightness(deviceName) {
|
||||||
if (!deviceName) {
|
if (!deviceName) {
|
||||||
return
|
|
||||||
} 50
|
|
||||||
|
|
||||||
const deviceInfo = getCurrentDeviceInfoByName(deviceName)
|
|
||||||
if (!deviceInfo) {
|
|
||||||
return 50
|
return 50
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceInfo.class === "ddc") {
|
if (deviceName in deviceBrightness) {
|
||||||
return deviceBrightness[deviceName] || 50
|
return deviceBrightness[deviceName]
|
||||||
}
|
}
|
||||||
|
|
||||||
return deviceBrightness[deviceName] || deviceInfo.percentage || 50
|
return 50
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultDevice() {
|
function getDefaultDevice() {
|
||||||
for (const device of devices) {
|
for (const device of devices) {
|
||||||
if (device.class === "backlight") {
|
if (device.class === "backlight") {
|
||||||
return device.name
|
return device.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return devices.length > 0 ? devices[0].name : ""
|
return devices.length > 0 ? devices[0].id : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentDeviceInfo() {
|
function getCurrentDeviceInfo() {
|
||||||
@@ -167,7 +149,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const device of devices) {
|
for (const device of devices) {
|
||||||
if (device.name === deviceToUse) {
|
if (device.id === deviceToUse) {
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,15 +158,7 @@ Singleton {
|
|||||||
|
|
||||||
function isCurrentDeviceReady() {
|
function isCurrentDeviceReady() {
|
||||||
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice)
|
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice)
|
||||||
if (!deviceToUse) {
|
return deviceToUse !== ""
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ddcPendingInit[deviceToUse]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentDeviceInfoByName(deviceName) {
|
function getCurrentDeviceInfoByName(deviceName) {
|
||||||
@@ -193,23 +167,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const device of devices) {
|
for (const device of devices) {
|
||||||
if (device.name === deviceName) {
|
if (device.id === deviceName) {
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function processNextDdcInit() {
|
|
||||||
if (ddcInitQueue.length === 0 || ddcInitialBrightnessProcess.running) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const displayId = ddcInitQueue.shift()
|
|
||||||
ddcInitialBrightnessProcess.command = ["ddcutil", "getvcp", "-d", String(displayId), "10", "--brief"]
|
|
||||||
ddcInitialBrightnessProcess.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Night Mode Functions - Simplified
|
// Night Mode Functions - Simplified
|
||||||
function enableNightMode() {
|
function enableNightMode() {
|
||||||
if (!gammaControlAvailable) {
|
if (!gammaControlAvailable) {
|
||||||
@@ -221,22 +185,22 @@ Singleton {
|
|||||||
SessionData.setNightModeEnabled(true)
|
SessionData.setNightModeEnabled(true)
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to enable gamma control:", response.error)
|
console.error("DisplayService: Failed to enable gamma control:", response.error)
|
||||||
ToastService.showError("Failed to enable night mode: " + response.error)
|
ToastService.showError("Failed to enable night mode: " + response.error)
|
||||||
nightModeEnabled = false
|
nightModeEnabled = false
|
||||||
SessionData.setNightModeEnabled(false)
|
SessionData.setNightModeEnabled(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SessionData.nightModeAutoEnabled) {
|
if (SessionData.nightModeAutoEnabled) {
|
||||||
startAutomation()
|
startAutomation()
|
||||||
} else {
|
} else {
|
||||||
applyNightModeDirectly()
|
applyNightModeDirectly()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableNightMode() {
|
function disableNightMode() {
|
||||||
@@ -248,13 +212,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to disable gamma control:", response.error)
|
console.error("DisplayService: Failed to disable gamma control:", response.error)
|
||||||
ToastService.showError("Failed to disable night mode: " + response.error)
|
ToastService.showError("Failed to disable night mode: " + response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleNightMode() {
|
function toggleNightMode() {
|
||||||
@@ -269,32 +233,32 @@ Singleton {
|
|||||||
const temperature = SessionData.nightModeTemperature || 4000
|
const temperature = SessionData.nightModeTemperature || 4000
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
||||||
"sunrise": null,
|
"sunrise": null,
|
||||||
"sunset": null
|
"sunset": null
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to clear manual times:", response.error)
|
console.error("DisplayService: Failed to clear manual times:", response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||||
"use": false
|
"use": false
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to disable IP location:", response.error)
|
console.error("DisplayService: Failed to disable IP location:", response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
||||||
"temp": temperature
|
"temp": temperature
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to set temperature:", response.error)
|
console.error("DisplayService: Failed to set temperature:", response.error)
|
||||||
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function startAutomation() {
|
function startAutomation() {
|
||||||
@@ -326,34 +290,34 @@ Singleton {
|
|||||||
const sunset = `${String(sunsetHour).padStart(2, '0')}:${String(sunsetMinute).padStart(2, '0')}`
|
const sunset = `${String(sunsetHour).padStart(2, '0')}:${String(sunsetMinute).padStart(2, '0')}`
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||||
"use": false
|
"use": false
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to disable IP location:", response.error)
|
console.error("DisplayService: Failed to disable IP location:", response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
||||||
"low": temperature,
|
"low": temperature,
|
||||||
"high": highTemp
|
"high": highTemp
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to set temperature:", response.error)
|
console.error("DisplayService: Failed to set temperature:", response.error)
|
||||||
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
||||||
"sunrise": sunrise,
|
"sunrise": sunrise,
|
||||||
"sunset": sunset
|
"sunset": sunset
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to set manual times:", response.error)
|
console.error("DisplayService: Failed to set manual times:", response.error)
|
||||||
ToastService.showError("Failed to set night mode schedule: " + response.error)
|
ToastService.showError("Failed to set night mode schedule: " + response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function startLocationBasedMode() {
|
function startLocationBasedMode() {
|
||||||
@@ -361,57 +325,57 @@ Singleton {
|
|||||||
const highTemp = SessionData.nightModeHighTemperature || 6500
|
const highTemp = SessionData.nightModeHighTemperature || 6500
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
DMSService.sendRequest("wayland.gamma.setManualTimes", {
|
||||||
"sunrise": null,
|
"sunrise": null,
|
||||||
"sunset": null
|
"sunset": null
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to clear manual times:", response.error)
|
console.error("DisplayService: Failed to clear manual times:", response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
DMSService.sendRequest("wayland.gamma.setTemperature", {
|
||||||
"low": temperature,
|
"low": temperature,
|
||||||
"high": highTemp
|
"high": highTemp
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to set temperature:", response.error)
|
console.error("DisplayService: Failed to set temperature:", response.error)
|
||||||
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
ToastService.showError("Failed to set night mode temperature: " + response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SessionData.nightModeUseIPLocation) {
|
if (SessionData.nightModeUseIPLocation) {
|
||||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||||
"use": true
|
"use": true
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to enable IP location:", response.error)
|
console.error("DisplayService: Failed to enable IP location:", response.error)
|
||||||
ToastService.showError("Failed to enable IP location: " + response.error)
|
ToastService.showError("Failed to enable IP location: " + response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
} else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||||
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
DMSService.sendRequest("wayland.gamma.setUseIPLocation", {
|
||||||
"use": false
|
"use": false
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to disable IP location:", response.error)
|
console.error("DisplayService: Failed to disable IP location:", response.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.setLocation", {
|
DMSService.sendRequest("wayland.gamma.setLocation", {
|
||||||
"latitude": SessionData.latitude,
|
"latitude": SessionData.latitude,
|
||||||
"longitude": SessionData.longitude
|
"longitude": SessionData.longitude
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error("DisplayService: Failed to set location:", response.error)
|
console.error("DisplayService: Failed to set location:", response.error)
|
||||||
ToastService.showError("Failed to set night mode location: " + response.error)
|
ToastService.showError("Failed to set night mode location: " + response.error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.warn("DisplayService: Location mode selected but no coordinates set and IP location disabled")
|
console.warn("DisplayService: Location mode selected but no coordinates set and IP location disabled")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNightModeAutomationMode(mode) {
|
function setNightModeAutomationMode(mode) {
|
||||||
@@ -450,32 +414,32 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DMSService.sendRequest("wayland.gamma.getState", null, response => {
|
DMSService.sendRequest("wayland.gamma.getState", null, response => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
gammaControlAvailable = false
|
gammaControlAvailable = false
|
||||||
automationAvailable = false
|
automationAvailable = false
|
||||||
console.error("DisplayService: Gamma control not available:", response.error)
|
console.error("DisplayService: Gamma control not available:", response.error)
|
||||||
} else {
|
} else {
|
||||||
gammaControlAvailable = true
|
gammaControlAvailable = true
|
||||||
automationAvailable = true
|
automationAvailable = true
|
||||||
|
|
||||||
if (nightModeEnabled) {
|
if (nightModeEnabled) {
|
||||||
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
DMSService.sendRequest("wayland.gamma.setEnabled", {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, enableResponse => {
|
}, enableResponse => {
|
||||||
if (enableResponse.error) {
|
if (enableResponse.error) {
|
||||||
console.error("DisplayService: Failed to enable gamma control on startup:", enableResponse.error)
|
console.error("DisplayService: Failed to enable gamma control on startup:", enableResponse.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SessionData.nightModeAutoEnabled) {
|
if (SessionData.nightModeAutoEnabled) {
|
||||||
startAutomation()
|
startAutomation()
|
||||||
} else {
|
} else {
|
||||||
applyNightModeDirectly()
|
applyNightModeDirectly()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -495,274 +459,9 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
ddcDetectionProcess.running = true
|
|
||||||
refreshDevices()
|
|
||||||
nightModeEnabled = SessionData.nightModeEnabled
|
nightModeEnabled = SessionData.nightModeEnabled
|
||||||
}
|
if (DMSService.isConnected) {
|
||||||
|
checkGammaControlAvailability()
|
||||||
Process {
|
|
||||||
id: ddcDetectionProcess
|
|
||||||
|
|
||||||
command: ["which", "ddcutil"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
ddcAvailable = (exitCode === 0)
|
|
||||||
if (ddcAvailable) {
|
|
||||||
ddcDisplayDetectionProcess.running = true
|
|
||||||
} else {
|
|
||||||
console.info("DisplayService: ddcutil not available")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: ddcDisplayDetectionProcess
|
|
||||||
|
|
||||||
command: ["bash", "-c", "ddcutil detect --brief 2>/dev/null | grep '^Display [0-9]' | awk '{print \"{\\\"display\\\":\" $2 \",\\\"name\\\":\\\"ddc-\" $2 \"\\\",\\\"class\\\":\\\"ddc\\\"}\"}' | tr '\\n' ',' | sed 's/,$//' | sed 's/^/[/' | sed 's/$/]/' || echo '[]'"]
|
|
||||||
running: false
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (!text.trim()) {
|
|
||||||
ddcDevices = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const parsedDevices = JSON.parse(text.trim())
|
|
||||||
const newDdcDevices = []
|
|
||||||
|
|
||||||
for (const device of parsedDevices) {
|
|
||||||
if (device.display && device.class === "ddc") {
|
|
||||||
newDdcDevices.push({
|
|
||||||
"name": device.name,
|
|
||||||
"class": "ddc",
|
|
||||||
"current": 50,
|
|
||||||
"percentage": 50,
|
|
||||||
"max": 100,
|
|
||||||
"ddcDisplay": device.display
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ddcDevices = newDdcDevices
|
|
||||||
console.info("DisplayService: Found", ddcDevices.length, "DDC displays")
|
|
||||||
|
|
||||||
// Queue initial brightness readings for DDC devices
|
|
||||||
ddcInitQueue = []
|
|
||||||
for (const device of ddcDevices) {
|
|
||||||
ddcInitQueue.push(device.ddcDisplay)
|
|
||||||
// Mark DDC device as pending initialization
|
|
||||||
ddcPendingInit[device.name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start processing the queue
|
|
||||||
processNextDdcInit()
|
|
||||||
|
|
||||||
// Refresh device list to include DDC devices
|
|
||||||
refreshDevicesInternal()
|
|
||||||
|
|
||||||
// Retry setting last device now that DDC devices are available
|
|
||||||
const lastDevice = SessionData.lastBrightnessDevice || ""
|
|
||||||
if (lastDevice) {
|
|
||||||
const deviceExists = devices.some(d => d.name === lastDevice)
|
|
||||||
if (deviceExists && (!currentDevice || currentDevice !== lastDevice)) {
|
|
||||||
setCurrentDevice(lastDevice, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("DisplayService: Failed to parse DDC devices:", error)
|
|
||||||
ddcDevices = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to detect DDC displays:", exitCode)
|
|
||||||
ddcDevices = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: deviceListProcess
|
|
||||||
|
|
||||||
command: ["brightnessctl", "-m", "-l"]
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to list devices:", exitCode)
|
|
||||||
brightnessAvailable = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (!text.trim()) {
|
|
||||||
console.warn("DisplayService: No devices found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const lines = text.trim().split("\n")
|
|
||||||
const newDevices = []
|
|
||||||
for (const line of lines) {
|
|
||||||
const parts = line.split(",")
|
|
||||||
if (parts.length >= 5) {
|
|
||||||
newDevices.push({
|
|
||||||
"name": parts[0],
|
|
||||||
"class": parts[1],
|
|
||||||
"current": parseInt(parts[2]),
|
|
||||||
"percentage": parseInt(parts[3]),
|
|
||||||
"max": parseInt(parts[4])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Store brightnessctl devices separately
|
|
||||||
devices = newDevices
|
|
||||||
|
|
||||||
// Always refresh to combine with DDC devices and set up device selection
|
|
||||||
refreshDevicesInternal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: brightnessSetProcess
|
|
||||||
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to set brightness:", exitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: ddcBrightnessSetProcess
|
|
||||||
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to set DDC brightness:", exitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: ddcInitialBrightnessProcess
|
|
||||||
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to get initial DDC brightness:", exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
processNextDdcInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (!text.trim())
|
|
||||||
return
|
|
||||||
|
|
||||||
const parts = text.trim().split(" ")
|
|
||||||
if (parts.length >= 5) {
|
|
||||||
const current = parseInt(parts[3]) || 50
|
|
||||||
const max = parseInt(parts[4]) || 100
|
|
||||||
const brightness = Math.round((current / max) * 100)
|
|
||||||
|
|
||||||
const commandParts = ddcInitialBrightnessProcess.command
|
|
||||||
if (commandParts && commandParts.length >= 4) {
|
|
||||||
const displayId = commandParts[3]
|
|
||||||
const deviceName = "ddc-" + displayId
|
|
||||||
|
|
||||||
var newBrightness = Object.assign({}, deviceBrightness)
|
|
||||||
newBrightness[deviceName] = brightness
|
|
||||||
deviceBrightness = newBrightness
|
|
||||||
|
|
||||||
var newPending = Object.assign({}, ddcPendingInit)
|
|
||||||
delete newPending[deviceName]
|
|
||||||
ddcPendingInit = newPending
|
|
||||||
|
|
||||||
console.log("DisplayService: Initial DDC Device", deviceName, "brightness:", brightness + "%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: brightnessGetProcess
|
|
||||||
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to get brightness:", exitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (!text.trim())
|
|
||||||
return
|
|
||||||
|
|
||||||
const parts = text.trim().split(",")
|
|
||||||
if (parts.length >= 5) {
|
|
||||||
const current = parseInt(parts[2])
|
|
||||||
const max = parseInt(parts[4])
|
|
||||||
maxBrightness = max
|
|
||||||
const brightness = Math.round((current / max) * 100)
|
|
||||||
|
|
||||||
// Update the device brightness cache
|
|
||||||
if (currentDevice) {
|
|
||||||
var newBrightness = Object.assign({}, deviceBrightness)
|
|
||||||
newBrightness[currentDevice] = brightness
|
|
||||||
deviceBrightness = newBrightness
|
|
||||||
}
|
|
||||||
|
|
||||||
brightnessInitialized = true
|
|
||||||
console.log("DisplayService: Device", currentDevice, "brightness:", brightness + "%")
|
|
||||||
brightnessChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: ddcBrightnessGetProcess
|
|
||||||
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
console.warn("DisplayService: Failed to get DDC brightness:", exitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: {
|
|
||||||
if (!text.trim())
|
|
||||||
return
|
|
||||||
|
|
||||||
// Parse ddcutil getvcp output format: "VCP 10 C 50 100"
|
|
||||||
const parts = text.trim().split(" ")
|
|
||||||
if (parts.length >= 5) {
|
|
||||||
const current = parseInt(parts[3]) || 50
|
|
||||||
const max = parseInt(parts[4]) || 100
|
|
||||||
maxBrightness = max
|
|
||||||
const brightness = Math.round((current / max) * 100)
|
|
||||||
|
|
||||||
// Update the device brightness cache
|
|
||||||
if (currentDevice) {
|
|
||||||
var newBrightness = Object.assign({}, deviceBrightness)
|
|
||||||
newBrightness[currentDevice] = brightness
|
|
||||||
deviceBrightness = newBrightness
|
|
||||||
}
|
|
||||||
|
|
||||||
brightnessInitialized = true
|
|
||||||
console.log("DisplayService: DDC Device", currentDevice, "brightness:", brightness + "%")
|
|
||||||
brightnessChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -773,6 +472,7 @@ Singleton {
|
|||||||
if (DMSService.isConnected) {
|
if (DMSService.isConnected) {
|
||||||
checkGammaControlAvailability()
|
checkGammaControlAvailability()
|
||||||
} else {
|
} else {
|
||||||
|
brightnessAvailable = false
|
||||||
gammaControlAvailable = false
|
gammaControlAvailable = false
|
||||||
automationAvailable = false
|
automationAvailable = false
|
||||||
}
|
}
|
||||||
@@ -781,6 +481,10 @@ Singleton {
|
|||||||
function onCapabilitiesReceived() {
|
function onCapabilitiesReceived() {
|
||||||
checkGammaControlAvailability()
|
checkGammaControlAvailability()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onBrightnessStateUpdate(data) {
|
||||||
|
updateFromBrightnessState(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session Data Connections
|
// Session Data Connections
|
||||||
@@ -842,8 +546,7 @@ Singleton {
|
|||||||
const clampedValue = Math.max(1, Math.min(100, value))
|
const clampedValue = Math.max(1, Math.min(100, value))
|
||||||
const targetDevice = device || ""
|
const targetDevice = device || ""
|
||||||
|
|
||||||
// Ensure device exists if specified
|
if (targetDevice && !root.devices.some(d => d.id === targetDevice)) {
|
||||||
if (targetDevice && !root.devices.some(d => d.name === targetDevice)) {
|
|
||||||
return "Device not found: " + targetDevice
|
return "Device not found: " + targetDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,8 +571,7 @@ Singleton {
|
|||||||
const targetDevice = device || ""
|
const targetDevice = device || ""
|
||||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice
|
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice
|
||||||
|
|
||||||
// Ensure device exists
|
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
||||||
if (actualDevice && !root.devices.some(d => d.name === actualDevice)) {
|
|
||||||
return "Device not found: " + actualDevice
|
return "Device not found: " + actualDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,8 +600,7 @@ Singleton {
|
|||||||
const targetDevice = device || ""
|
const targetDevice = device || ""
|
||||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice
|
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice
|
||||||
|
|
||||||
// Ensure device exists
|
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
||||||
if (actualDevice && !root.devices.some(d => d.name === actualDevice)) {
|
|
||||||
return "Device not found: " + actualDevice
|
return "Device not found: " + actualDevice
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -935,7 +636,7 @@ Singleton {
|
|||||||
|
|
||||||
let result = "Available devices:\\n"
|
let result = "Available devices:\\n"
|
||||||
for (const device of root.devices) {
|
for (const device of root.devices) {
|
||||||
result += device.name + " (" + device.class + ")\\n"
|
result += device.id + " (" + device.class + ")\\n"
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import qs.Common
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property string shellDir: Paths.strip(Qt.resolvedUrl(".").toString()).replace("/Services/", "")
|
|
||||||
property string scriptPath: `${shellDir}/scripts/hyprland_keybinds.py`
|
|
||||||
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
||||||
readonly property string _configDir: Paths.strip(_configUrl)
|
readonly property string _configDir: Paths.strip(_configUrl)
|
||||||
property string hyprConfigPath: `${_configDir}/hypr`
|
property string hyprConfigPath: `${_configDir}/hypr`
|
||||||
@@ -20,7 +18,7 @@ Singleton {
|
|||||||
Process {
|
Process {
|
||||||
id: getKeybinds
|
id: getKeybinds
|
||||||
running: false
|
running: false
|
||||||
command: [root.scriptPath, "--path", root.hyprConfigPath]
|
command: ["dms", "hyprland", "keybinds", "--path", root.hyprConfigPath]
|
||||||
|
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: data => {
|
onRead: data => {
|
||||||
|
|||||||
@@ -1,237 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# Based on end-4 dots-hyprland get_keybinds.py
|
|
||||||
# https://github.com/end-4/dots-hyprland/blob/main/.config/quickshell/ii/scripts/hyprland/get_keybinds.py
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
from os.path import expandvars as os_expandvars
|
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
TITLE_REGEX = "#+!"
|
|
||||||
HIDE_COMMENT = "[hidden]"
|
|
||||||
MOD_SEPARATORS = ['+', ' ']
|
|
||||||
COMMENT_BIND_PATTERN = "#/#"
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Hyprland keybind reader')
|
|
||||||
parser.add_argument('--path', type=str, default="$HOME/.config/hypr", help='path to hyprland config directory')
|
|
||||||
args = parser.parse_args()
|
|
||||||
content_lines = []
|
|
||||||
reading_line = 0
|
|
||||||
|
|
||||||
Variables: Dict[str, str] = {}
|
|
||||||
|
|
||||||
|
|
||||||
class KeyBinding(dict):
|
|
||||||
def __init__(self, mods, key, dispatcher, params, comment) -> None:
|
|
||||||
self["mods"] = mods
|
|
||||||
self["key"] = key
|
|
||||||
self["dispatcher"] = dispatcher
|
|
||||||
self["params"] = params
|
|
||||||
self["comment"] = comment
|
|
||||||
|
|
||||||
class Section(dict):
|
|
||||||
def __init__(self, children, keybinds, name) -> None:
|
|
||||||
self["children"] = children
|
|
||||||
self["keybinds"] = keybinds
|
|
||||||
self["name"] = name
|
|
||||||
|
|
||||||
|
|
||||||
def read_content(directory: str) -> str:
|
|
||||||
expanded_dir = os.path.expanduser(os.path.expandvars(directory))
|
|
||||||
if not os.path.isdir(expanded_dir):
|
|
||||||
return "error"
|
|
||||||
|
|
||||||
conf_files = glob.glob(os.path.join(expanded_dir, "*.conf"))
|
|
||||||
if not conf_files:
|
|
||||||
return "error"
|
|
||||||
|
|
||||||
combined_content = []
|
|
||||||
for conf_file in sorted(conf_files):
|
|
||||||
if os.access(conf_file, os.R_OK):
|
|
||||||
with open(conf_file, "r") as file:
|
|
||||||
combined_content.append(file.read())
|
|
||||||
|
|
||||||
return "\n".join(combined_content) if combined_content else "error"
|
|
||||||
|
|
||||||
|
|
||||||
def autogenerate_comment(dispatcher: str, params: str = "") -> str:
|
|
||||||
match dispatcher:
|
|
||||||
|
|
||||||
case "resizewindow":
|
|
||||||
return "Resize window"
|
|
||||||
|
|
||||||
case "movewindow":
|
|
||||||
if(params == ""):
|
|
||||||
return "Move window"
|
|
||||||
else:
|
|
||||||
return "Window: move in {} direction".format({
|
|
||||||
"l": "left",
|
|
||||||
"r": "right",
|
|
||||||
"u": "up",
|
|
||||||
"d": "down",
|
|
||||||
}.get(params, "null"))
|
|
||||||
|
|
||||||
case "pin":
|
|
||||||
return "Window: pin (show on all workspaces)"
|
|
||||||
|
|
||||||
case "splitratio":
|
|
||||||
return "Window split ratio {}".format(params)
|
|
||||||
|
|
||||||
case "togglefloating":
|
|
||||||
return "Float/unfloat window"
|
|
||||||
|
|
||||||
case "resizeactive":
|
|
||||||
return "Resize window by {}".format(params)
|
|
||||||
|
|
||||||
case "killactive":
|
|
||||||
return "Close window"
|
|
||||||
|
|
||||||
case "fullscreen":
|
|
||||||
return "Toggle {}".format(
|
|
||||||
{
|
|
||||||
"0": "fullscreen",
|
|
||||||
"1": "maximization",
|
|
||||||
"2": "fullscreen on Hyprland's side",
|
|
||||||
}.get(params, "null")
|
|
||||||
)
|
|
||||||
|
|
||||||
case "fakefullscreen":
|
|
||||||
return "Toggle fake fullscreen"
|
|
||||||
|
|
||||||
case "workspace":
|
|
||||||
if params == "+1":
|
|
||||||
return "Workspace: focus right"
|
|
||||||
elif params == "-1":
|
|
||||||
return "Workspace: focus left"
|
|
||||||
return "Focus workspace {}".format(params)
|
|
||||||
|
|
||||||
case "movefocus":
|
|
||||||
return "Window: move focus {}".format(
|
|
||||||
{
|
|
||||||
"l": "left",
|
|
||||||
"r": "right",
|
|
||||||
"u": "up",
|
|
||||||
"d": "down",
|
|
||||||
}.get(params, "null")
|
|
||||||
)
|
|
||||||
|
|
||||||
case "swapwindow":
|
|
||||||
return "Window: swap in {} direction".format(
|
|
||||||
{
|
|
||||||
"l": "left",
|
|
||||||
"r": "right",
|
|
||||||
"u": "up",
|
|
||||||
"d": "down",
|
|
||||||
}.get(params, "null")
|
|
||||||
)
|
|
||||||
|
|
||||||
case "movetoworkspace":
|
|
||||||
if params == "+1":
|
|
||||||
return "Window: move to right workspace (non-silent)"
|
|
||||||
elif params == "-1":
|
|
||||||
return "Window: move to left workspace (non-silent)"
|
|
||||||
return "Window: move to workspace {} (non-silent)".format(params)
|
|
||||||
|
|
||||||
case "movetoworkspacesilent":
|
|
||||||
if params == "+1":
|
|
||||||
return "Window: move to right workspace"
|
|
||||||
elif params == "-1":
|
|
||||||
return "Window: move to right workspace"
|
|
||||||
return "Window: move to workspace {}".format(params)
|
|
||||||
|
|
||||||
case "togglespecialworkspace":
|
|
||||||
return "Workspace: toggle special"
|
|
||||||
|
|
||||||
case "exec":
|
|
||||||
return "Execute: {}".format(params)
|
|
||||||
|
|
||||||
case _:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def get_keybind_at_line(line_number, line_start = 0):
|
|
||||||
global content_lines
|
|
||||||
line = content_lines[line_number]
|
|
||||||
_, keys = line.split("=", 1)
|
|
||||||
keys, *comment = keys.split("#", 1)
|
|
||||||
|
|
||||||
mods, key, dispatcher, *params = list(map(str.strip, keys.split(",", 4)))
|
|
||||||
params = "".join(map(str.strip, params))
|
|
||||||
|
|
||||||
# Remove empty spaces
|
|
||||||
comment = list(map(str.strip, comment))
|
|
||||||
# Add comment if it exists, else generate it
|
|
||||||
if comment:
|
|
||||||
comment = comment[0]
|
|
||||||
if comment.startswith("[hidden]"):
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
comment = autogenerate_comment(dispatcher, params)
|
|
||||||
|
|
||||||
if mods:
|
|
||||||
modstring = mods + MOD_SEPARATORS[0] # Add separator at end to ensure last mod is read
|
|
||||||
mods = []
|
|
||||||
p = 0
|
|
||||||
for index, char in enumerate(modstring):
|
|
||||||
if(char in MOD_SEPARATORS):
|
|
||||||
if(index - p > 1):
|
|
||||||
mods.append(modstring[p:index])
|
|
||||||
p = index+1
|
|
||||||
else:
|
|
||||||
mods = []
|
|
||||||
|
|
||||||
return KeyBinding(mods, key, dispatcher, params, comment)
|
|
||||||
|
|
||||||
def get_binds_recursive(current_content, scope):
|
|
||||||
global content_lines
|
|
||||||
global reading_line
|
|
||||||
# print("get_binds_recursive({0}, {1}) [@L{2}]".format(current_content, scope, reading_line + 1))
|
|
||||||
while reading_line < len(content_lines): # TODO: Adjust condition
|
|
||||||
line = content_lines[reading_line]
|
|
||||||
heading_search_result = re.search(TITLE_REGEX, line)
|
|
||||||
# print("Read line {0}: {1}\tisHeading: {2}".format(reading_line + 1, content_lines[reading_line], "[{0}, {1}, {2}]".format(heading_search_result.start(), heading_search_result.start() == 0, ((heading_search_result != None) and (heading_search_result.start() == 0))) if heading_search_result != None else "No"))
|
|
||||||
if ((heading_search_result != None) and (heading_search_result.start() == 0)): # Found title
|
|
||||||
# Determine scope
|
|
||||||
heading_scope = line.find('!')
|
|
||||||
# Lower? Return
|
|
||||||
if(heading_scope <= scope):
|
|
||||||
reading_line -= 1
|
|
||||||
return current_content
|
|
||||||
|
|
||||||
section_name = line[(heading_scope+1):].strip()
|
|
||||||
# print("[[ Found h{0} at line {1} ]] {2}".format(heading_scope, reading_line+1, content_lines[reading_line]))
|
|
||||||
reading_line += 1
|
|
||||||
current_content["children"].append(get_binds_recursive(Section([], [], section_name), heading_scope))
|
|
||||||
|
|
||||||
elif line.startswith(COMMENT_BIND_PATTERN):
|
|
||||||
keybind = get_keybind_at_line(reading_line, line_start=len(COMMENT_BIND_PATTERN))
|
|
||||||
if(keybind != None):
|
|
||||||
current_content["keybinds"].append(keybind)
|
|
||||||
|
|
||||||
elif line == "" or not line.lstrip().startswith("bind"): # Comment, ignore
|
|
||||||
pass
|
|
||||||
|
|
||||||
else: # Normal keybind
|
|
||||||
keybind = get_keybind_at_line(reading_line)
|
|
||||||
if(keybind != None):
|
|
||||||
current_content["keybinds"].append(keybind)
|
|
||||||
|
|
||||||
reading_line += 1
|
|
||||||
|
|
||||||
return current_content;
|
|
||||||
|
|
||||||
def parse_keys(path: str) -> Dict[str, List[KeyBinding]]:
|
|
||||||
global content_lines
|
|
||||||
content_lines = read_content(path).splitlines()
|
|
||||||
if content_lines[0] == "error":
|
|
||||||
return "error"
|
|
||||||
return get_binds_recursive(Section([], [], ""), 0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import json
|
|
||||||
|
|
||||||
ParsedKeys = parse_keys(args.path)
|
|
||||||
print(json.dumps(ParsedKeys))
|
|
||||||
Reference in New Issue
Block a user