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
This commit is contained in:
Bastien Nocera 2014-11-13 10:58:35 +01:00
parent 3fc5afaff1
commit 8ceae3b054
2 changed files with 61 additions and 13 deletions

View File

@ -72,6 +72,16 @@
This key sets the default state of the checkbox. This key sets the default state of the checkbox.
</_description> </_description>
</key> </key>
<key name="had-bluetooth-devices-setup" type="b">
<default>false</default>
<_summary>Whether the default Bluetooth adapter had set up devices associated to it</_summary>
<_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.
</_description>
</key>
<child name="calendar" schema="org.gnome.shell.calendar"/> <child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="keybindings" schema="org.gnome.shell.keybindings"/> <child name="keybindings" schema="org.gnome.shell.keybindings"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/> <child name="keyboard" schema="org.gnome.shell.keyboard"/>

View File

@ -23,6 +23,8 @@ const RfkillManagerInterface = '<node> \
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface); const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
const HAD_BLUETOOTH_DEVICES_SETUP = 'had-bluetooth-devices-setup';
const Indicator = new Lang.Class({ const Indicator = new Lang.Class({
Name: 'BTIndicator', Name: 'BTIndicator',
Extends: PanelMenu.SystemIndicator, Extends: PanelMenu.SystemIndicator,
@ -32,6 +34,7 @@ const Indicator = new Lang.Class({
this._indicator = this._addIndicator(); this._indicator = this._addIndicator();
this._indicator.icon_name = 'bluetooth-active-symbolic'; 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, this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) { 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)); this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
// The Bluetooth menu only appears when Bluetooth is in use, this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
// so just statically build it with a "Turn Off" menu item.
this._item = new PopupMenu.PopupSubMenuMenuItem('', true);
this._item.icon.icon_name = 'bluetooth-active-symbolic'; 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._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this.menu.addMenuItem(this._item); this.menu.addMenuItem(this._item);
@ -68,42 +73,75 @@ const Indicator = new Lang.Class({
while (ret) { while (ret) {
let isDefault = this._model.get_value(iter, let isDefault = this._model.get_value(iter,
GnomeBluetooth.Column.DEFAULT); GnomeBluetooth.Column.DEFAULT);
if (isDefault) let isPowered = this._model.get_value(iter,
GnomeBluetooth.Column.POWERED);
if (isDefault && isPowered)
return iter; return iter;
ret = this._model.iter_next(iter); ret = this._model.iter_next(iter);
} }
return null; 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(); let adapter = this._getDefaultAdapter();
if (!adapter) if (!adapter)
return 0; return [ this._hadSetupDevices ? 1 : -1, -1 ];
let nConnectedDevices = 0;
let nDevices = 0; let nDevices = 0;
let [ret, iter] = this._model.iter_children(adapter); let [ret, iter] = this._model.iter_children(adapter);
while (ret) { while (ret) {
let isConnected = this._model.get_value(iter, let isConnected = this._model.get_value(iter,
GnomeBluetooth.Column.CONNECTED); GnomeBluetooth.Column.CONNECTED);
if (isConnected) 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++; nDevices++;
ret = this._model.iter_next(iter); 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() { _sync: function() {
let nDevices = this._getNConnectedDevices(); let [ nDevices, nConnectedDevices ] = this._getNDevices();
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter; let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive); this.menu.setSensitive(sensitive);
this._indicator.visible = nDevices > 0; 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; this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
if (nDevices > 0) if (nConnectedDevices > 0)
/* Translators: this is the number of connected bluetooth devices */ /* 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 else
this._item.label.text = _("Not In Use"); this._item.label.text = _("Not In Use");
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
}, },
}); });