98 lines
2.8 KiB
QML
98 lines
2.8 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
|
|
// Backlight control. Reads the sysfs value directly so the OSD is exact, and
|
|
// writes through brightnessctl, which already owns the udev permissions here.
|
|
Singleton {
|
|
id: root
|
|
|
|
readonly property string device: "amdgpu_bl1"
|
|
|
|
property int raw: 0
|
|
property int maxRaw: 65535
|
|
readonly property real percent: maxRaw > 0 ? raw / maxRaw * 100 : 0
|
|
readonly property bool available: maxRaw > 0
|
|
|
|
signal bumped()
|
|
|
|
FileView {
|
|
id: maxFile
|
|
path: "/sys/class/backlight/" + root.device + "/max_brightness"
|
|
watchChanges: false
|
|
onLoaded: {
|
|
const v = parseInt(text().trim());
|
|
if (v > 0) root.maxRaw = v;
|
|
}
|
|
}
|
|
|
|
FileView {
|
|
id: currentFile
|
|
path: "/sys/class/backlight/" + root.device + "/brightness"
|
|
watchChanges: true
|
|
onFileChanged: reload()
|
|
onLoaded: {
|
|
const v = parseInt(text().trim());
|
|
if (!isNaN(v) && v !== root.raw) {
|
|
root.raw = v;
|
|
// Settled, or moved by something else: step from here again.
|
|
if (!setter.running && root.pending < 0) root.target = -1;
|
|
root.bumped();
|
|
}
|
|
}
|
|
}
|
|
|
|
// sysfs writes do not always fire inotify for backlight, so poll gently too.
|
|
Timer {
|
|
interval: 1000
|
|
running: !GameMode.active
|
|
repeat: true
|
|
onTriggered: currentFile.reload()
|
|
}
|
|
|
|
// The level last asked for, until the backlight reports it. Steps build on
|
|
// it rather than on `percent`, which only catches up on the next read, so
|
|
// a fast scroll adds up instead of repeating one step.
|
|
property int target: -1
|
|
// A level asked for while a write is still running. Restarting the write
|
|
// would kill it half done, so the newest request waits and the rest drop.
|
|
property int pending: -1
|
|
|
|
Process {
|
|
id: setter
|
|
onExited: {
|
|
currentFile.reload();
|
|
if (root.pending < 0) return;
|
|
const next = root.pending;
|
|
root.pending = -1;
|
|
root._write(next);
|
|
}
|
|
}
|
|
|
|
function _write(p: int) {
|
|
setter.command = ["brightnessctl", "-d", root.device, "-q", "set", p + "%"];
|
|
setter.running = true;
|
|
}
|
|
|
|
function setPercent(p: real) {
|
|
const clamped = Math.max(1, Math.min(100, Math.round(p)));
|
|
root.target = clamped;
|
|
if (setter.running) root.pending = clamped;
|
|
else root._write(clamped);
|
|
}
|
|
|
|
function change(delta: real) {
|
|
setPercent((root.target >= 0 ? root.target : percent) + delta);
|
|
}
|
|
|
|
readonly property string icon: {
|
|
const p = root.percent;
|
|
if (p >= 80) return "";
|
|
if (p >= 55) return "";
|
|
if (p >= 30) return "";
|
|
return "";
|
|
}
|
|
}
|