From f7ca11b202e442e759cca86a70d9c6d027e82e76 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 11 Oct 2013 08:38:51 -0500 Subject: if /dev/rfkill doesn't exist or isn't writable, then try to handle bluetooth toggles simply by toggling bluez Adapters' Powered property --- src/bluetooth.vala | 49 ++++----------------- src/bluez.vala | 121 +++++++++++++++++++++++++++++++++++++++++++++------- src/desktop.vala | 6 +-- src/killswitch.vala | 7 +++ src/phone.vala | 2 +- src/profile.vala | 13 +++--- 6 files changed, 128 insertions(+), 70 deletions(-) diff --git a/src/bluetooth.vala b/src/bluetooth.vala index 100bdf2..b268701 100644 --- a/src/bluetooth.vala +++ b/src/bluetooth.vala @@ -27,22 +27,19 @@ public interface Bluetooth: Object This work as a proxy for "does this hardware support bluetooth?" */ public abstract bool supported { get; protected set; } - /* True if there are any bluetooth adapters powered up on the system. - In short, whether or not this system's bluetooth is "on". */ - public abstract bool powered { get; protected set; } + /* True if bluetooth's enabled on this system. + Bluetooth can be soft-blocked by software and hard-blocked physically, + eg by a laptop's network killswitch */ + public abstract bool enabled { get; protected set; } + + /* Try to enable/disable bluetooth. This can fail if it's overridden + by the system, eg by a laptop's network killswitch */ + public abstract void try_set_enabled (bool b); /* True if our system can be seen by other bluetooth devices */ public abstract bool discoverable { get; protected set; } public abstract void try_set_discoverable (bool discoverable); - /* True if bluetooth's blocked. This can be soft-blocked by software and - * hard-blocked physically, eg by a laptop's network killswitch */ - public abstract bool blocked { get; protected set; } - - /* Try to block/unblock bluetooth. This can fail if it's overridden - by the system, eg by a laptop's network killswitch */ - public abstract void try_set_blocked (bool b); - /* Get a list of the Device structs that we know about */ public abstract List get_devices (); @@ -53,33 +50,3 @@ public interface Bluetooth: Object The device_key argument comes from the Device struct */ public abstract void set_device_connected (uint device_key, bool connected); } - - - -/** - * Base class for Bluetooth objects that use a killswitch to implement - * the 'discoverable' property. - */ -public abstract class KillswitchBluetooth: Object, Bluetooth -{ - private KillSwitch killswitch; - - public KillswitchBluetooth (KillSwitch killswitch) - { - // always sync our 'blocked' property with the one in killswitch - this.killswitch = killswitch; - blocked = killswitch.blocked; - killswitch.notify["blocked"].connect (() => blocked = killswitch.blocked ); - } - - public bool supported { get; protected set; default = false; } - public bool powered { get; protected set; default = false; } - public bool discoverable { get; protected set; default = false; } - public bool blocked { get; protected set; default = true; } - public void try_set_blocked (bool b) { killswitch.try_set_blocked (b); } - - // empty implementations - public abstract void try_set_discoverable (bool b); - public abstract List get_devices (); - public abstract void set_device_connected (uint device_key, bool connected); -} diff --git a/src/bluez.vala b/src/bluez.vala index 8c8c1b6..82f34f4 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -22,12 +22,25 @@ /** * Bluetooth implementaion which uses org.bluez on DBus */ -public class Bluez: KillswitchBluetooth +public class Bluez: Bluetooth, Object { uint next_device_id = 1; org.bluez.Manager manager; org.bluez.Adapter default_adapter; + private bool _powered = false; + + private bool powered { + get { return _powered; } + set { _powered = value; update_enabled(); } + } + + private KillSwitch killswitch = null; + + private string adapter_path = null; + + private DBusConnection bus = null; + /* maps an org.bluez.Device's object_path to the org.bluez.Device proxy */ HashTable path_to_proxy; @@ -42,42 +55,85 @@ public class Bluez: KillswitchBluetooth public Bluez (KillSwitch killswitch) { - base (killswitch); + try + { + bus = Bus.get_sync (BusType.SYSTEM); + } + catch (Error e) + { + critical (@"$(e.message)"); + } - string adapter_path = null; + if (killswitch.is_valid()) + { + this.killswitch = killswitch; + killswitch.notify["blocked"].connect (() => update_enabled()); + update_enabled (); + } id_to_path = new HashTable (direct_hash, direct_equal); id_to_device = new HashTable (direct_hash, direct_equal); path_to_id = new HashTable (str_hash, str_equal); path_to_proxy = new HashTable (str_hash, str_equal); + reset_manager (); + } + + private void reset_manager () + { + string new_adapter_path = null; try { - manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", "/"); + manager = bus.get_proxy_sync ("org.bluez", "/"); - // get the current default adapter & watch for future default adapters - adapter_path = manager.default_adapter (); + // if the default adapter changes, update our connections manager.default_adapter_changed.connect ((object_path) => on_default_adapter_changed (object_path)); + + // if the current adapter disappears, call clear_adapter() + manager.adapter_removed.connect ((object_path) => { + if (object_path == adapter_path) + clear_adapter (); + }); + + // get the current default adapter & watch for future default adapters + new_adapter_path = manager.default_adapter (); } catch (Error e) { critical (@"$(e.message)"); } - on_default_adapter_changed (adapter_path); + on_default_adapter_changed (new_adapter_path); } - private void on_default_adapter_changed (string? object_path) + private void clear_adapter () { - supported = object_path != null; + if (adapter_path != null) + debug (@"clearing adapter; was using $adapter_path"); + + path_to_proxy.remove_all (); + path_to_id.remove_all (); + id_to_path.remove_all (); + id_to_device.remove_all (); + + default_adapter = null; + adapter_path = null; + + discoverable = false; + powered = false; + } + + void on_default_adapter_changed (string? object_path) + { + clear_adapter (); if (object_path != null) try { - debug (@"using default adapter at $object_path"); + adapter_path = object_path; default_adapter = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", - object_path); + adapter_path); default_adapter.property_changed.connect (() => on_default_adapter_properties_changed ()); @@ -104,6 +160,8 @@ public class Bluez: KillswitchBluetooth on_default_adapter_properties_changed (); } + /* When the default adapter's properties change, + update our own properties "powered" and "discoverable" */ private void on_default_adapter_properties_changed () { bool is_discoverable = false; @@ -217,7 +275,6 @@ public class Bluez: KillswitchBluetooth private void device_connect_on_interface (DBusProxy proxy, string interface_name) { - var bus = proxy.get_connection (); var object_path = proxy.get_object_path (); debug (@"trying to connect to $object_path: $(interface_name)"); @@ -359,11 +416,21 @@ public class Bluez: KillswitchBluetooth devices_changed (); } + /* update the 'enabled' property by looking at the killswitch state + and the 'powered' property state */ + void update_enabled () + { + var blocked = (killswitch != null) && killswitch.blocked; + debug (@"in upate_enabled, powered is $powered, blocked is $blocked"); + enabled = powered && !blocked; + } + + //// //// Public API //// - public override void set_device_connected (uint id, bool connected) + public void set_device_connected (uint id, bool connected) { var device = id_to_device.lookup (id); var path = id_to_path.lookup (id); @@ -380,7 +447,7 @@ public class Bluez: KillswitchBluetooth } } - public override void try_set_discoverable (bool b) + public void try_set_discoverable (bool b) { if (discoverable != b) try { @@ -392,8 +459,32 @@ public class Bluez: KillswitchBluetooth } } - public override List get_devices () + public List get_devices () { return id_to_device.get_values(); } + + public bool supported { get; protected set; default = false; } + public bool discoverable { get; protected set; default = false; } + public bool enabled { get; protected set; default = false; } + + public void try_set_enabled (bool b) + { + if (killswitch != null) + { + debug (@"setting killswitch blocked to $(!b)"); + killswitch.try_set_blocked (!b); + } + + if (default_adapter != null) try + { + debug (@"setting bluez Adapter's Powered property to $b"); + default_adapter.set_property ("Powered", new Variant.boolean (b)); + powered = b; + } + catch (Error e) + { + critical (@"$(e.message)"); + } + } } diff --git a/src/desktop.vala b/src/desktop.vala index 7c99a45..a30935a 100644 --- a/src/desktop.vala +++ b/src/desktop.vala @@ -82,7 +82,7 @@ class Desktop: Profile void update_visibility () { - visible = bluetooth.powered && !bluetooth.blocked && settings.get_boolean("visible"); + visible = bluetooth.enabled && settings.get_boolean("visible"); } /// @@ -229,10 +229,6 @@ class Desktop: Profile bluetooth.notify["discoverable"].connect (() => action.set_state (bluetooth.discoverable)); - action.set_enabled (bluetooth.powered); - bluetooth.notify["powered"].connect (() - => action.set_enabled (bluetooth.powered)); - return action; } diff --git a/src/killswitch.vala b/src/killswitch.vala index 08ee0cc..167d189 100644 --- a/src/killswitch.vala +++ b/src/killswitch.vala @@ -26,6 +26,8 @@ */ public interface KillSwitch: Object { + public abstract bool is_valid (); + public abstract bool blocked { get; protected set; } /* Try to block/unblock bluetooth. @@ -109,6 +111,11 @@ public class RfKillSwitch: KillSwitch, Object } } + public bool is_valid () + { + return fd != -1; + } + private bool on_channel_event (IOChannel source, IOCondition condition) { read_event (); diff --git a/src/phone.vala b/src/phone.vala index 18c698c..2b0b96b 100644 --- a/src/phone.vala +++ b/src/phone.vala @@ -53,7 +53,7 @@ class Phone: Profile void update_visibility () { - visible = bluetooth.powered && !bluetooth.blocked; + visible = bluetooth.enabled; } /// diff --git a/src/profile.vala b/src/profile.vala index c32e46b..584af56 100644 --- a/src/profile.vala +++ b/src/profile.vala @@ -123,16 +123,16 @@ class Profile: Object { var action = new SimpleAction.stateful ("bluetooth-enabled", null, - !bluetooth.blocked); + bluetooth.enabled); action.activate.connect (() => action.change_state (!action.get_state().get_boolean())); action.change_state.connect ((action, requestedValue) - => bluetooth.try_set_blocked (!requestedValue.get_boolean())); + => bluetooth.try_set_enabled (requestedValue.get_boolean())); - bluetooth.notify["blocked"].connect (() - => action.set_state (!bluetooth.blocked)); + bluetooth.notify["enabled"].connect (() + => action.set_state (bluetooth.enabled)); return action; } @@ -144,12 +144,9 @@ class Profile: Object protected Variant action_state_for_root () { - var blocked = bluetooth.blocked; - var powered = bluetooth.powered; - string a11y; string icon_name; - if (powered && !blocked) + if (bluetooth.enabled) { a11y = "Bluetooth (on)"; icon_name = "bluetooth-active"; -- cgit v1.2.3 From 5a14c4f435040a77f4fda33a537e0029e7e678fe Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Oct 2013 12:50:05 -0500 Subject: if killswitch exists and is valid, prefer its use over toggling org.bluez.Adapter's Powered property --- src/bluez.vala | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/bluez.vala b/src/bluez.vala index 82f34f4..472a16d 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -53,7 +53,7 @@ public class Bluez: Bluetooth, Object /* maps our arbitrary unique id to a Bluetooth.Device struct for public consumption */ HashTable id_to_device; - public Bluez (KillSwitch killswitch) + public Bluez (KillSwitch? killswitch) { try { @@ -64,7 +64,7 @@ public class Bluez: Bluetooth, Object critical (@"$(e.message)"); } - if (killswitch.is_valid()) + if ((killswitch != null) && (killswitch.is_valid())) { this.killswitch = killswitch; killswitch.notify["blocked"].connect (() => update_enabled()); @@ -475,16 +475,18 @@ public class Bluez: Bluetooth, Object debug (@"setting killswitch blocked to $(!b)"); killswitch.try_set_blocked (!b); } - - if (default_adapter != null) try - { - debug (@"setting bluez Adapter's Powered property to $b"); - default_adapter.set_property ("Powered", new Variant.boolean (b)); - powered = b; - } - catch (Error e) + else { - critical (@"$(e.message)"); + if (default_adapter != null) try + { + debug (@"setting bluez Adapter's Powered property to $b"); + default_adapter.set_property ("Powered", new Variant.boolean (b)); + powered = b; + } + catch (Error e) + { + critical (@"$(e.message)"); + } } } } -- cgit v1.2.3 From e15cd36f96ae3108faf50da2c613d4a3e3d44359 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Oct 2013 18:25:57 -0500 Subject: when listening to notify events from bluetooth to update desktop indicator visibility, add a specifier for which event to monitor --- src/desktop.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop.vala b/src/desktop.vala index a30935a..4e36273 100644 --- a/src/desktop.vala +++ b/src/desktop.vala @@ -66,7 +66,7 @@ class Desktop: Profile // know when to show the indicator & when to hide it settings.changed["visible"].connect (()=> update_visibility()); - bluetooth.notify.connect (() => update_visibility()); + bluetooth.notify["enabled"].connect (() => update_visibility()); update_visibility (); // when devices change, rebuild our device section -- cgit v1.2.3 From 46d4ad6f0e470049fee1236e93f2e8f8191da72b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Oct 2013 18:27:17 -0500 Subject: omit the rfkill killswitch altogether, leaving on/off to bluez via org.bluez.Adapter's Powered property --- src/main.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.vala b/src/main.vala index caee3b3..828a96b 100644 --- a/src/main.vala +++ b/src/main.vala @@ -26,7 +26,7 @@ public static int main (string[] args) Intl.textdomain (Config.GETTEXT_PACKAGE); // create the backend - var bluetooth = new Bluez (new RfKillSwitch ()); + var bluetooth = new Bluez (null); // start the service var service = new Service (bluetooth); -- cgit v1.2.3 From 73cc5b06408e95c0401cb3cd3c2249f9376f2606 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Oct 2013 18:33:59 -0500 Subject: make org.bluez.Adapter's set_property() call nonblocking --- src/bluez.vala | 23 ++++++----------------- src/org-bluez.vala | 2 +- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/bluez.vala b/src/bluez.vala index 472a16d..1a1f837 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -449,13 +449,9 @@ public class Bluez: Bluetooth, Object public void try_set_discoverable (bool b) { - if (discoverable != b) try + if (discoverable != b) { - default_adapter.set_property ("Discoverable", new Variant.boolean (b)); - } - catch (Error e) - { - critical (@"$(e.message)"); + default_adapter.set_property.begin ("Discoverable", new Variant.boolean (b)); } } @@ -475,18 +471,11 @@ public class Bluez: Bluetooth, Object debug (@"setting killswitch blocked to $(!b)"); killswitch.try_set_blocked (!b); } - else + else if (default_adapter != null) { - if (default_adapter != null) try - { - debug (@"setting bluez Adapter's Powered property to $b"); - default_adapter.set_property ("Powered", new Variant.boolean (b)); - powered = b; - } - catch (Error e) - { - critical (@"$(e.message)"); - } + debug (@"setting bluez Adapter's Powered property to $b"); + default_adapter.set_property.begin ("Powered", new Variant.boolean (b)); + powered = b; } } } diff --git a/src/org-bluez.vala b/src/org-bluez.vala index 49c8e4d..4bd267f 100644 --- a/src/org-bluez.vala +++ b/src/org-bluez.vala @@ -69,7 +69,7 @@ namespace org { public abstract GLib.HashTable get_properties() throws DBusError, IOError; [DBus (name = "SetProperty")] - public abstract void set_property(string name, GLib.Variant value) throws DBusError, IOError; + public abstract async void set_property(string name, GLib.Variant value) throws DBusError, IOError; [DBus (name = "RequestSession")] public abstract void request_session() throws DBusError, IOError; -- cgit v1.2.3