diff --git a/js/ui/status/bluetooth.js b/js/ui/status/bluetooth.js index 1584e0468..888592dc9 100644 --- a/js/ui/status/bluetooth.js +++ b/js/ui/status/bluetooth.js @@ -24,6 +24,8 @@ const rfkillManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(RfkillManagerInterfa Gio._promisify(GnomeBluetooth.Client.prototype, 'connect_service'); +const STATE_CHANGE_FAILED_TIMEOUT_MS = 30 * 1000; + const BtClient = GObject.registerClass({ Properties: { 'available': GObject.ParamSpec.boolean('available', '', '', @@ -48,8 +50,10 @@ const BtClient = GObject.registerClass({ this._client.connect('notify::default-adapter-powered', () => { this.notify('active'); }); - this._client.connect('notify::default-adapter-state', - () => this.notify('adapter-state')); + this._client.connect('notify::default-adapter-state', () => { + delete this._predictedState; + this.notify('adapter-state'); + }); this._client.connect('notify::default-adapter', () => { const newAdapter = this._client.default_adapter ?? null; @@ -108,11 +112,30 @@ const BtClient = GObject.registerClass({ } get adapter_state() { + if (this._predictedState !== undefined) + return this._predictedState; return this._client.default_adapter_state; } toggleActive() { - this._proxy.BluetoothAirplaneMode = this.active; + const {active} = this; + + // on many systems, there's a significant delay until the rfkill + // state results in an adapter state change; work around that by + // overriding the current state with the expected transition + this._predictedState = active + ? AdapterState.TURNING_OFF + : AdapterState.TURNING_ON; + this.notify('adapter-state'); + + // toggling the state *really* should result in an adapter-state + // change eventually (even on error), but just to be sure to not + // be stuck with the overriden state, force a notify signal after + // a timeout + setTimeout(() => this._client.notify('default-adapter-state'), + STATE_CHANGE_FAILED_TIMEOUT_MS); + + this._proxy.BluetoothAirplaneMode = active; if (!this._client.default_adapter_powered) this._client.default_adapter_powered = true; }