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");
},
});