From 8ceae3b0548efcd7f514c2dd7b365f261654cbb6 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 13 Nov 2014 10:58:35 +0100 Subject: [PATCH] bluetooth: Show the Bluetooth menu when there were setup devices If we detected that Bluetooth devices were setup, show the Bluetooth menu so that users can easily turn Bluetooth back on. This is a bit of a hack, as we cannot detect whether there is a Bluetooth adapter at all when it's disabled, so we cannot tell whether there were any Bluetooth devices setup, at some point. This state is saved in the gnome-shell GSettings in the had-bluetooth-devices-setup key. Checking whether we saw Bluetooth devices at one point is a good enough guess of whether there will be some in the future. https://bugzilla.gnome.org/show_bug.cgi?id=723848 --- data/org.gnome.shell.gschema.xml.in.in | 10 ++++ js/ui/status/bluetooth.js | 64 ++++++++++++++++++++------ 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/data/org.gnome.shell.gschema.xml.in.in b/data/org.gnome.shell.gschema.xml.in.in index 12b76c94f..c42a9f732 100644 --- a/data/org.gnome.shell.gschema.xml.in.in +++ b/data/org.gnome.shell.gschema.xml.in.in @@ -72,6 +72,16 @@ This key sets the default state of the checkbox. + + false + <_summary>Whether the default Bluetooth adapter had set up devices associated to it + <_description> + The shell will only show a Bluetooth menu item if a Bluetooth + adapter is powered, or if there were devices set up associated + with the default adapter. This will be reset if the default + adapter is ever seen not to have devices associated to it. + + diff --git a/js/ui/status/bluetooth.js b/js/ui/status/bluetooth.js index 8c9afcfd5..d689e54d7 100644 --- a/js/ui/status/bluetooth.js +++ b/js/ui/status/bluetooth.js @@ -23,6 +23,8 @@ const RfkillManagerInterface = ' \ const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface); +const HAD_BLUETOOTH_DEVICES_SETUP = 'had-bluetooth-devices-setup'; + const Indicator = new Lang.Class({ Name: 'BTIndicator', Extends: PanelMenu.SystemIndicator, @@ -32,6 +34,7 @@ const Indicator = new Lang.Class({ this._indicator = this._addIndicator(); this._indicator.icon_name = 'bluetooth-active-symbolic'; + this._hadSetupDevices = global.settings.get_boolean(HAD_BLUETOOTH_DEVICES_SETUP); this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH, Lang.bind(this, function(proxy, error) { @@ -44,13 +47,15 @@ const Indicator = new Lang.Class({ })); this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync)); - // The Bluetooth menu only appears when Bluetooth is in use, - // so just statically build it with a "Turn Off" menu item. - this._item = new PopupMenu.PopupSubMenuMenuItem('', true); + this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true); this._item.icon.icon_name = 'bluetooth-active-symbolic'; - this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() { - this._proxy.BluetoothAirplaneMode = true; + + this._toggleItem = new PopupMenu.PopupMenuItem(''); + this._toggleItem.connect('activate', Lang.bind(this, function() { + this._proxy.BluetoothAirplaneMode = !this._proxy.BluetoothAirplaneMode; })); + this._item.menu.addMenuItem(this._toggleItem); + this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop'); this.menu.addMenuItem(this._item); @@ -68,42 +73,75 @@ const Indicator = new Lang.Class({ while (ret) { let isDefault = this._model.get_value(iter, GnomeBluetooth.Column.DEFAULT); - if (isDefault) + let isPowered = this._model.get_value(iter, + GnomeBluetooth.Column.POWERED); + if (isDefault && isPowered) return iter; ret = this._model.iter_next(iter); } return null; }, - _getNConnectedDevices: function() { + // nDevices is the number of devices setup for the current default + // adapter if one exists and is powered. If unpowered or unavailable, + // nDevice is "1" if it had setup devices associated to it the last + // time it was seen, and "-1" if not. + // + // nConnectedDevices is the number of devices connected to the default + // adapter if one exists and is powered, or -1 if it's not available. + _getNDevices: function() { let adapter = this._getDefaultAdapter(); if (!adapter) - return 0; + return [ this._hadSetupDevices ? 1 : -1, -1 ]; + let nConnectedDevices = 0; let nDevices = 0; let [ret, iter] = this._model.iter_children(adapter); while (ret) { let isConnected = this._model.get_value(iter, GnomeBluetooth.Column.CONNECTED); if (isConnected) + nConnectedDevices++; + + let isPaired = this._model.get_value(iter, + GnomeBluetooth.Column.PAIRED); + let isTrusted = this._model.get_value(iter, + GnomeBluetooth.Column.TRUSTED); + if (isPaired || isTrusted) nDevices++; ret = this._model.iter_next(iter); } - return nDevices; + + if (this._hadSetupDevices != (nDevices > 0)) { + this._hadSetupDevices = !this._hadSetupDevices; + global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices); + } + + return [ nDevices, nConnectedDevices]; }, _sync: function() { - let nDevices = this._getNConnectedDevices(); + let [ nDevices, nConnectedDevices ] = this._getNDevices(); let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter; this.menu.setSensitive(sensitive); - this._indicator.visible = nDevices > 0; - this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode; + this._indicator.visible = nConnectedDevices > 0; + // Remember if there were setup devices and show the menu + // if we've seen setup devices and we're not hard blocked if (nDevices > 0) + this._item.actor.visible = !this._proxy.BluetoothHardwareAirplaneMode; + else + this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode; + + if (nConnectedDevices > 0) /* Translators: this is the number of connected bluetooth devices */ - this._item.label.text = ngettext("%d Connected", "%d Connected", nDevices).format(nDevices); + this._item.label.text = ngettext("%d Connected", "%d Connected", nConnectedDevices).format(nConnectedDevices); + else if (nConnectedDevices == -1) + this._item.label.text = _("Off"); else this._item.label.text = _("Not In Use"); + + this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off"); }, });