From cf894302767d5ec483b5f8002bb796a284895bbf Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 1 Aug 2013 18:21:05 -0500 Subject: add a bluetooth backend to track bluetooth being enabled, being hard/soft blocked, and its devices. --- Makefile.am | 6 +- configure.ac | 8 -- data/Makefile.am | 2 +- debian/control | 2 - src/Makefile.am | 5 + src/bluetooth.vala | 53 ++++++++++ src/bluez.vala | 97 +++++++++++++++++ src/desktop.vala | 121 +++++++++++++++------ src/killswitch.vala | 147 ++++++++++++++++++++++++++ src/libido3-0.1.vapi | 10 -- src/main.vala | 4 +- src/org-bluez.vala | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/phone.vala | 2 +- src/service.vala | 21 ++-- vapi/rfkill.vapi | 44 ++++++++ 15 files changed, 748 insertions(+), 67 deletions(-) create mode 100644 src/bluetooth.vala create mode 100644 src/bluez.vala create mode 100644 src/killswitch.vala delete mode 100644 src/libido3-0.1.vapi create mode 100644 src/org-bluez.vala create mode 100644 vapi/rfkill.vapi diff --git a/Makefile.am b/Makefile.am index 4fa38ad..31ba5e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,9 @@ SUBDIRS = data po src -EXTRA_DIST = autogen.sh NEWS +EXTRA_DIST = \ + autogen.sh \ + NEWS \ + vapi/rfkill.vapi \ + vapi/config.vapi DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall diff --git a/configure.ac b/configure.ac index 3179a1e..15f09ef 100644 --- a/configure.ac +++ b/configure.ac @@ -21,14 +21,6 @@ PKG_CHECK_MODULES(INDICATOR_BLUETOOTH_SERVICE, [ dbusmenu-gtk3-0.4 ]) -PKG_CHECK_MODULES(INDICATOR_BLUETOOTH, [ - glib-2.0 - gtk+-3.0 - indicator3-0.4 - dbusmenu-gtk3-0.4 - libido3-0.1 -]) - dnl ############################## dnl # Custom Junk dnl ############################## diff --git a/data/Makefile.am b/data/Makefile.am index d5f40aa..fc726a7 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1,7 +1,7 @@ # the indicator bus file indicatorsdir = $(prefix)/share/unity/indicators -dist_indicators_DATA = com.canonical.indicator.datetime +dist_indicators_DATA = com.canonical.indicator.bluetooth # the dbus service file dbus_servicesdir = $(datadir)/dbus-1/services diff --git a/debian/control b/debian/control index 07bc74d..a08015d 100644 --- a/debian/control +++ b/debian/control @@ -8,9 +8,7 @@ Build-Depends: debhelper (>= 9.0), gnome-common, libdbusmenu-gtk3-dev, libglib2.0-dev, - libgnome-bluetooth-dev, libgtk-3-dev, - libido3-0.1-dev, libindicator3-dev, valac (>=0.18), Standards-Version: 3.9.4 diff --git a/src/Makefile.am b/src/Makefile.am index ed2c976..720c981 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,10 +2,14 @@ pkglibexec_PROGRAMS = indicator-bluetooth-service indicator_bluetooth_service_SOURCES = \ indicator3-0.4.vapi \ + org-bluez.vala \ + bluetooth.vala \ + bluez.vala \ desktop.vala \ main.vala \ menu.vala \ phone.vala \ + killswitch.vala \ service.vala indicator_bluetooth_service_VALAFLAGS = \ @@ -14,6 +18,7 @@ indicator_bluetooth_service_VALAFLAGS = \ --vapidir=./ \ --pkg gnome-bluetooth-1.0 \ --pkg config \ + --pkg rfkill \ --pkg posix \ --pkg glib-2.0 \ --pkg gtk+-3.0 \ diff --git a/src/bluetooth.vala b/src/bluetooth.vala new file mode 100644 index 0000000..ad5ee09 --- /dev/null +++ b/src/bluetooth.vala @@ -0,0 +1,53 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +public class Bluetooth: Object +{ + /*** + **** Properties + ***/ + + public bool discoverable { get; protected set; default = false; } + public virtual void try_set_discoverable (bool b) {} + + public bool powered { get; protected set; default = false; } + + public bool blocked { get; protected set; default = true; } + public virtual void try_set_blocked (bool b) { + kill_switch.try_set_blocked (b); + } + + /*** + **** Killswitch Implementation + ***/ + + protected KillSwitch kill_switch; + + public Bluetooth (KillSwitch kill_switch) + { + this.kill_switch = kill_switch; + + message ("changing blocked to %d", (int)!this.kill_switch.blocked); + blocked = this.kill_switch.blocked; + kill_switch.notify["blocked"].connect (() => { + message ("bluetooth changing blocked to %d", (int)kill_switch.blocked); + this.blocked = kill_switch.blocked; + }); + } +} diff --git a/src/bluez.vala b/src/bluez.vala new file mode 100644 index 0000000..178cc57 --- /dev/null +++ b/src/bluez.vala @@ -0,0 +1,97 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +public class Bluez: Bluetooth +{ + private org.bluez.Manager manager; + private org.bluez.Adapter default_adapter; + + public Bluez (KillSwitch kill_switch) + { + string default_adapter_object_path = null; + + base (kill_switch); + + try + { + manager = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", "/"); + + manager.default_adapter_changed.connect ((object_path) => on_default_adapter_changed (object_path)); + default_adapter_object_path = manager.default_adapter (); + } + catch (Error e) + { + critical ("%s", e.message); + } + + on_default_adapter_changed (default_adapter_object_path); + } + + private void on_default_adapter_changed (string? object_path) + { + if (object_path != null) try + { + message ("using default adapter at %s", object_path); + this.default_adapter = Bus.get_proxy_sync (BusType.SYSTEM, "org.bluez", object_path); + this.default_adapter.property_changed.connect(() => this.on_default_adapter_properties_changed()); + } + catch (Error e) + { + critical ("%s", e.message); + } + + this.on_default_adapter_properties_changed (); + } + + private void on_default_adapter_properties_changed () + { + bool is_discoverable = false; + bool is_powered = false; + + if (this.default_adapter != null) try + { + var properties = this.default_adapter.get_properties(); + + var v = properties.lookup("Discoverable"); + is_discoverable = (v != null) && v.get_boolean (); + + v = properties.lookup("Powered"); + is_powered = (v != null) && v.get_boolean (); + } + catch (Error e) + { + critical ("%s", e.message); + } + + this.powered = is_powered; + this.discoverable = is_discoverable; + } + + public override void try_set_discoverable (bool b) + { + if (discoverable != b) try + { + this.default_adapter.set_property ("Discoverable", new Variant.boolean(b)); + } + catch (Error e) + { + critical ("%s", e.message); + } + } +} diff --git a/src/desktop.vala b/src/desktop.vala index bd005f5..351770a 100644 --- a/src/desktop.vala +++ b/src/desktop.vala @@ -20,80 +20,133 @@ class DesktopMenu: BluetoothMenu { private Settings settings; + private Bluetooth bluetooth; - private Action[] actions; + private SimpleAction root_action; + private Action[] all_actions; public override void add_actions_to_group (SimpleActionGroup group) { base.add_actions_to_group (group); - for (var i=0; i { message("visible toggled"); }); - this.actions = {}; - this.actions += new SimpleAction.stateful ("root-desktop", null, action_state_for_root()); - this.actions += create_settings_action (); - this.actions += create_wizard_action (); + this.root_action = new SimpleAction.stateful ("root-desktop", null, action_state_for_root()); + + this.all_actions = {}; + this.all_actions += this.root_action; + this.all_actions += create_enabled_action (bluetooth); + this.all_actions += create_discoverable_action (bluetooth); + this.all_actions += create_settings_action (); + this.all_actions += create_wizard_action (); + + bluetooth.notify.connect (() => this.update_root_action_state()); + settings.changed["visible"].connect (()=> this.update_root_action_state()); + + Menu section; + MenuItem item; - var section = new Menu (); + section = new Menu (); + item = new MenuItem ("Bluetooth", "indicator.desktop-enabled"); + item.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.switch"); + section.append_item (item); + item = new MenuItem ("Visible", "indicator.desktop-discoverable"); + item.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.switch"); + section.append_item (item); + this.menu.append_section (null, section); + + section = new Menu (); section.append (_("Set Up New Deviceā€¦"), "indicator.desktop-wizard"); section.append (_("Bluetooth Settingsā€¦"), "indicator.desktop-settings"); this.menu.append_section (null, section); } - Action create_wizard_action () + Action create_enabled_action (Bluetooth bluetooth) { - var action = new SimpleAction ("desktop-wizard", null); + var action = new SimpleAction.stateful ("desktop-enabled", null, !bluetooth.blocked); + action.activate.connect (() => action.set_state (!action.get_state().get_boolean())); + action.notify["state"].connect (() => bluetooth.try_set_blocked (!action.get_state().get_boolean())); + bluetooth.notify["blocked"].connect (() => action.set_state (!bluetooth.blocked)); + return action; + } - action.activate.connect ((action, param) => { - try { - Process.spawn_command_line_async ("bluetooth-wizard"); - } catch (Error e) { - warning ("unable to launch settings: %s", e.message); - } - }); + Action create_discoverable_action (Bluetooth bluetooth) + { + var action = new SimpleAction.stateful ("desktop-discoverable", null, bluetooth.discoverable); + action.set_enabled (bluetooth.powered); + action.activate.connect (() => action.set_state (!action.get_state().get_boolean())); + action.notify["state"].connect (() => bluetooth.try_set_discoverable (action.get_state().get_boolean())); + bluetooth.notify["discoverable"].connect (() => action.set_state (bluetooth.discoverable)); + bluetooth.notify["powered"].connect (() => action.set_enabled (bluetooth.powered)); + return action; + } + void spawn_command_line_async (string command) + { + try { + Process.spawn_command_line_async (command); + } catch (Error e) { + warning ("unable to launch '%s': %s", command, e.message); + } + } + + Action create_wizard_action () + { + var action = new SimpleAction ("desktop-wizard", null); + action.activate.connect (() => spawn_command_line_async ("bluetooth-wizard")); return action; } Action create_settings_action () { var action = new SimpleAction ("desktop-settings", null); - - action.activate.connect ((action, param) => { - try { - Process.spawn_command_line_async ("gnome-control-center bluetooth"); - } catch (Error e) { - warning ("unable to launch settings: %s", e.message); - } - }); - + action.activate.connect (() => spawn_command_line_async ("gnome-control-center bluetooth")); return action; } protected Variant action_state_for_root () { - var label = "Hello"; // FIXME - var a11y = "Hello"; // FIXME - var visible = true; // FIXME + bool blocked = bluetooth.blocked; + bool powered = bluetooth.powered; + + settings.changed["visible"].connect (()=> this.update_root_action_state()); + + bool visible = powered && settings.get_boolean("visible"); + + string a11y; + string icon_name; + if (powered && !blocked) + { + a11y = "Bluetooth (on)"; + icon_name = "bluetooth-active"; + } + else + { + a11y = "Bluetooth (off)"; + icon_name = "bluetooth-disabled"; + } - string icon_name = "bluetooth-active"; // FIXME: enabled, disabled, connected, etc. -//indicator-bluetooth-service.vala: bluetooth_service._icon_name = enabled ? "bluetooth-active" : "bluetooth-disabled"; var icon = new ThemedIcon.with_default_fallbacks (icon_name); var builder = new VariantBuilder (new VariantType ("a{sv}")); builder.add ("{sv}", "visible", new Variant ("b", visible)); - builder.add ("{sv}", "label", new Variant ("s", label)); builder.add ("{sv}", "accessible-desc", new Variant ("s", a11y)); builder.add ("{sv}", "icon", icon.serialize()); return builder.end (); } + + void update_root_action_state () + { + root_action.set_state (action_state_for_root ()); + } } diff --git a/src/killswitch.vala b/src/killswitch.vala new file mode 100644 index 0000000..92b1a3c --- /dev/null +++ b/src/killswitch.vala @@ -0,0 +1,147 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +/** + * Monitors whether or not bluetooth is blocked, + * either by software (e.g., a session configuration setting) + * or by hardware (e.g., user disabled it via a physical switch on her laptop) + */ +public class KillSwitch: Object +{ + public bool blocked { get; protected set; default = false; } + + public void try_set_blocked (bool blocked) + { + return_if_fail (this.blocked != blocked); + + // write a 'soft kill' event to fkill + var event = Linux.RfKillEvent() { + op = Linux.RfKillOp.CHANGE_ALL, + type = Linux.RfKillType.BLUETOOTH, + soft = (uint8)blocked + }; + + var bwritten = Posix.write (fd, &event, sizeof(Linux.RfKillEvent)); + if (bwritten == -1) + warning ("Could not write rfkill event: %s", strerror(errno)); + } + + /*** + **** Past this point, it's all RfKill implementation details... + ***/ + + private class Entry + { + public uint32 idx; + public Linux.RfKillType type; + public bool soft; + public bool hard; + } + + private HashTable entries; + private int fd; + private IOChannel channel; + private uint watch; + + private bool calculate_blocked () + { + foreach (Entry entry in entries.get_values()) + if (entry.soft || entry.hard) + return true; + + return false; + } + + ~KillSwitch () + { + Source.remove (watch); + Posix.close (fd); + } + + public KillSwitch () + { + entries = new HashTable(direct_hash, direct_equal); + + var path = "/dev/rfkill"; + fd = Posix.open (path, Posix.O_RDWR | Posix.O_NONBLOCK ); + message ("fd is %d", fd); + if (fd == -1) + { + warning (@"Can't open $path: $(strerror(errno)); KillSwitch disable"); + } + else + { + // read everything that's already there, then watch for more + while (read_event()); + channel = new IOChannel.unix_new (fd); + watch = channel.add_watch (IOCondition.IN, on_channel_event); + } + } + + private bool on_channel_event (IOChannel source, IOCondition condition) + { + read_event (); + return true; + } + + private bool read_event () + { + assert (fd != -1); + + var event = Linux.RfKillEvent(); + var n = sizeof (Linux.RfKillEvent); + var bytesread = Posix.read (fd, &event, n); + + if (bytesread == n) + { + process_event (event); + return true; + } + + return false; + } + + private void process_event (Linux.RfKillEvent event) + { + // we only want things that affect bluetooth + if ((event.type != Linux.RfKillType.ALL) && + (event.type != Linux.RfKillType.BLUETOOTH)) + return; + + switch (event.op) + { + case Linux.RfKillOp.CHANGE: + case Linux.RfKillOp.ADD: + Entry entry = new Entry (); + entry.idx = event.idx; + entry.type = event.type; + entry.soft = event.soft != 0; + entry.hard = event.hard != 0; + entries.insert (entry.idx, entry); + break; + + case Linux.RfKillOp.DEL: + entries.remove (event.idx); + break; + } + + // update the 'blocked' property + blocked = calculate_blocked (); + } +} diff --git a/src/libido3-0.1.vapi b/src/libido3-0.1.vapi deleted file mode 100644 index e6a8953..0000000 --- a/src/libido3-0.1.vapi +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ido -{ - [CCode (cheader_filename = "libido/idoswitchmenuitem.h")] - public class SwitchMenuItem : Gtk.CheckMenuItem - { - [CCode (has_construct_function = false)] - public SwitchMenuItem (); - public Gtk.Container content_area { get; } - } -} diff --git a/src/main.vala b/src/main.vala index 1df55c3..7af617d 100644 --- a/src/main.vala +++ b/src/main.vala @@ -7,7 +7,9 @@ main (string[] args) Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR); Intl.textdomain (Config.GETTEXT_PACKAGE); - var service = new BluetoothIndicator (); + var bluetooth = new Bluez (new KillSwitch ()); + var service = new BluetoothIndicator (bluetooth); + service.run (); return Posix.EXIT_SUCCESS; diff --git a/src/org-bluez.vala b/src/org-bluez.vala new file mode 100644 index 0000000..49c8e4d --- /dev/null +++ b/src/org-bluez.vala @@ -0,0 +1,293 @@ +/* Generated by vala-dbus-binding-tool 0.4.0. Do not modify! */ +/* Generated with: vala-dbus-binding-tool --gdbus --directory=. */ +using GLib; + +namespace org { + + namespace bluez { + + [DBus (name = "org.bluez.Manager", timeout = 120000)] + public interface Manager : GLib.Object { + + [DBus (name = "GetProperties")] + public abstract GLib.HashTable get_properties() throws DBusError, IOError; + + [DBus (name = "DefaultAdapter")] + public abstract GLib.ObjectPath default_adapter() throws DBusError, IOError; + + [DBus (name = "FindAdapter")] + public abstract GLib.ObjectPath find_adapter(string pattern) throws DBusError, IOError; + + [DBus (name = "ListAdapters")] + public abstract GLib.ObjectPath[] list_adapters() throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "AdapterAdded")] + public signal void adapter_added(GLib.ObjectPath adapter); + + [DBus (name = "AdapterRemoved")] + public signal void adapter_removed(GLib.ObjectPath adapter); + + [DBus (name = "DefaultAdapterChanged")] + public signal void default_adapter_changed(GLib.ObjectPath adapter); + } + + [DBus (name = "org.bluez.Manager", timeout = 120000)] + public interface ManagerSync : GLib.Object { + + [DBus (name = "GetProperties")] + public abstract GLib.HashTable get_properties() throws DBusError, IOError; + + [DBus (name = "DefaultAdapter")] + public abstract GLib.ObjectPath default_adapter() throws DBusError, IOError; + + [DBus (name = "FindAdapter")] + public abstract GLib.ObjectPath find_adapter(string pattern) throws DBusError, IOError; + + [DBus (name = "ListAdapters")] + public abstract GLib.ObjectPath[] list_adapters() throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "AdapterAdded")] + public signal void adapter_added(GLib.ObjectPath adapter); + + [DBus (name = "AdapterRemoved")] + public signal void adapter_removed(GLib.ObjectPath adapter); + + [DBus (name = "DefaultAdapterChanged")] + public signal void default_adapter_changed(GLib.ObjectPath adapter); + } + + [DBus (name = "org.bluez.Adapter", timeout = 120000)] + public interface Adapter : GLib.Object { + + [DBus (name = "GetProperties")] + 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; + + [DBus (name = "RequestSession")] + public abstract void request_session() throws DBusError, IOError; + + [DBus (name = "ReleaseSession")] + public abstract void release_session() throws DBusError, IOError; + + [DBus (name = "StartDiscovery")] + public abstract void start_discovery() throws DBusError, IOError; + + [DBus (name = "StopDiscovery")] + public abstract void stop_discovery() throws DBusError, IOError; + + [DBus (name = "ListDevices")] + public abstract GLib.ObjectPath[] list_devices() throws DBusError, IOError; + + [DBus (name = "CreateDevice")] + public abstract GLib.ObjectPath create_device(string address) throws DBusError, IOError; + + [DBus (name = "CreatePairedDevice")] + public abstract GLib.ObjectPath create_paired_device(string address, GLib.ObjectPath agent, string capability) throws DBusError, IOError; + + [DBus (name = "CancelDeviceCreation")] + public abstract void cancel_device_creation(string address) throws DBusError, IOError; + + [DBus (name = "RemoveDevice")] + public abstract void remove_device(GLib.ObjectPath device) throws DBusError, IOError; + + [DBus (name = "FindDevice")] + public abstract GLib.ObjectPath find_device(string address) throws DBusError, IOError; + + [DBus (name = "RegisterAgent")] + public abstract void register_agent(GLib.ObjectPath agent, string capability) throws DBusError, IOError; + + [DBus (name = "UnregisterAgent")] + public abstract void unregister_agent(GLib.ObjectPath agent) throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "DeviceCreated")] + public signal void device_created(GLib.ObjectPath device); + + [DBus (name = "DeviceRemoved")] + public signal void device_removed(GLib.ObjectPath device); + + [DBus (name = "DeviceFound")] + public signal void device_found(string address, GLib.HashTable values); + + [DBus (name = "DeviceDisappeared")] + public signal void device_disappeared(string address); + } + + [DBus (name = "org.bluez.Adapter", timeout = 120000)] + public interface AdapterSync : GLib.Object { + + [DBus (name = "GetProperties")] + 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; + + [DBus (name = "RequestSession")] + public abstract void request_session() throws DBusError, IOError; + + [DBus (name = "ReleaseSession")] + public abstract void release_session() throws DBusError, IOError; + + [DBus (name = "StartDiscovery")] + public abstract void start_discovery() throws DBusError, IOError; + + [DBus (name = "StopDiscovery")] + public abstract void stop_discovery() throws DBusError, IOError; + + [DBus (name = "ListDevices")] + public abstract GLib.ObjectPath[] list_devices() throws DBusError, IOError; + + [DBus (name = "CreateDevice")] + public abstract GLib.ObjectPath create_device(string address) throws DBusError, IOError; + + [DBus (name = "CreatePairedDevice")] + public abstract GLib.ObjectPath create_paired_device(string address, GLib.ObjectPath agent, string capability) throws DBusError, IOError; + + [DBus (name = "CancelDeviceCreation")] + public abstract void cancel_device_creation(string address) throws DBusError, IOError; + + [DBus (name = "RemoveDevice")] + public abstract void remove_device(GLib.ObjectPath device) throws DBusError, IOError; + + [DBus (name = "FindDevice")] + public abstract GLib.ObjectPath find_device(string address) throws DBusError, IOError; + + [DBus (name = "RegisterAgent")] + public abstract void register_agent(GLib.ObjectPath agent, string capability) throws DBusError, IOError; + + [DBus (name = "UnregisterAgent")] + public abstract void unregister_agent(GLib.ObjectPath agent) throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "DeviceCreated")] + public signal void device_created(GLib.ObjectPath device); + + [DBus (name = "DeviceRemoved")] + public signal void device_removed(GLib.ObjectPath device); + + [DBus (name = "DeviceFound")] + public signal void device_found(string address, GLib.HashTable values); + + [DBus (name = "DeviceDisappeared")] + public signal void device_disappeared(string address); + } + + [DBus (name = "org.bluez.Agent", timeout = 120000)] + public interface Agent : GLib.Object { + + [DBus (name = "Authorize")] + public abstract void authorize(GLib.ObjectPath device, string uuid) throws DBusError, IOError; + + [DBus (name = "RequestPinCode")] + public abstract string request_pin_code(GLib.ObjectPath device) throws DBusError, IOError; + + [DBus (name = "DisplayPasskey")] + public abstract void display_passkey(GLib.ObjectPath device, uint passkey) throws DBusError, IOError; + + [DBus (name = "Release")] + public abstract void release() throws DBusError, IOError; + + [DBus (name = "Cancel")] + public abstract void cancel() throws DBusError, IOError; + + [DBus (name = "RequestConfirmation")] + public abstract void request_confirmation(GLib.ObjectPath device, uint passkey) throws DBusError, IOError; + + [DBus (name = "ConfirmModeChange")] + public abstract void confirm_mode_change(string mode) throws DBusError, IOError; + + [DBus (name = "RequestPasskey")] + public abstract uint request_passkey(GLib.ObjectPath device) throws DBusError, IOError; + } + + [DBus (name = "org.bluez.Agent", timeout = 120000)] + public interface AgentSync : GLib.Object { + + [DBus (name = "Authorize")] + public abstract void authorize(GLib.ObjectPath device, string uuid) throws DBusError, IOError; + + [DBus (name = "RequestPinCode")] + public abstract string request_pin_code(GLib.ObjectPath device) throws DBusError, IOError; + + [DBus (name = "DisplayPasskey")] + public abstract void display_passkey(GLib.ObjectPath device, uint passkey) throws DBusError, IOError; + + [DBus (name = "Release")] + public abstract void release() throws DBusError, IOError; + + [DBus (name = "Cancel")] + public abstract void cancel() throws DBusError, IOError; + + [DBus (name = "RequestConfirmation")] + public abstract void request_confirmation(GLib.ObjectPath device, uint passkey) throws DBusError, IOError; + + [DBus (name = "ConfirmModeChange")] + public abstract void confirm_mode_change(string mode) throws DBusError, IOError; + + [DBus (name = "RequestPasskey")] + public abstract uint request_passkey(GLib.ObjectPath device) throws DBusError, IOError; + } + + [DBus (name = "org.bluez.Device", timeout = 120000)] + public interface Device : GLib.Object { + + [DBus (name = "GetProperties")] + 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; + + [DBus (name = "DiscoverServices")] + public abstract GLib.HashTable discover_services(string pattern) throws DBusError, IOError; + + [DBus (name = "CancelDiscovery")] + public abstract void cancel_discovery() throws DBusError, IOError; + + [DBus (name = "Disconnect")] + public abstract void disconnect() throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "DisconnectRequested")] + public signal void disconnect_requested(); + } + + [DBus (name = "org.bluez.Device", timeout = 120000)] + public interface DeviceSync : GLib.Object { + + [DBus (name = "GetProperties")] + 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; + + [DBus (name = "DiscoverServices")] + public abstract GLib.HashTable discover_services(string pattern) throws DBusError, IOError; + + [DBus (name = "CancelDiscovery")] + public abstract void cancel_discovery() throws DBusError, IOError; + + [DBus (name = "Disconnect")] + public abstract void disconnect() throws DBusError, IOError; + + [DBus (name = "PropertyChanged")] + public signal void property_changed(string name, GLib.Variant value); + + [DBus (name = "DisconnectRequested")] + public signal void disconnect_requested(); + } + } +} diff --git a/src/phone.vala b/src/phone.vala index 2abcf11..a2a9917 100644 --- a/src/phone.vala +++ b/src/phone.vala @@ -29,7 +29,7 @@ class PhoneMenu: BluetoothMenu group.insert (actions[i]); } - public PhoneMenu () + public PhoneMenu (Bluetooth bluetooth) { base ("phone"); diff --git a/src/service.vala b/src/service.vala index b6ae0f3..0f3d779 100644 --- a/src/service.vala +++ b/src/service.vala @@ -28,24 +28,27 @@ public class BluetoothIndicator private List device_items; private Dbusmenu.Menuitem menu; - public BluetoothIndicator () throws Error + public BluetoothIndicator (Bluetooth bluetooth) { - var phone = new PhoneMenu (); - var desktop = new DesktopMenu (); + var phone = new PhoneMenu (bluetooth); + var desktop = new DesktopMenu (bluetooth); - this.menus = new HashTable (str_hash, str_equal); - this.menus.insert ("phone", phone); - this.menus.insert ("desktop", desktop); + this.menus = new HashTable (str_hash, str_equal); + this.menus.insert ("phone", phone); + this.menus.insert ("desktop", desktop); - this.actions = new SimpleActionGroup (); - phone.add_actions_to_group (this.actions); - desktop.add_actions_to_group (this.actions); + this.actions = new SimpleActionGroup (); + phone.add_actions_to_group (this.actions); + desktop.add_actions_to_group (this.actions); } private void init_for_bus (DBusConnection bus) { this.bus = bus; + /// + /// + indicator_service = new Indicator.Service ("com.canonical.indicator.bluetooth.old"); menu_server = new Dbusmenu.Server ("/com/canonical/indicator/bluetooth/menu"); diff --git a/vapi/rfkill.vapi b/vapi/rfkill.vapi new file mode 100644 index 0000000..7bfd16d --- /dev/null +++ b/vapi/rfkill.vapi @@ -0,0 +1,44 @@ +// (C) Michael 'Mickey' Lauer +// LGPL2 +// scheduled for inclusion in linux.vapi + +namespace Linux +{ + /* + * RfKill + */ + [CCode (cname = "struct rfkill_event", cheader_filename = "linux/rfkill.h")] + public struct RfKillEvent { + public uint32 idx; + public RfKillType type; + public RfKillOp op; + public uint8 soft; + public uint8 hard; + } + + [CCode (cname = "guint8", cprefix = "RFKILL_OP_", cheader_filename = "linux/rfkill.h")] + public enum RfKillOp { + ADD, + DEL, + CHANGE, + CHANGE_ALL + } + + [CCode (cname = "guint8", cprefix = "RFKILL_STATE_", cheader_filename = "linux/rfkill.h")] + public enum RfKillState { + SOFT_BLOCKED, + UNBLOCKED, + HARD_BLOCKED + } + + [CCode (cname = "guint8", cprefix = "RFKILL_TYPE_", cheader_filename = "linux/rfkill.h")] + public enum RfKillType { + ALL, + WLAN, + BLUETOOTH, + UWB, + WIMAX, + WWAN + } + +} /* namespace Linux */ -- cgit v1.2.3