Brightness.qml
1 pragma Singleton 2 pragma ComponentBehavior: Bound 3 4 import "root:/widgets" 5 import Quickshell 6 import Quickshell.Io 7 import QtQuick 8 9 Singleton { 10 id: root 11 12 property var ddcMonitors: [] 13 readonly property list<Monitor> monitors: variants.instances 14 15 function getMonitorForScreen(screen: ShellScreen): var { 16 return monitors.find(m => m.modelData === screen); 17 } 18 19 function increaseBrightness(): void { 20 const focusedName = Hyprland.focusedMonitor.name; 21 const monitor = monitors.find(m => focusedName === m.modelData.name); 22 if (monitor) 23 monitor.setBrightness(monitor.brightness + 0.1); 24 } 25 26 function decreaseBrightness(): void { 27 const focusedName = Hyprland.focusedMonitor.name; 28 const monitor = monitors.find(m => focusedName === m.modelData.name); 29 if (monitor) 30 monitor.setBrightness(monitor.brightness - 0.1); 31 } 32 33 reloadableId: "brightness" 34 35 onMonitorsChanged: { 36 ddcMonitors = []; 37 ddcProc.running = true; 38 } 39 40 Variants { 41 id: variants 42 43 model: Quickshell.screens 44 45 Monitor {} 46 } 47 48 Process { 49 id: ddcProc 50 51 command: ["ddcutil", "detect", "--brief"] 52 stdout: SplitParser { 53 splitMarker: "\n\n" 54 onRead: data => { 55 if (data.startsWith("Display ")) { 56 const lines = data.split("\n").map(l => l.trim()); 57 root.ddcMonitors.push({ 58 model: lines.find(l => l.startsWith("Monitor:")).split(":")[2], 59 busNum: lines.find(l => l.startsWith("I2C bus:")).split("/dev/i2c-")[1] 60 }); 61 } 62 } 63 } 64 onExited: root.ddcMonitorsChanged() 65 } 66 67 Process { 68 id: setProc 69 } 70 71 CustomShortcut { 72 name: "brightnessUp" 73 onPressed: root.increaseBrightness() 74 } 75 76 CustomShortcut { 77 name: "brightnessDown" 78 onPressed: root.decreaseBrightness() 79 } 80 81 component Monitor: QtObject { 82 id: monitor 83 84 required property ShellScreen modelData 85 readonly property bool isDdc: root.ddcMonitors.some(m => m.model === modelData.model) 86 readonly property string busNum: root.ddcMonitors.find(m => m.model === modelData.model)?.busNum ?? "" 87 property real brightness 88 89 readonly property Process initProc: Process { 90 stdout: SplitParser { 91 onRead: data => { 92 const [, , , current, max] = data.split(" "); 93 monitor.brightness = parseInt(current) / parseInt(max); 94 } 95 } 96 } 97 98 function setBrightness(value: real): void { 99 value = Math.max(0, Math.min(1, value)); 100 const rounded = Math.round(value * 100); 101 if (Math.round(brightness * 100) === rounded) 102 return; 103 brightness = value; 104 setProc.command = isDdc ? ["ddcutil", "-b", busNum, "setvcp", "10", rounded] : ["brightnessctl", "s", `${rounded}%`]; 105 setProc.startDetached(); 106 } 107 108 onBusNumChanged: { 109 initProc.command = isDdc ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`]; 110 initProc.running = true; 111 } 112 113 Component.onCompleted: { 114 initProc.command = isDdc ? ["ddcutil", "-b", busNum, "getvcp", "10", "--brief"] : ["sh", "-c", `echo "a b c $(brightnessctl g) $(brightnessctl m)"`]; 115 initProc.running = true; 116 } 117 } 118 }