summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md7
-rw-r--r--lib/bluetooth/adapter.vala117
-rw-r--r--lib/bluetooth/bluetooth.vala50
-rw-r--r--lib/bluetooth/device.vala169
l---------lib/bluetooth/gir.py1
-rw-r--r--lib/bluetooth/interfaces.vala46
-rw-r--r--lib/bluetooth/meson.build49
7 files changed, 341 insertions, 98 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e6c097e..e09c3dc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,6 +1,7 @@
# Contributing
You can contribute by:
+
- [Suggesting new features](https://github.com/Aylur/astal/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=)
- [Reporting bugs](https://github.com/Aylur/astal/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title=)
- Improving docs with additional contexts and examples
@@ -18,9 +19,11 @@ Write libraries preferably in Vala. Only choose C if some dependency is only ava
## Todo
Planned features, you could help with:
+
- [niri ipc library](https://github.com/Aylur/astal/issues/8)
- sway ipc library
- greetd ipc library
-- core: http request library, abstraction over libsoup included (mostly to be used in gjs and lua)
-- core: notification sending, libnotify clone [#26](https://github.com/Aylur/astal/issues/26)
+- http request library abstraction over libsoup (mostly to be used in gjs and lua)
+- notification sending libnotify clone [#26](https://github.com/Aylur/astal/issues/26)
- setting up [uncrustify](https://github.com/uncrustify/uncrustify) for Vala
+- bluetooth custom errordomains, currently every error is simply Error
diff --git a/lib/bluetooth/adapter.vala b/lib/bluetooth/adapter.vala
index 0c9d00e..99a59fb 100644
--- a/lib/bluetooth/adapter.vala
+++ b/lib/bluetooth/adapter.vala
@@ -1,27 +1,10 @@
-namespace AstalBluetooth {
-[DBus (name = "org.bluez.Adapter1")]
-internal interface IAdapter : DBusProxy {
- public abstract void remove_device(ObjectPath device) throws Error;
- public abstract void start_discovery() throws Error;
- public abstract void stop_discovery() throws Error;
-
- public abstract string[] uuids { owned get; }
- public abstract bool discoverable { get; set; }
- public abstract bool discovering { get; }
- public abstract bool pairable { get; set; }
- public abstract bool powered { get; set; }
- public abstract string address { owned get; }
- public abstract string alias { owned get; set; }
- public abstract string modalias { owned get; }
- public abstract string name { owned get; }
- public abstract uint class { get; }
- public abstract uint discoverable_timeout { get; set; }
- public abstract uint pairable_timeout { get; set; }
-}
-
-public class Adapter : Object {
+/**
+ * Object representing an [[https://github.com/RadiusNetworks/bluez/blob/master/doc/adapter-api.txt|adapter]].
+ */
+public class AstalBluetooth.Adapter : Object {
private IAdapter proxy;
- public string object_path { owned get; construct set; }
+
+ internal string object_path { owned get; private set; }
internal Adapter(IAdapter proxy) {
this.proxy = proxy;
@@ -37,53 +20,127 @@ public class Adapter : Object {
});
}
+ /**
+ * List of 128-bit UUIDs that represents the available local services.
+ */
public string[] uuids { owned get { return proxy.uuids; } }
+
+ /**
+ * Indicates that a device discovery procedure is active.
+ */
public bool discovering { get { return proxy.discovering; } }
+
+ /**
+ * Local Device ID information in modalias format used by the kernel and udev.
+ */
public string modalias { owned get { return proxy.modalias; } }
+
+ /**
+ * The Bluetooth system name (pretty hostname).
+ */
public string name { owned get { return proxy.name; } }
+
+ /**
+ * The Bluetooth class of device.
+ */
public uint class { get { return proxy.class; } }
+
+ /**
+ * The Bluetooth device address.
+ */
public string address { owned get { return proxy.address; } }
+
+ /**
+ * Switch an adapter to discoverable or non-discoverable
+ * to either make it visible or hide it.
+ */
public bool discoverable {
get { return proxy.discoverable; }
set { proxy.discoverable = value; }
}
+
+ /**
+ * Switch an adapter to pairable or non-pairable.
+ */
public bool pairable {
get { return proxy.pairable; }
set { proxy.pairable = value; }
}
+
+ /**
+ * Switch an adapter on or off.
+ */
public bool powered {
get { return proxy.powered; }
set { proxy.powered = value; }
}
+
+ /**
+ * The Bluetooth friendly name.
+ *
+ * In case no alias is set, it will return [[email protected]:name].
+ */
public string alias {
owned get { return proxy.alias; }
set { proxy.alias = value; }
}
+
+ /**
+ * The discoverable timeout in seconds.
+ * A value of zero means that the timeout is disabled
+ * and it will stay in discoverable/limited mode forever
+ * until [[email protected]_discovery] is invoked.
+ * The default value for the discoverable timeout should be `180`.
+ */
public uint discoverable_timeout {
get { return proxy.discoverable_timeout; }
set { proxy.discoverable_timeout = value; }
}
+
+ /**
+ * The pairable timeout in seconds.
+ *
+ * A value of zero means that the timeout is disabled and it will stay in pairable mode forever.
+ * The default value for pairable timeout should be disabled `0`.
+ */
public uint pairable_timeout {
get { return proxy.pairable_timeout; }
set { proxy.pairable_timeout = value; }
}
- public void remove_device(Device device) {
- try { proxy.remove_device((ObjectPath)device.object_path); } catch (Error err) { critical(err.message); }
+
+ /**
+ * This removes the remote device and the pairing information.
+ *
+ * Possible errors: `InvalidArguments`, `Failed`.
+ */
+ public void remove_device(Device device) throws Error {
+ proxy.remove_device(device.object_path);
}
- public void start_discovery() {
- try { proxy.start_discovery(); } catch (Error err) { critical(err.message); }
+
+ /**
+ * This method starts the device discovery procedure.
+ *
+ * Possible errors: `NotReady`, `Failed`.
+ */
+ public void start_discovery() throws Error {
+ proxy.start_discovery();
}
- public void stop_discovery() {
- try { proxy.stop_discovery(); } catch (Error err) { critical(err.message); }
+
+ /**
+ * This method will cancel any previous [[email protected]_discovery] procedure.
+ *
+ * Possible errors: `NotReady`, `Failed`, `NotAuthorized`.
+ */
+ public void stop_discovery() throws Error {
+ proxy.stop_discovery();
}
}
-}
diff --git a/lib/bluetooth/bluetooth.vala b/lib/bluetooth/bluetooth.vala
index ce086ba..6eb6b76 100644
--- a/lib/bluetooth/bluetooth.vala
+++ b/lib/bluetooth/bluetooth.vala
@@ -1,11 +1,21 @@
namespace AstalBluetooth {
-public Bluetooth get_default() {
- return Bluetooth.get_default();
+ /**
+ * Gets the default singleton Bluetooth object.
+ */
+ public Bluetooth get_default() {
+ return Bluetooth.get_default();
+ }
}
-public class Bluetooth : Object {
+/**
+ * Manager object for `org.bluez`.
+ */
+public class AstalBluetooth.Bluetooth : Object {
private static Bluetooth _instance;
+ /**
+ * Gets the default singleton Bluetooth object.
+ */
public static Bluetooth get_default() {
if (_instance == null)
_instance = new Bluetooth();
@@ -21,30 +31,59 @@ public class Bluetooth : Object {
private HashTable<string, Device> _devices =
new HashTable<string, Device>(str_hash, str_equal);
+ /**
+ * Emitted when a new device is registered on the `org.bluez` bus.
+ */
public signal void device_added (Device device) {
notify_property("devices");
}
+ /**
+ * Emitted when a device is unregistered on the `org.bluez` bus.
+ */
public signal void device_removed (Device device) {
notify_property("devices");
}
+ /**
+ * Emitted when an adapter is registered on the `org.bluez` bus.
+ */
public signal void adapter_added (Adapter adapter) {
notify_property("adapters");
}
+ /**
+ * Emitted when an adapter is unregistered on the `org.bluez` bus.
+ */
public signal void adapter_removed (Adapter adapter) {
notify_property("adapters");
}
+ /**
+ * `true` if any of the [[email protected]:adapters] are powered.
+ */
public bool is_powered { get; private set; default = false; }
+
+ /**
+ * `true` if any of the [[email protected]:devices] is connected.
+ */
public bool is_connected { get; private set; default = false; }
+
+ /**
+ * The first registered adapter which is usually the only adapter.
+ */
public Adapter? adapter { get { return adapters.nth_data(0); } }
+ /**
+ * List of adapters available on the host device.
+ */
public List<weak Adapter> adapters {
owned get { return _adapters.get_values(); }
}
+ /**
+ * List of registered devices on the `org.bluez` bus.
+ */
public List<weak Device> devices {
owned get { return _devices.get_values(); }
}
@@ -85,6 +124,10 @@ public class Bluetooth : Object {
}
}
+ /**
+ * Toggle the [[email protected]:powered]
+ * property of the [[email protected]:adapter].
+ */
public void toggle() {
adapter.powered = !adapter.powered;
}
@@ -178,4 +221,3 @@ public class Bluetooth : Object {
return false;
}
}
-}
diff --git a/lib/bluetooth/device.vala b/lib/bluetooth/device.vala
index 8fe086f..3f00cd9 100644
--- a/lib/bluetooth/device.vala
+++ b/lib/bluetooth/device.vala
@@ -1,37 +1,14 @@
-namespace AstalBluetooth {
-[DBus (name = "org.bluez.Device1")]
-internal interface IDevice : DBusProxy {
- public abstract void cancel_pairing() throws Error;
- public abstract async void connect() throws Error;
- public abstract void connect_profile(string uuid) throws Error;
- public abstract async void disconnect() throws Error;
- public abstract void disconnect_profile(string uuid) throws Error;
- public abstract void pair() throws Error;
-
- public abstract string[] uuids { owned get; }
- public abstract bool blocked { get; set; }
- public abstract bool connected { get; }
- public abstract bool legacy_pairing { get; }
- public abstract bool paired { get; }
- public abstract bool trusted { get; set; }
- public abstract int16 rssi { get; }
- public abstract ObjectPath adapter { owned get; }
- public abstract string address { owned get; }
- public abstract string alias { owned get; set; }
- public abstract string icon { owned get; }
- public abstract string modalias { owned get; }
- public abstract string name { owned get; }
- public abstract uint16 appearance { get; }
- public abstract uint32 class { get; }
-}
-
-public class Device : Object {
+/**
+ * Object representing a [[https://github.com/luetzel/bluez/blob/master/doc/device-api.txt|device]].
+ */
+public class AstalBluetooth.Device : Object {
private IDevice proxy;
- public string object_path { owned get; construct set; }
+
+ internal ObjectPath object_path { owned get; private set; }
internal Device(IDevice proxy) {
this.proxy = proxy;
- this.object_path = proxy.g_object_path;
+ this.object_path = (ObjectPath)proxy.g_object_path;
proxy.g_properties_changed.connect((props) => {
var map = (HashTable<string, Variant>)props;
foreach (var key in map.get_keys()) {
@@ -43,64 +20,164 @@ public class Device : Object {
});
}
+ /**
+ * List of 128-bit UUIDs that represents the available remote services.
+ */
public string[] uuids { owned get { return proxy.uuids; } }
+
+ /**
+ * Indicates if the remote device is currently connected.
+ */
public bool connected { get { return proxy.connected; } }
+
+ /**
+ * `true` if the device only supports the pre-2.1 pairing mechanism.
+ */
public bool legacy_pairing { get { return proxy.legacy_pairing; } }
+
+ /**
+ * Indicates if the remote device is paired.
+ */
public bool paired { get { return proxy.paired; } }
+
+ /**
+ * Received Signal Strength Indicator of the remote device (inquiry or advertising).
+ */
public int16 rssi { get { return proxy.rssi; } }
+
+ /**
+ * The object path of the adapter the device belongs to.
+ */
public ObjectPath adapter { owned get { return proxy.adapter; } }
+
+ /**
+ * The Bluetooth device address of the remote device.
+ */
public string address { owned get { return proxy.address; } }
+
+ /**
+ * Proposed icon name.
+ */
public string icon { owned get { return proxy.icon; } }
+
+ /**
+ * Remote Device ID information in modalias format used by the kernel and udev.
+ */
public string modalias { owned get { return proxy.modalias; } }
+
+ /**
+ * The Bluetooth remote name.
+ *
+ * It is always better to use [[email protected]:alias].
+ */
public string name { owned get { return proxy.name; } }
+
+ /**
+ * External appearance of device, as found on GAP service.
+ */
public uint16 appearance { get { return proxy.appearance; } }
+
+ /**
+ * The Bluetooth class of device of the remote device.
+ */
public uint32 class { get { return proxy.class; } }
+
+ /**
+ * Indicates if this device is currently trying to be connected.
+ */
public bool connecting { get; private set; }
+ /**
+ * If set to `true` any incoming connections from the device will be immediately rejected.
+ */
public bool blocked {
get { return proxy.blocked; }
set { proxy.blocked = value; }
}
+ /**
+ * Indicates if the remote is seen as trusted.
+ */
public bool trusted {
get { return proxy.trusted; }
set { proxy.trusted = value; }
}
+ /**
+ * The name alias for the remote device.
+ *
+ * In case no alias is set, it will return the remote device [[email protected]:name].
+ */
public string alias {
owned get { return proxy.alias; }
set { proxy.alias = value; }
}
- public void cancel_pairing() {
- try { proxy.cancel_pairing(); } catch (Error err) { critical(err.message); }
- }
-
- public async void connect_device() {
+ /**
+ * This is a generic method to connect any profiles
+ * the remote device supports that can be connected to.
+ *
+ * Possible errors: `NotReady`, `Failed`, `InProgress`, `AlreadyConnected`.
+ */
+ public async void connect_device() throws Error {
try {
connecting = true;
yield proxy.connect();
- } catch (Error err) {
- critical(err.message);
} finally {
connecting = false;
}
}
- public async void disconnect_device() {
- try { yield proxy.disconnect(); } catch (Error err) { critical(err.message); }
+ /**
+ * This method gracefully disconnects all connected profiles.
+ *
+ * Possible errors: `NotConnected`.
+ */
+ public async void disconnect_device() throws Error {
+ yield proxy.disconnect();
}
- public void connect_profile(string uuid) {
- try { proxy.connect_profile(uuid); } catch (Error err) { critical(err.message); }
+ /**
+ * This method connects a specific profile of this device.
+ * The UUID provided is the remote service UUID for the profile.
+ *
+ * Possible errors: `Failed`, `InProgress`, `InvalidArguments`, `NotAvailable`, `NotReady`.
+ *
+ * @param uuid the remote service UUID.
+ */
+ public void connect_profile(string uuid) throws Error {
+ proxy.connect_profile(uuid);
}
- public void disconnect_profile(string uuid) {
- try { proxy.disconnect_profile(uuid); } catch (Error err) { critical(err.message); }
+ /**
+ * This method disconnects a specific profile of this device.
+ *
+ * Possible errors: `Failed`, `InProgress`, `InvalidArguments`, `NotSupported`.
+ *
+ * @param uuid the remote service UUID.
+ */
+ public void disconnect_profile(string uuid) throws Error {
+ proxy.disconnect_profile(uuid);
}
- public void pair() {
- try { proxy.pair(); } catch (Error err) { critical(err.message); }
+ /**
+ * This method will connect to the remote device and initiate pairing.
+ *
+ * Possible errors: `InvalidArguments`, `Failed`, `AlreadyExists`,
+ * `AuthenticationCanceled`, `AuthenticationFailed`, `AuthenticationRejected`,
+ * `AuthenticationTimeout`, `ConnectionAttemptFailed`.
+ */
+ public void pair() throws Error {
+ proxy.pair();
+ }
+
+ /**
+ * This method can be used to cancel a pairing operation
+ * initiated by [[email protected]].
+ *
+ * Possible errors: `DoesNotExist`, `Failed`.
+ */
+ public void cancel_pairing() throws Error {
+ proxy.cancel_pairing();
}
-}
}
diff --git a/lib/bluetooth/gir.py b/lib/bluetooth/gir.py
new file mode 120000
index 0000000..b5b4f1d
--- /dev/null
+++ b/lib/bluetooth/gir.py
@@ -0,0 +1 @@
+../gir.py \ No newline at end of file
diff --git a/lib/bluetooth/interfaces.vala b/lib/bluetooth/interfaces.vala
new file mode 100644
index 0000000..dcb1c4b
--- /dev/null
+++ b/lib/bluetooth/interfaces.vala
@@ -0,0 +1,46 @@
+[DBus (name = "org.bluez.Adapter1")]
+private interface AstalBluetooth.IAdapter : DBusProxy {
+ public abstract void remove_device(ObjectPath device) throws Error;
+ public abstract void start_discovery() throws Error;
+ public abstract void stop_discovery() throws Error;
+
+ public abstract string[] uuids { owned get; }
+ public abstract bool discoverable { get; set; }
+ public abstract bool discovering { get; }
+ public abstract bool pairable { get; set; }
+ public abstract bool powered { get; set; }
+ public abstract string address { owned get; }
+ public abstract string alias { owned get; set; }
+ public abstract string modalias { owned get; }
+ public abstract string name { owned get; }
+ public abstract uint class { get; }
+ public abstract uint discoverable_timeout { get; set; }
+ public abstract uint pairable_timeout { get; set; }
+}
+
+[DBus (name = "org.bluez.Device1")]
+private interface AstalBluetooth.IDevice : DBusProxy {
+ public abstract void cancel_pairing() throws Error;
+ public abstract async void connect() throws Error;
+ public abstract void connect_profile(string uuid) throws Error;
+ public abstract async void disconnect() throws Error;
+ public abstract void disconnect_profile(string uuid) throws Error;
+ public abstract void pair() throws Error;
+
+ public abstract string[] uuids { owned get; }
+ public abstract bool blocked { get; set; }
+ public abstract bool connected { get; }
+ public abstract bool legacy_pairing { get; }
+ public abstract bool paired { get; }
+ public abstract bool trusted { get; set; }
+ public abstract int16 rssi { get; }
+ public abstract ObjectPath adapter { owned get; }
+ public abstract string address { owned get; }
+ public abstract string alias { owned get; set; }
+ public abstract string icon { owned get; }
+ public abstract string modalias { owned get; }
+ public abstract string name { owned get; }
+ public abstract uint16 appearance { get; }
+ public abstract uint32 class { get; }
+}
+
diff --git a/lib/bluetooth/meson.build b/lib/bluetooth/meson.build
index 934d380..347b463 100644
--- a/lib/bluetooth/meson.build
+++ b/lib/bluetooth/meson.build
@@ -33,34 +33,41 @@ deps = [
dependency('gio-2.0'),
]
-sources = [
- config,
- 'utils.vala',
- 'device.vala',
+sources = [config] + files(
'adapter.vala',
'bluetooth.vala',
-]
+ 'device.vala',
+ 'interfaces.vala',
+ 'utils.vala',
+)
lib = library(
meson.project_name(),
sources,
dependencies: deps,
+ vala_args: ['--vapi-comments'],
vala_header: meson.project_name() + '.h',
vala_vapi: meson.project_name() + '-' + api_version + '.vapi',
- vala_gir: gir,
version: meson.project_version(),
install: true,
- install_dir: [true, true, true, true],
+ install_dir: [true, true, true],
)
-import('pkgconfig').generate(
- lib,
- name: meson.project_name(),
- filebase: meson.project_name() + '-' + api_version,
- version: meson.project_version(),
- subdirs: meson.project_name(),
- requires: deps,
- install_dir: get_option('libdir') / 'pkgconfig',
+pkgs = []
+foreach dep : deps
+ pkgs += ['--pkg=' + dep.name()]
+endforeach
+
+gir_tgt = custom_target(
+ gir,
+ command: [find_program('python3'), files('gir.py'), meson.project_name(), gir]
+ + pkgs
+ + sources,
+ input: sources,
+ depends: lib,
+ output: gir,
+ install: true,
+ install_dir: get_option('datadir') / 'gir-1.0',
)
custom_target(
@@ -73,7 +80,17 @@ custom_target(
],
input: lib,
output: typelib,
- depends: lib,
+ depends: [lib, gir_tgt],
install: true,
install_dir: get_option('libdir') / 'girepository-1.0',
)
+
+import('pkgconfig').generate(
+ lib,
+ name: meson.project_name(),
+ filebase: meson.project_name() + '-' + api_version,
+ version: meson.project_version(),
+ subdirs: meson.project_name(),
+ requires: deps,
+ install_dir: get_option('libdir') / 'pkgconfig',
+)