🔧 chore(modules/bluetooth): also select default adapter on bluetoothctl

This commit is contained in:
retrozinndev
2025-09-25 15:42:48 -03:00
parent 2e8b1f8815
commit e07ef2ef15
3 changed files with 56 additions and 52 deletions
+51 -31
View File
@@ -1,5 +1,7 @@
import { createRoot, getScope, Scope } from "ags"; import { createRoot, getScope, Scope } from "ags";
import GObject, { getter, gtype, register, setter } from "ags/gobject"; import GObject, { getter, gtype, property, register, setter } from "ags/gobject";
import { execAsync } from "ags/process";
import AstalBluetooth from "gi://AstalBluetooth"; import AstalBluetooth from "gi://AstalBluetooth";
@@ -17,6 +19,8 @@ export class Bluetooth extends GObject.Object {
@getter(Boolean) @getter(Boolean)
get isAvailable() { return this.#isAvailable; } get isAvailable() { return this.#isAvailable; }
@property(Boolean) saveDefaultAdapter = true;
@getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter)) @getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter))
get adapter() { return this.#adapter; } get adapter() { return this.#adapter; }
@@ -24,6 +28,19 @@ export class Bluetooth extends GObject.Object {
set adapter(newAdapter: AstalBluetooth.Adapter|null) { set adapter(newAdapter: AstalBluetooth.Adapter|null) {
this.#adapter = newAdapter; this.#adapter = newAdapter;
this.notify("adapter"); this.notify("adapter");
if(!newAdapter) return;
AstalBluetooth.get_default().adapters.filter(ad => {
if(ad.address !== newAdapter.address)
return true;
ad.set_powered(true);
return false;
}).forEach(ad => ad.set_powered(false));
execAsync(`bluetoothctl select ${newAdapter.address}`).catch(e =>
console.error(`Bluetooth: Couldn't select adapter. Stderr: ${e}`));
} }
constructor() { constructor() {
@@ -38,38 +55,41 @@ export class Bluetooth extends GObject.Object {
} }
this.#connections.set( this.#connections.set(
AstalBluetooth.get_default(), AstalBluetooth.get_default(), [
AstalBluetooth.get_default().connect("adapter-added", (self, adapter) => { AstalBluetooth.get_default().connect("adapter-added", (self, adapter) => {
if(self.adapters.length === 1) // adapter was just added if(self.adapters.length === 1) // adapter was just added
this.adapter = adapter; this.adapter = adapter;
}) }),
AstalBluetooth.get_default().connect("adapter-removed", (self, adapter) => {
if(self.adapters.length < 1) {
this.adapter = null;
this.#isAvailable = false;
this.notify("is-available");
}
if(this.#adapter?.address !== adapter.address)
return;
// the removed adapter was the default
if(self.adapters.length < 1) {
this.adapter = null;
this.#isAvailable = false;
this.notify("is-available");
return;
}
this.#adapter = self.adapters[0];
})
]
); );
this.#connections.set( this.#scope.onCleanup(() => this.#connections.forEach((ids, gobj) =>
AstalBluetooth.get_default(), Array.isArray(ids) ?
AstalBluetooth.get_default().connect("adapter-removed", (self, adapter) => { ids.forEach(id => gobj.disconnect(id))
if(self.adapters.length < 1) { : gobj.disconnect(ids)
this.adapter = null; ));
this.#isAvailable = false;
this.notify("is-available");
}
if(this.#adapter?.address !== adapter.address)
return;
// the removed adapter was the default
if(self.adapters.length < 1) {
this.adapter = null;
this.#isAvailable = false;
this.notify("is-available");
return;
}
this.#adapter = self.adapters[0];
})
);
}); });
} }
+1 -1
View File
@@ -1,6 +1,6 @@
import { createPoll } from "ags/time"; import { createPoll } from "ags/time";
import { exec, execAsync } from "ags/process"; import { exec, execAsync } from "ags/process";
import { Accessor, For, getScope, onCleanup, With } from "ags"; import { Accessor, For, getScope, With } from "ags";
import { Astal, Gtk } from "ags/gtk4"; import { Astal, Gtk } from "ags/gtk4";
import { getSymbolicIcon } from "./apps"; import { getSymbolicIcon } from "./apps";
@@ -4,7 +4,6 @@ import { tr } from "../../../../i18n/intl";
import { Windows } from "../../../../windows"; import { Windows } from "../../../../windows";
import { Notifications } from "../../../../modules/notifications"; import { Notifications } from "../../../../modules/notifications";
import { execApp } from "../../../../modules/apps"; import { execApp } from "../../../../modules/apps";
import { execAsync } from "ags/process";
import { createBinding, createComputed, For, With } from "ags"; import { createBinding, createComputed, For, With } from "ags";
import { Bluetooth } from "../../../../modules/bluetooth"; import { Bluetooth } from "../../../../modules/bluetooth";
@@ -69,10 +68,10 @@ export const BluetoothPage = new Page({
return <PageButton class={isSelected.as(is => is ? "selected" : "")} return <PageButton class={isSelected.as(is => is ? "selected" : "")}
title={adapter.alias ?? "Adapter"} icon={"bluetooth-active-symbolic"} title={adapter.alias ?? "Adapter"} icon={"bluetooth-active-symbolic"}
description={createBinding(adapter, "address")} description={createBinding(adapter, "address")}
actionClicked={() => actionClicked={() => {
adapter.address !== Bluetooth.getDefault().adapter?.address && if(adapter.address !== Bluetooth.getDefault().adapter?.address)
selectAdapter(adapter) Bluetooth.getDefault().adapter = adapter;
} }}
endWidget={ endWidget={
<Gtk.Image iconName={"object-select-symbolic"} visible={isSelected} /> <Gtk.Image iconName={"object-select-symbolic"} visible={isSelected} />
} }
@@ -212,18 +211,3 @@ function DeviceWidget({ device }: { device: AstalBluetooth.Device }): Gtk.Widget
</With>} </With>}
/> as Gtk.Widget; /> as Gtk.Widget;
} }
function selectAdapter(adapter: AstalBluetooth.Adapter): void {
AstalBluetooth.get_default().adapters.filter(ad => {
if(ad.alias !== adapter.alias)
return true;
ad.set_powered(true);
return false;
}).forEach(ad => ad.set_powered(false));
execAsync(`bluetoothctl select ${adapter.address}`).catch(e =>
console.error(`Bluetooth: Couldn't select adapter. Stderr: ${e}`));
Bluetooth.getDefault().adapter = adapter;
}