From a575245d7b9f084110ce062b35d908ceeda260ab Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sun, 4 May 2025 22:11:03 +1000 Subject: feat: brightness osd --- config/OsdConfig.qml | 2 +- modules/osd/Content.qml | 4 +- modules/osd/Osd.qml | 60 ++++++++++++++----------- services/Brightness.qml | 113 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 services/Brightness.qml diff --git a/config/OsdConfig.qml b/config/OsdConfig.qml index 1bfdbd6..467d8e7 100644 --- a/config/OsdConfig.qml +++ b/config/OsdConfig.qml @@ -4,7 +4,7 @@ import Quickshell import QtQuick Singleton { - readonly property int hideDelay: 1500 + readonly property int hideDelay: 2000 readonly property Sizes sizes: Sizes {} component Sizes: QtObject { diff --git a/modules/osd/Content.qml b/modules/osd/Content.qml index daab4e2..b224bf6 100644 --- a/modules/osd/Content.qml +++ b/modules/osd/Content.qml @@ -7,7 +7,7 @@ import QtQuick Column { id: root - required property ShellScreen screen + required property Brightness.Monitor monitor padding: Appearance.padding.large @@ -35,6 +35,8 @@ Column { VerticalSlider { icon: "brightness_6" + value: root.monitor?.brightness ?? 0 + onMoved: root.monitor?.setBrightness(value) implicitWidth: OsdConfig.sizes.sliderWidth implicitHeight: OsdConfig.sizes.sliderHeight diff --git a/modules/osd/Osd.qml b/modules/osd/Osd.qml index 4d744f6..4d6ab7e 100644 --- a/modules/osd/Osd.qml +++ b/modules/osd/Osd.qml @@ -4,47 +4,55 @@ import "root:/config" import Quickshell import QtQuick -Scope { - id: root +Variants { + model: Quickshell.screens - property bool osdVisible + Scope { + id: root - function show(): void { - root.osdVisible = true; - timer.restart(); - } - - Connections { - target: Audio + required property ShellScreen modelData + readonly property Brightness.Monitor monitor: Brightness.getMonitorForScreen(modelData) + property bool osdVisible - function onMutedChanged(): void { - root.show(); + function show(): void { + root.osdVisible = true; + timer.restart(); } - function onVolumeChanged(): void { - root.show(); + Connections { + target: Audio + + function onMutedChanged(): void { + root.show(); + } + + function onVolumeChanged(): void { + root.show(); + } } - } - Timer { - id: timer + Connections { + target: root.monitor - interval: OsdConfig.hideDelay - onTriggered: root.osdVisible = false - } + function onBrightnessChanged(): void { + root.show(); + } + } - Variants { - model: Quickshell.screens + Timer { + id: timer + + interval: OsdConfig.hideDelay + onTriggered: root.osdVisible = false + } LazyLoader { loading: true - required property ShellScreen modelData - StyledWindow { id: win - screen: parent.modelData + screen: root.modelData name: "osd" visible: wrapper.shouldBeVisible @@ -80,7 +88,7 @@ Scope { Content { id: content - screen: parent.modelData + monitor: root.monitor } } } diff --git a/services/Brightness.qml b/services/Brightness.qml new file mode 100644 index 0000000..dd51376 --- /dev/null +++ b/services/Brightness.qml @@ -0,0 +1,113 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import "root:/widgets" +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + property var ddcMonitors: [] + readonly property list monitors: Quickshell.screens.map(screen => monitorComp.createObject(root, { + screen + })) + + function getMonitorForScreen(screen: ShellScreen): var { + return monitors.find(m => m.screen === screen); + } + + function increaseBrightness(): void { + const focusedName = Hyprland.focusedMonitor.name; + const monitor = monitors.find(m => focusedName === m.screen.name); + if (monitor) + monitor.setBrightness(monitor.brightness + 0.1); + } + + function decreaseBrightness(): void { + const focusedName = Hyprland.focusedMonitor.name; + const monitor = monitors.find(m => focusedName === m.screen.name); + if (monitor) + monitor.setBrightness(monitor.brightness - 0.1); + } + + reloadableId: "brightness" + + onMonitorsChanged: { + ddcMonitors = []; + ddcProc.running = true; + } + + Process { + id: ddcProc + + command: ["ddcutil", "detect", "--brief"] + stdout: SplitParser { + splitMarker: "\n\n" + onRead: data => { + if (data.startsWith("Display ")) { + const lines = data.split("\n").map(l => l.trim()); + root.ddcMonitors.push({ + model: lines.find(l => l.startsWith("Monitor:")).split(":")[2], + busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1] + }); + } + } + } + onExited: root.ddcMonitorsChanged() + } + + Process { + id: setProc + } + + CustomShortcut { + name: "brightnessUp" + onPressed: root.increaseBrightness() + } + + CustomShortcut { + name: "brightnessDown" + onPressed: root.decreaseBrightness() + } + + component Monitor: QtObject { + id: monitor + + required property ShellScreen screen + readonly property bool isDdc: root.ddcMonitors.some(m => m.model === screen.model) + readonly property string busNum: root.ddcMonitors.find(m => m.model === screen.model)?.busNum ?? "" + property real brightness + + readonly property Process initProc: Process { + stdout: SplitParser { + onRead: data => { + const [, , , current, max] = data.split(" "); + monitor.brightness = parseInt(current) / parseInt(max); + } + } + } + + function setBrightness(value: real): void { + value = Math.max(0, Math.min(1, value)); + const rounded = Math.round(value * 100); + if (Math.round(brightness * 100) === rounded) + return; + brightness = value; + setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rounded] : ["brightnessctl", "s", rounded]; + setProc.startDetached(); + } + + onBusNumChanged: { + initProc.command = isDdc ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`]; + initProc.running = true; + } + } + + Component { + id: monitorComp + + Monitor {} + } +} -- cgit v1.2.3-freya