From 4993d0aae0511ae56a830fe8b51b1cde5723a1a8 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 6 Dec 2012 15:35:57 +1300 Subject: Make into a proper indicator --- src/indicator-bluetooth.vala | 407 +++++++------------------------------------ 1 file changed, 64 insertions(+), 343 deletions(-) (limited to 'src/indicator-bluetooth.vala') diff --git a/src/indicator-bluetooth.vala b/src/indicator-bluetooth.vala index 9f7468a..3881fc7 100644 --- a/src/indicator-bluetooth.vala +++ b/src/indicator-bluetooth.vala @@ -9,376 +9,97 @@ * license. */ -public class BluetoothIndicator : AppIndicator.Indicator +public class BluetoothIndicator : Indicator.Object { - private GnomeBluetooth.Client client; - private GnomeBluetooth.Killswitch killswitch; - private bool updating_killswitch = false; - private Gtk.MenuItem status_item; - private Gtk.MenuItem enable_item; - private bool enable_value = false; - private Gtk.CheckMenuItem visible_item; - private bool updating_visible = false; - private Gtk.SeparatorMenuItem devices_separator; - private List device_items; - private Gtk.MenuItem settings_item; - private Gtk.Menu menu; + private Indicator.ServiceManager service; + private Gtk.Image image; + private DbusmenuGtk.Menu menu; + private BluetoothService proxy; - public BluetoothIndicator () + construct { - Object (id: "indicator-bluetooth", icon_name: "bluetooth-active", category: "Hardware"); - - killswitch = new GnomeBluetooth.Killswitch (); - killswitch.state_changed.connect (killswitch_state_changed_cb); - - client = new GnomeBluetooth.Client (); - - set_status (AppIndicator.IndicatorStatus.ACTIVE); - - menu = new Gtk.Menu (); - set_menu (menu); - - status_item = new Gtk.MenuItem (); - status_item.sensitive = false; - status_item.visible = true; - menu.append (status_item); - - enable_item = new Gtk.MenuItem (); - enable_item.activate.connect (() => - { - if (updating_killswitch) - return; - if (killswitch.state == GnomeBluetooth.KillswitchState.UNBLOCKED) - killswitch.state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED; - else - killswitch.state = GnomeBluetooth.KillswitchState.UNBLOCKED; - }); - menu.append (enable_item); - - visible_item = new Gtk.CheckMenuItem.with_label (_("Visible")); - bool discoverable; - client.get ("default-adapter-discoverable", out discoverable); - visible_item.active = discoverable; - client.notify["default-adapter-discoverable"].connect (() => - { - updating_visible = true; - bool is_discoverable; - client.get ("default-adapter-discoverable", out is_discoverable); - visible_item.active = is_discoverable; - updating_visible = false; - }); - visible_item.activate.connect (() => - { - if (updating_visible) - return; - client.set ("default-adapter-discoverable", visible_item.active); - }); - menu.append (visible_item); - - devices_separator = new Gtk.SeparatorMenuItem (); - menu.append (devices_separator); - - device_items = new List (); - - client.model.row_inserted.connect (device_changed_cb); - client.model.row_changed.connect (device_changed_cb); - client.model.row_deleted.connect (device_removed_cb); - Gtk.TreeIter iter; - var have_iter = client.model.get_iter_first (out iter); - while (have_iter) - { - Gtk.TreeIter child_iter; - var have_child_iter = client.model.iter_children (out child_iter, iter); - while (have_child_iter) - { - device_changed_cb (null, child_iter); - have_child_iter = client.model.iter_next (ref child_iter); - } - have_iter = client.model.iter_next (ref iter); - } - - var sep = new Gtk.SeparatorMenuItem (); - sep.visible = true; - menu.append (sep); - - settings_item = new Gtk.MenuItem.with_label (_("Bluetooth Settings...")); - settings_item.activate.connect (() => { show_control_center ("bluetooth"); }); - settings_item.visible = true; - menu.append (settings_item); - - killswitch_state_changed_cb (killswitch.state); + service = new Indicator.ServiceManager ("com.canonical.indicator.bluetooth"); + service.connection_change.connect (connection_change_cb); + menu = new DbusmenuGtk.Menu ("com.canonical.indicator.bluetooth", "/com/canonical/indicator/bluetooth/menu"); + image = Indicator.image_helper ("bluetooth-active"); + image.visible = true; + + var menu_client = menu.get_client (); + menu_client.add_type_handler_full ("x-canonical-switch", new_switch_cb); } - private BluetoothMenuItem? find_menu_item (DBusProxy proxy) + private bool new_switch_cb (Dbusmenu.Menuitem newitem, Dbusmenu.Menuitem parent, Dbusmenu.Client client) { - foreach (var item in device_items) - if (item.proxy == proxy) - return item; - - return null; + var item = new Ido.SwitchMenuItem (); + item.active = newitem.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED; + var label = new Gtk.Label (newitem.property_get (Dbusmenu.MENUITEM_PROP_LABEL)); + label.visible = true; + item.content_area.add (label); + newitem.property_changed.connect ((mi, prop, value) => + { + label.label = mi.property_get (Dbusmenu.MENUITEM_PROP_LABEL); + item.active = mi.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED; + }); + (client as DbusmenuGtk.Client).newitem_base (newitem, item, parent); + return true; } - private void device_changed_cb (Gtk.TreePath? path, Gtk.TreeIter iter) + public override unowned Gtk.Image get_image () { - /* Ignore adapters */ - Gtk.TreeIter parent_iter; - if (!client.model.iter_parent (out parent_iter, iter)) - return; - - DBusProxy proxy; - string address; - string alias; - GnomeBluetooth.Type type; - string icon; - bool connected; - HashTable services; - string[] uuids; - client.model.get (iter, - GnomeBluetooth.Column.PROXY, out proxy, - GnomeBluetooth.Column.ADDRESS, out address, - GnomeBluetooth.Column.ALIAS, out alias, - GnomeBluetooth.Column.TYPE, out type, - GnomeBluetooth.Column.ICON, out icon, - GnomeBluetooth.Column.CONNECTED, out connected, - GnomeBluetooth.Column.SERVICES, out services, - GnomeBluetooth.Column.UUIDS, out uuids); - - /* Skip if haven't actually got any information yet */ - if (proxy == null) - return; - - /* Find or create menu item */ - var item = find_menu_item (proxy); - if (item == null) - { - item = new BluetoothMenuItem (client, proxy); - item.visible = true; - var last_item = devices_separator as Gtk.MenuItem; - if (device_items != null) - last_item = device_items.last ().data; - device_items.append (item); - menu.insert (item, menu.get_children ().index (last_item) + 1); - } - - item.update (type, address, alias, icon, connected, services, uuids); + return image; } - private void device_removed_cb (Gtk.TreePath path) + public override unowned Gtk.Menu get_menu () { - Gtk.TreeIter iter; - if (!client.model.get_iter (out iter, path)) - return; - - DBusProxy proxy; - client.model.get (iter, GnomeBluetooth.Column.PROXY, out proxy); - - var item = find_menu_item (proxy); - if (item == null) - return; - - device_items.remove (item); - menu.remove (item); + return menu; } - private void killswitch_state_changed_cb (GnomeBluetooth.KillswitchState state) + private void connection_change_cb (bool connected) { - updating_killswitch = true; + if (!connected) + return; - if (state == GnomeBluetooth.KillswitchState.HARD_BLOCKED) - { - icon_name = "bluetooth-inactive"; - status_item.label = _("Bluetooth: Disabled"); - enable_item.visible = false; - } - if (state == GnomeBluetooth.KillswitchState.SOFT_BLOCKED) - { - icon_name = "bluetooth-inactive"; - status_item.label = _("Bluetooth: Off"); - enable_item.label = _("Turn on Bluetooth"); - enable_item.visible = true; - enable_value = false; - } - else + // FIXME: Set proxy to null on disconnect? + // FIXME: Use Cancellable to cancel existing connection + if (proxy == null) { - status_item.label = _("Bluetooth: On"); - enable_item.label = _("Turn off Bluetooth"); - enable_item.visible = true; - enable_value = true; + Bus.get_proxy.begin (BusType.SESSION, + "com.canonical.indicator.bluetooth", + "/com/canonical/indicator/bluetooth/service", + DBusProxyFlags.NONE, null, (object, result) => + { + try + { + proxy = Bus.get_proxy.end (result); + proxy.g_properties_changed.connect (update_icon_cb); + update_icon_cb (); + } + catch (IOError e) + { + warning ("Failed to connect to bluetooth service: %s", e.message); + } + }); } + } - if (state == GnomeBluetooth.KillswitchState.UNBLOCKED) - icon_name = "bluetooth-active"; - else - icon_name = "bluetooth-disabled"; - - /* Disable devices when locked */ - visible_item.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED; - devices_separator.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED; - foreach (var item in device_items) - item.visible = state == GnomeBluetooth.KillswitchState.UNBLOCKED; - - updating_killswitch = false; + private void update_icon_cb () + { + Indicator.image_helper_update (image, proxy.icon_name); } } -private class BluetoothMenuItem : Gtk.ImageMenuItem +[DBus (name = "com.canonical.indicator.bluetooth.service")] +public interface BluetoothService : DBusProxy { - private GnomeBluetooth.Client client; - public DBusProxy proxy; - private Gtk.MenuItem? status_item = null; - private Gtk.MenuItem? connect_item = null; - - public BluetoothMenuItem (GnomeBluetooth.Client client, DBusProxy proxy) - { - this.client = client; - this.proxy = proxy; - label = ""; /* Workaround for https://bugs.launchpad.net/bugs/1086563 - without a label it thinks this is a separator */ - image = new Gtk.Image (); - always_show_image = true; - } - - public void update (GnomeBluetooth.Type type, string address, string alias, string icon, bool connected, HashTable? services, string[] uuids) - { - label = alias; - (image as Gtk.Image).icon_name = icon; - - submenu = new Gtk.Menu (); - - if (services != null) - { - status_item = new Gtk.MenuItem (); - status_item.visible = true; - status_item.sensitive = false; - submenu.append (status_item); - - connect_item = new Gtk.MenuItem (); - connect_item.visible = true; - connect_item.activate.connect (() => { connect_service (proxy.get_object_path (), true); }); - submenu.append (connect_item); - } - - update_connect_items (connected); - - var can_send = false; - var can_browse = false; - if (uuids != null) - { - for (var i = 0; uuids[i] != null; i++) - { - if (uuids[i] == "OBEXObjectPush") - can_send = true; - if (uuids[i] == "OBEXFileTransfer") - can_browse = true; - } - } - - if (can_send) - { - var send_item = new Gtk.MenuItem.with_label (_("Send files...")); - send_item.visible = true; - send_item.activate.connect (() => { GnomeBluetooth.send_to_address (address, alias); }); - submenu.append (send_item); - } - - if (can_browse) - { - var browse_item = new Gtk.MenuItem.with_label (_("Browse files...")); - browse_item.visible = true; - browse_item.activate.connect (() => { GnomeBluetooth.browse_address (null, address, Gdk.CURRENT_TIME, null); }); - submenu.append (browse_item); - } - - switch (type) - { - case GnomeBluetooth.Type.KEYBOARD: - var keyboard_item = new Gtk.MenuItem.with_label (_("Keyboard Settings...")); - keyboard_item.visible = true; - keyboard_item.activate.connect (() => { show_control_center ("keyboard"); }); - submenu.append (keyboard_item); - break; - - case GnomeBluetooth.Type.MOUSE: - case GnomeBluetooth.Type.TABLET: - var mouse_item = new Gtk.MenuItem.with_label (_("Mouse and Touchpad Settings...")); - mouse_item.visible = true; - mouse_item.activate.connect (() => { show_control_center ("mouse"); }); - submenu.append (mouse_item); - break; - - case GnomeBluetooth.Type.HEADSET: - case GnomeBluetooth.Type.HEADPHONES: - case GnomeBluetooth.Type.OTHER_AUDIO: - var sound_item = new Gtk.MenuItem.with_label (_("Sound Settings...")); - sound_item.visible = true; - sound_item.activate.connect (() => { show_control_center ("sound"); }); - submenu.append (sound_item); - break; - } - } - - private void connect_service (string device, bool connect) - { - status_item.label = _("Connecting..."); - client.connect_service.begin (device, connect, null, (object, result) => - { - var connected = false; - try - { - connected = client.connect_service.end (result); - } - catch (Error e) - { - warning ("Failed to connect service: %s", e.message); - } - update_connect_items (connected); - }); - } - - private void update_connect_items (bool connected) - { - if (status_item != null) - { - if (connected) - status_item.label = _("Connected"); - else - status_item.label = _("Disconnected"); - } - if (connect_item != null) - { - if (connected) - connect_item.label = _("Disconnect"); - else - connect_item.label = _("Connect"); - } - } + public abstract string icon_name { owned get; } } -private void show_control_center (string panel) +public static string get_version () { - try - { - Process.spawn_command_line_async ("gnome-control-center %s".printf (panel)); - } - catch (GLib.SpawnError e) - { - warning ("Failed to open control center: %s", e.message); - } + return Indicator.VERSION; } -public static int main (string[] args) +public static GLib.Type get_type () { - Intl.setlocale (LocaleCategory.ALL, ""); - Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); - Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - Intl.textdomain (GETTEXT_PACKAGE); - - Gtk.init (ref args); - - var indicator = new BluetoothIndicator (); - - Gtk.main (); - - indicator = null; - - return Posix.EXIT_SUCCESS; + return typeof (BluetoothIndicator); } -- cgit v1.2.3