[gnome-shell] ibusManager, inputMethod: Cancel async ibus calls chain on disconnect
- From: Marco Trevisan <marcotrevi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] ibusManager, inputMethod: Cancel async ibus calls chain on disconnect
- Date: Wed, 2 Oct 2019 16:26:45 +0000 (UTC)
commit 1cc766d6369361a3c8b80acfb6236c7ef8e0bdaf
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date: Wed Sep 25 20:56:46 2019 +0200
ibusManager, inputMethod: Cancel async ibus calls chain on disconnect
The shell tries to spawn the ibus daemon on startup if unavailable, however
as per commit 8adfc5b1 we also force restarting it once the X11 server is
available.
Unfortunately this could cause a race if we disconnect while we were already
connected to an ibus daemon, but still in the process of going through the
various nested calls.
In fact the ::disconnect callback didn't stop any further async ibus call
that, even if failing, would have eventually triggered the emission of a
'ready' signal and to the Keyboard's callback, leading under X11 to a full
grab owned by ibus daemon.
In order to avoid this and keep control of the calls order, use in both
IbusManager and InputMethod a cancellable that is setup before connecting to
the bus, and that is cancelled on disconnection.
Then handle the finish() calls properly, using try/catch to validate the
returned value, taking in account the potential error and just not
proceeding in case of cancellation.
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1712
js/misc/ibusManager.js | 52 ++++++++++++++++++++++++++++++++++++++------------
js/misc/inputMethod.js | 47 ++++++++++++++++++++++++++++++---------------
2 files changed, 72 insertions(+), 27 deletions(-)
---
diff --git a/js/misc/ibusManager.js b/js/misc/ibusManager.js
index 2011321eeb..55e2fd97bd 100644
--- a/js/misc/ibusManager.js
+++ b/js/misc/ibusManager.js
@@ -72,6 +72,11 @@ var IBusManager = class {
}
_clear() {
+ if (this._cancellable) {
+ this._cancellable.cancel();
+ this._cancellable = null;
+ }
+
if (this._panelService)
this._panelService.destroy();
@@ -86,28 +91,41 @@ var IBusManager = class {
}
_onConnected() {
- this._ibus.list_engines_async(-1, null, this._initEngines.bind(this));
+ this._cancellable = new Gio.Cancellable();
+ this._ibus.list_engines_async(-1, this._cancellable,
+ this._initEngines.bind(this));
this._ibus.request_name_async(IBus.SERVICE_PANEL,
- IBus.BusNameFlag.REPLACE_EXISTING,
- -1, null,
- this._initPanelService.bind(this));
+ IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
+ this._initPanelService.bind(this));
}
_initEngines(ibus, result) {
- let enginesList = this._ibus.list_engines_async_finish(result);
- if (enginesList) {
+ try {
+ let enginesList = this._ibus.list_engines_async_finish(result);
for (let i = 0; i < enginesList.length; ++i) {
let name = enginesList[i].get_name();
this._engines.set(name, enginesList[i]);
}
this._updateReadiness();
- } else {
+ } catch (e) {
+ if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return;
+
+ logError(e);
this._clear();
}
}
_initPanelService(ibus, result) {
- let success = this._ibus.request_name_async_finish(result);
+ let success = false;
+ try {
+ success = !!this._ibus.request_name_async_finish(result);
+ } catch (e) {
+ if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return;
+ logError(e);
+ }
+
if (success) {
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
@@ -134,7 +152,7 @@ var IBusManager = class {
} catch (e) {
}
// If an engine is already active we need to get its properties
- this._ibus.get_global_engine_async(-1, null, (i, result) => {
+ this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, result) => {
let engine;
try {
engine = this._ibus.get_global_engine_async_finish(result);
@@ -206,8 +224,18 @@ var IBusManager = class {
return;
}
- this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
- null, callback || null);
+ this._ibus.set_global_engine_async(id,
+ this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
+ this._cancellable, (_bus, res) => {
+ try {
+ this._ibus.set_global_engine_async_finish(res);
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ logError(e);
+ }
+ if (callback)
+ callback();
+ });
}
preloadEngines(ids) {
@@ -227,7 +255,7 @@ var IBusManager = class {
this._ibus.preload_engines_async(
ids,
-1,
- null,
+ this._cancellable,
null);
this._preloadEnginesId = 0;
return GLib.SOURCE_REMOVE;
diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js
index 1ca70c3df5..42bf7f6321 100644
--- a/js/misc/inputMethod.js
+++ b/js/misc/inputMethod.js
@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported InputMethod */
-const { Clutter, GLib, GObject, IBus } = imports.gi;
+const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
const Keyboard = imports.ui.status.keyboard;
@@ -47,12 +47,22 @@ class InputMethod extends Clutter.InputMethod {
}
_onConnected() {
- this._ibus.create_input_context_async ('gnome-shell', -1, null,
- this._setContext.bind(this));
+ this._cancellable = new Gio.Cancellable();
+ this._ibus.create_input_context_async ('gnome-shell', -1,
+ this._cancellable, this._setContext.bind(this));
}
_setContext(bus, res) {
- this._context = this._ibus.create_input_context_async_finish(res);
+ try {
+ this._context = this._ibus.create_input_context_async_finish(res);
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
+ logError(e);
+ this._clear();
+ }
+ return;
+ }
+
this._context.connect('commit-text', this._onCommitText.bind(this));
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
@@ -64,6 +74,11 @@ class InputMethod extends Clutter.InputMethod {
}
_clear() {
+ if (this._cancellable) {
+ this._cancellable.cancel();
+ this._cancellable = null;
+ }
+
this._context = null;
this._hints = 0;
this._purpose = 0;
@@ -244,17 +259,19 @@ class InputMethod extends Clutter.InputMethod {
if (event.type() == Clutter.EventType.KEY_RELEASE)
state |= IBus.ModifierType.RELEASE_MASK;
- this._context.process_key_event_async(event.get_key_symbol(),
- event.get_key_code() - 8, // Convert XKB keycodes to evcodes
- state, -1, null,
- (context, res) => {
- try {
- let retval =
context.process_key_event_async_finish(res);
- this.notify_key_event(event, retval);
- } catch (e) {
- log(`Error processing key on IM: ${e.message}`);
- }
- });
+ this._context.process_key_event_async(
+ event.get_key_symbol(),
+ event.get_key_code() - 8, // Convert XKB keycodes to evcodes
+ state, -1, this._cancellable,
+ (context, res) => {
+ try {
+ let retval = context.process_key_event_async_finish(res);
+ this.notify_key_event(event, retval);
+ } catch (e) {
+ if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ log(`Error processing key on IM: ${e.message}`);
+ }
+ });
return true;
}
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]