forked from Shinonome/dots-hyprland
ags: implement per-monitor brightness control
This commit is contained in:
@@ -38,6 +38,9 @@ let configOptions = {
|
|||||||
'warnTitles': ["Low battery", "Very low battery", 'Critical Battery'],
|
'warnTitles': ["Low battery", "Very low battery", 'Critical Battery'],
|
||||||
'warnMessages': ["Plug in the charger", "You there?", 'PLUG THE CHARGER ALREADY'],
|
'warnMessages': ["Plug in the charger", "You there?", 'PLUG THE CHARGER ALREADY'],
|
||||||
},
|
},
|
||||||
|
'brightness': {
|
||||||
|
'controller': "brightnessctl",
|
||||||
|
},
|
||||||
'music': {
|
'music': {
|
||||||
'preferredPlayer': "plasma-browser-integration",
|
'preferredPlayer': "plasma-browser-integration",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export const Bar = async (monitor = 0) => {
|
|||||||
const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||||
// execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print);
|
// execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print);
|
||||||
},
|
},
|
||||||
startWidget: (await WindowTitle()),
|
startWidget: (await WindowTitle(monitor)),
|
||||||
centerWidget: Widget.Box({
|
centerWidget: Widget.Box({
|
||||||
className: 'spacing-h-4',
|
className: 'spacing-h-4',
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -39,16 +39,16 @@ const WindowTitle = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default async () => {
|
export default async (monitor = 0) => {
|
||||||
const optionalWindowTitleInstance = await WindowTitle();
|
const optionalWindowTitleInstance = await WindowTitle();
|
||||||
return Widget.EventBox({
|
return Widget.EventBox({
|
||||||
onScrollUp: () => {
|
onScrollUp: () => {
|
||||||
Indicator.popup(1); // Since the brightness and speaker are both on the same window
|
Indicator.popup(1); // Since the brightness and speaker are both on the same window
|
||||||
Brightness.screen_value += 0.05;
|
Brightness[monitor].screen_value += 0.05;
|
||||||
},
|
},
|
||||||
onScrollDown: () => {
|
onScrollDown: () => {
|
||||||
Indicator.popup(1); // Since the brightness and speaker are both on the same window
|
Indicator.popup(1); // Since the brightness and speaker are both on the same window
|
||||||
Brightness.screen_value -= 0.05;
|
Brightness[monitor].screen_value -= 0.05;
|
||||||
},
|
},
|
||||||
onPrimaryClick: () => {
|
onPrimaryClick: () => {
|
||||||
App.toggleWindow('sideleft');
|
App.toggleWindow('sideleft');
|
||||||
|
|||||||
@@ -49,16 +49,16 @@ const OsdValue = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default (monitor = 0) => {
|
||||||
const brightnessIndicator = OsdValue({
|
const brightnessIndicator = OsdValue({
|
||||||
name: 'Brightness',
|
name: 'Brightness',
|
||||||
extraClassName: 'osd-brightness',
|
extraClassName: 'osd-brightness',
|
||||||
extraProgressClassName: 'osd-brightness-progress',
|
extraProgressClassName: 'osd-brightness-progress',
|
||||||
labelSetup: (self) => self.hook(Brightness, self => {
|
labelSetup: (self) => self.hook(Brightness[monitor], self => {
|
||||||
self.label = `${Math.round(Brightness.screen_value * 100)}`;
|
self.label = `${Math.round(Brightness[monitor].screen_value * 100)}`;
|
||||||
}, 'notify::screen-value'),
|
}, 'notify::screen-value'),
|
||||||
progressSetup: (self) => self.hook(Brightness, (progress) => {
|
progressSetup: (self) => self.hook(Brightness[monitor], (progress) => {
|
||||||
const updateValue = Brightness.screen_value;
|
const updateValue = Brightness[monitor].screen_value;
|
||||||
progress.value = updateValue;
|
progress.value = updateValue;
|
||||||
}, 'notify::screen-value'),
|
}, 'notify::screen-value'),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default (monitor = 0) => Widget.Window({
|
|||||||
className: 'osd-window',
|
className: 'osd-window',
|
||||||
css: 'min-height: 2px;',
|
css: 'min-height: 2px;',
|
||||||
children: [
|
children: [
|
||||||
IndicatorValues(),
|
IndicatorValues(monitor),
|
||||||
MusicControls(),
|
MusicControls(),
|
||||||
NotificationPopups(),
|
NotificationPopups(),
|
||||||
ColorScheme(),
|
ColorScheme(),
|
||||||
@@ -30,4 +30,3 @@ export default (monitor = 0) => Widget.Window({
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
||||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
const { exec, execAsync } = Utils;
|
const { exec, execAsync } = Utils;
|
||||||
|
|
||||||
import { clamp } from '../modules/.miscutils/mathfuncs.js';
|
import { clamp } from '../modules/.miscutils/mathfuncs.js';
|
||||||
|
|
||||||
class BrightnessService extends Service {
|
class BrightnessServiceBase extends Service {
|
||||||
static {
|
static {
|
||||||
Service.register(
|
Service.register(
|
||||||
this,
|
this,
|
||||||
@@ -23,7 +24,7 @@ class BrightnessService extends Service {
|
|||||||
percent = clamp(percent, 0, 1);
|
percent = clamp(percent, 0, 1);
|
||||||
this._screenValue = percent;
|
this._screenValue = percent;
|
||||||
|
|
||||||
Utils.execAsync(`brightnessctl s ${percent * 100}% -q`)
|
Utils.execAsync(this.setBrightnessCmd(percent))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// signals has to be explicity emitted
|
// signals has to be explicity emitted
|
||||||
this.emit('screen-changed', percent);
|
this.emit('screen-changed', percent);
|
||||||
@@ -35,13 +36,6 @@ class BrightnessService extends Service {
|
|||||||
.catch(print);
|
.catch(print);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const current = Number(exec('brightnessctl g'));
|
|
||||||
const max = Number(exec('brightnessctl m'));
|
|
||||||
this._screenValue = current / max;
|
|
||||||
}
|
|
||||||
|
|
||||||
// overwriting connectWidget method, lets you
|
// overwriting connectWidget method, lets you
|
||||||
// change the default event that widgets connect to
|
// change the default event that widgets connect to
|
||||||
connectWidget(widget, callback, event = 'screen-changed') {
|
connectWidget(widget, callback, event = 'screen-changed') {
|
||||||
@@ -49,11 +43,70 @@ class BrightnessService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BrightnessCtlService extends BrightnessServiceBase {
|
||||||
|
static {
|
||||||
|
Service.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
const current = Number(exec('brightnessctl g'));
|
||||||
|
const max = Number(exec('brightnessctl m'));
|
||||||
|
this._screenValue = current / max;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBrightnessCmd(percent) {
|
||||||
|
return `brightnessctl s ${percent * 100}% -q`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BrightnessDdcService extends BrightnessServiceBase {
|
||||||
|
static {
|
||||||
|
Service.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(monitor = 0) {
|
||||||
|
super();
|
||||||
|
// don't use Hyprland.getMonitor(id), Hyprland monitor id isn't consistent
|
||||||
|
// with Gdk, but the Array ordering is (magically)
|
||||||
|
this._sn = Hyprland.monitors[monitor].serial;
|
||||||
|
Utils.execAsync(`ddcutil --sn ${this._sn} getvcp 10 --brief`)
|
||||||
|
.then((out) => {
|
||||||
|
// only the last line is useful
|
||||||
|
out = out.split('\n');
|
||||||
|
out = out[out.length - 1];
|
||||||
|
|
||||||
|
out = out.split(' ');
|
||||||
|
const current = Number(out[3]);
|
||||||
|
const max = Number(out[4]);
|
||||||
|
this._screenValue = current / max;
|
||||||
|
})
|
||||||
|
.catch(print);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBrightnessCmd(percent) {
|
||||||
|
return `ddcutil --sn ${this._sn} setvcp 10 ${Math.round(percent * 100)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the singleton instance
|
// the singleton instance
|
||||||
const service = new BrightnessService();
|
const numMonitors = Hyprland.monitors.length;
|
||||||
|
const service = Array(numMonitors);
|
||||||
|
switch (userOptions.brightness.controller) {
|
||||||
|
case "brightnessctl":
|
||||||
|
service.fill(new BrightnessCtlService());
|
||||||
|
break;
|
||||||
|
case "ddcutil":
|
||||||
|
for (let i = 0; i < numMonitors; i++) {
|
||||||
|
service[i] = new BrightnessDdcService(i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown brightness controller ${userOptions.brightness.controller}`);
|
||||||
|
}
|
||||||
|
|
||||||
// make it global for easy use with cli
|
// make it global for easy use with cli
|
||||||
globalThis.brightness = service;
|
globalThis.brightness = service[0];
|
||||||
|
|
||||||
// export to use in other modules
|
// export to use in other modules
|
||||||
export default service;
|
export default service;
|
||||||
Reference in New Issue
Block a user