🔧 chore(modules/utils, osd): use secureBaseBinding() for osd modes

This commit is contained in:
retrozinndev
2025-09-28 13:38:52 -03:00
parent 6018d6d792
commit 914d949ad3
3 changed files with 94 additions and 12 deletions
+2 -2
View File
@@ -291,7 +291,7 @@ you should use the socket in the XDG_RUNTIME_DIR/colorshell.sock for a faster re
this.#connections.set(Wireplumber.getDefault(), this.#connections.set(Wireplumber.getDefault(),
Wireplumber.getDefault().getDefaultSink().connect("notify::volume", () => Wireplumber.getDefault().getDefaultSink().connect("notify::volume", () =>
!Windows.getDefault().isOpen("control-center") && !Windows.getDefault().isOpen("control-center") &&
triggerOSD(OSDModes.SINK) triggerOSD(OSDModes.sink)
) )
); );
@@ -311,7 +311,7 @@ you should use the socket in the XDG_RUNTIME_DIR/colorshell.sock for a faster re
this.#connections.set(defaultBk, defaultBk.connect("brightness-changed", () => this.#connections.set(defaultBk, defaultBk.connect("brightness-changed", () =>
!Windows.getDefault().isOpen("control-center") && !Windows.getDefault().isOpen("control-center") &&
triggerOSD(OSDModes.BRIGHTNESS) triggerOSD(OSDModes.brightness)
)); ));
}) })
); );
+59 -1
View File
@@ -6,7 +6,7 @@ import { getSymbolicIcon } from "./apps";
import GLib from "gi://GLib?version=2.0"; import GLib from "gi://GLib?version=2.0";
import Gio from "gi://Gio?version=2.0"; import Gio from "gi://Gio?version=2.0";
import GObject from "ags/gobject"; import GObject from "gi://GObject?version=2.0";
/** gnim doesn't export this, so we need to do it again */ /** gnim doesn't export this, so we need to do it again */
@@ -301,3 +301,61 @@ export function secureBinding<
} }
); );
} }
/** securely bind to a property of a gobject accessor
* use this to securely bind to a property of a constantly
* updated variable that points to a gobject.
*
* It follows the same idea from secureBinding, it allows setting
* a default value to return when the base gobject is null.
*
* @param baseObject a binding to the constantly updated property
* that points to the gobject
* @param prop the property to bind
* @param defaultValue the value to return when the baseObject is
* null/undefined
*
* @returns a bind to the specified property of the constantly-updated
* object or the default value.
* */
export function secureBaseBinding<
T extends GObject.Object = GObject.Object,
Prop extends keyof T = keyof T,
Default = any
>(
baseObject: Accessor<T>,
prop: Prop,
defaultValue: Default
): Accessor<T[Prop]|Default> {
let gobj: T|undefined = baseObject.get();
let notify: () => void;
const baseSub = baseObject.subscribe(() => {
const newBase = baseObject.get();
if(!newBase) {
gobj = undefined;
notify!();
return;
}
});
const accessor = new Accessor<T[Prop]|Default>(
() => gobj ? gobj[prop] : defaultValue,
(notifyFun) => {
notify = notifyFun;
const id = gobj?.connect(
`notify::${(prop as string).replace(/[A-Z]/g, (s) => `-${s.toLowerCase()}`)}`,
() => notify()
);
return () => {
id && gobj?.disconnect(id);
baseSub();
}
}
);
return accessor;
}
+33 -9
View File
@@ -3,7 +3,7 @@ import { createBinding, createState, With } from "ags";
import { Wireplumber } from "../../modules/volume"; import { Wireplumber } from "../../modules/volume";
import { Windows } from "../../windows"; import { Windows } from "../../windows";
import { Backlights } from "../../modules/backlight"; import { Backlights } from "../../modules/backlight";
import { secureBinding, variableToBoolean } from "../../modules/utils"; import { secureBaseBinding, secureBinding, variableToBoolean } from "../../modules/utils";
import Pango from "gi://Pango?version=1.0"; import Pango from "gi://Pango?version=1.0";
import GLib from "gi://GLib?version=2.0"; import GLib from "gi://GLib?version=2.0";
@@ -13,18 +13,42 @@ import OSDMode from "./modules/osdmode";
export const OSDModes = { export const OSDModes = {
sink: new OSDMode({ sink: new OSDMode({
icon: secureBinding(AstalWp.get_default().defaultSpeaker, "volumeIcon", available: secureBinding(AstalWp.get_default(), "defaultSpeaker", false).as((sink) =>
"audio-volume-high-symbolic"), Boolean(sink)),
value: secureBinding(Wireplumber.getWireplumber().defaultSpeaker, "volume", 50), icon: secureBaseBinding<AstalWp.Endpoint>(
text: secureBinding(Wireplumber.getWireplumber().defaultSpeaker, "description", createBinding(AstalWp.get_default(), "defaultSpeaker"),
"Unknown Speaker"), "volumeIcon",
"audio-volume-high-symbolic"
),
value: secureBaseBinding<AstalWp.Endpoint>(
createBinding(AstalWp.get_default(), "defaultSpeaker"),
"volume",
.5
),
text: secureBaseBinding<AstalWp.Endpoint>(
createBinding(AstalWp.get_default(), "defaultSpeaker"),
"description",
"Unknown Speaker"
),
max: Wireplumber.getDefault().getMaxSinkVolume() / 100 max: Wireplumber.getDefault().getMaxSinkVolume() / 100
}), }),
brightness: new OSDMode({ brightness: new OSDMode({
icon: "display-brightness-symbolic", icon: "display-brightness-symbolic",
value: secureBinding(Backlights.getDefault().default, "brightness", 100), value: secureBaseBinding<Backlights.Backlight>(
max: secureBinding(Backlights.getDefault().default, "maxBrightness", 100), createBinding(Backlights.getDefault(), "default"),
text: secureBinding(Backlights.getDefault().default, "name", "Unknown Backlight"), "brightness",
100
),
max: secureBaseBinding<Backlights.Backlight>(
createBinding(Backlights.getDefault(), "default"),
"maxBrightness",
100
),
text: secureBaseBinding<Backlights.Backlight>(
createBinding(Backlights.getDefault(), "default"),
"name",
"Unknown Backlight"
),
available: createBinding(Backlights.getDefault(), "available") available: createBinding(Backlights.getDefault(), "available")
}) })
} }