2017-12-05 19:05:00 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2019-01-31 14:07:06 +00:00
|
|
|
/* exported InputMethod */
|
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
2019-09-25 18:56:46 +00:00
|
|
|
const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
|
2019-02-09 03:21:36 +00:00
|
|
|
|
2017-12-05 19:05:00 +00:00
|
|
|
const Keyboard = imports.ui.status.keyboard;
|
2022-08-09 14:00:33 +00:00
|
|
|
const Main = imports.ui.main;
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-12-19 19:50:37 +00:00
|
|
|
Gio._promisify(IBus.Bus.prototype,
|
|
|
|
'create_input_context_async', 'create_input_context_async_finish');
|
2022-10-11 16:24:15 +00:00
|
|
|
Gio._promisify(IBus.InputContext.prototype,
|
|
|
|
'process_key_event_async', 'process_key_event_async_finish');
|
2019-12-19 19:50:37 +00:00
|
|
|
|
2019-02-08 22:00:18 +00:00
|
|
|
var HIDE_PANEL_TIME = 50;
|
|
|
|
|
2022-04-20 21:16:38 +00:00
|
|
|
var InputMethod = GObject.registerClass({
|
|
|
|
Signals: {
|
|
|
|
'surrounding-text-set': {},
|
2022-04-22 19:16:52 +00:00
|
|
|
'terminal-mode-changed': {},
|
2022-04-20 21:16:38 +00:00
|
|
|
},
|
|
|
|
}, class InputMethod extends Clutter.InputMethod {
|
2017-10-31 00:03:21 +00:00
|
|
|
_init() {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init();
|
2017-12-05 19:05:00 +00:00
|
|
|
this._hints = 0;
|
|
|
|
this._purpose = 0;
|
|
|
|
this._currentFocus = null;
|
2018-08-21 11:21:53 +00:00
|
|
|
this._preeditStr = '';
|
|
|
|
this._preeditPos = 0;
|
2022-07-18 13:11:49 +00:00
|
|
|
this._preeditAnchor = 0;
|
2018-11-13 17:28:15 +00:00
|
|
|
this._preeditVisible = false;
|
2019-02-08 22:00:18 +00:00
|
|
|
this._hidePanelId = 0;
|
2022-04-22 19:16:52 +00:00
|
|
|
this.terminalMode = false;
|
2017-12-05 19:05:00 +00:00
|
|
|
this._ibus = IBus.Bus.new_async();
|
2017-12-02 00:27:35 +00:00
|
|
|
this._ibus.connect('connected', this._onConnected.bind(this));
|
|
|
|
this._ibus.connect('disconnected', this._clear.bind(this));
|
|
|
|
this.connect('notify::can-show-preedit', this._updateCapabilities.bind(this));
|
2017-12-05 19:05:00 +00:00
|
|
|
|
|
|
|
this._inputSourceManager = Keyboard.getInputSourceManager();
|
|
|
|
this._sourceChangedId = this._inputSourceManager.connect('current-source-changed',
|
2017-12-02 00:27:35 +00:00
|
|
|
this._onSourceChanged.bind(this));
|
2017-12-05 19:05:00 +00:00
|
|
|
this._currentSource = this._inputSourceManager.currentSource;
|
|
|
|
|
|
|
|
if (this._ibus.is_connected())
|
|
|
|
this._onConnected();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
|
|
|
get currentFocus() {
|
|
|
|
return this._currentFocus;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateCapabilities() {
|
2019-10-01 10:53:20 +00:00
|
|
|
let caps = IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT;
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2022-08-09 14:00:33 +00:00
|
|
|
if (Main.keyboard.visible)
|
|
|
|
caps |= IBus.Capabilite.OSK;
|
|
|
|
|
2017-12-05 19:05:00 +00:00
|
|
|
if (this._context)
|
|
|
|
this._context.set_capabilities(caps);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onSourceChanged() {
|
2017-12-05 19:05:00 +00:00
|
|
|
this._currentSource = this._inputSourceManager.currentSource;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-12-19 19:50:37 +00:00
|
|
|
async _onConnected() {
|
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
2019-09-25 18:56:46 +00:00
|
|
|
this._cancellable = new Gio.Cancellable();
|
|
|
|
try {
|
2019-12-19 19:50:37 +00:00
|
|
|
this._context = await this._ibus.create_input_context_async(
|
|
|
|
'gnome-shell', -1, this._cancellable);
|
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
2019-09-25 18:56:46 +00:00
|
|
|
} catch (e) {
|
|
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
|
|
|
logError(e);
|
|
|
|
this._clear();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-27 14:52:32 +00:00
|
|
|
this._context.set_client_commit_preedit(true);
|
2017-12-02 00:27:35 +00:00
|
|
|
this._context.connect('commit-text', this._onCommitText.bind(this));
|
|
|
|
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
|
2021-07-27 14:52:32 +00:00
|
|
|
this._context.connect('update-preedit-text-with-mode', this._onUpdatePreeditText.bind(this));
|
2018-08-21 11:21:53 +00:00
|
|
|
this._context.connect('show-preedit-text', this._onShowPreeditText.bind(this));
|
|
|
|
this._context.connect('hide-preedit-text', this._onHidePreeditText.bind(this));
|
2018-06-29 15:35:39 +00:00
|
|
|
this._context.connect('forward-key-event', this._onForwardKeyEvent.bind(this));
|
2019-11-07 18:06:15 +00:00
|
|
|
this._context.connect('destroy', this._clear.bind(this));
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2022-08-09 14:00:33 +00:00
|
|
|
Main.keyboard.connectObject('visibility-changed', () => this._updateCapabilities());
|
|
|
|
|
2017-12-05 19:05:00 +00:00
|
|
|
this._updateCapabilities();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_clear() {
|
2022-08-09 14:00:33 +00:00
|
|
|
Main.keyboard.disconnectObject(this);
|
|
|
|
|
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
2019-09-25 18:56:46 +00:00
|
|
|
if (this._cancellable) {
|
|
|
|
this._cancellable.cancel();
|
|
|
|
this._cancellable = null;
|
|
|
|
}
|
|
|
|
|
2017-12-05 19:05:00 +00:00
|
|
|
this._context = null;
|
|
|
|
this._hints = 0;
|
|
|
|
this._purpose = 0;
|
2019-01-29 01:18:52 +00:00
|
|
|
this._preeditStr = '';
|
2018-08-21 11:21:53 +00:00
|
|
|
this._preeditPos = 0;
|
2022-07-18 13:11:49 +00:00
|
|
|
this._preeditAnchor = 0;
|
2018-11-13 17:28:15 +00:00
|
|
|
this._preeditVisible = false;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_emitRequestSurrounding() {
|
2017-12-05 19:05:00 +00:00
|
|
|
if (this._context.needs_surrounding_text())
|
|
|
|
this.emit('request-surrounding');
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
_onCommitText(_context, text) {
|
2017-12-05 19:05:00 +00:00
|
|
|
this.commit(text.get_text());
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-08-14 08:16:46 +00:00
|
|
|
_onDeleteSurroundingText(_context, offset, nchars) {
|
2020-03-28 16:26:39 +00:00
|
|
|
try {
|
|
|
|
this.delete_surrounding(offset, nchars);
|
|
|
|
} catch (e) {
|
|
|
|
// We may get out of bounds for negative offset on older mutter
|
|
|
|
this.delete_surrounding(0, nchars + offset);
|
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2021-07-27 14:52:32 +00:00
|
|
|
_onUpdatePreeditText(_context, text, pos, visible, mode) {
|
2018-08-21 11:21:53 +00:00
|
|
|
if (text == null)
|
|
|
|
return;
|
2018-11-13 17:28:15 +00:00
|
|
|
|
|
|
|
let preedit = text.get_text();
|
2021-10-29 14:41:55 +00:00
|
|
|
if (preedit === '')
|
|
|
|
preedit = null;
|
2018-11-13 17:28:15 +00:00
|
|
|
|
2022-07-18 13:11:49 +00:00
|
|
|
const anchor = pos;
|
2018-08-21 11:21:53 +00:00
|
|
|
if (visible)
|
2022-07-18 13:11:49 +00:00
|
|
|
this.set_preedit_text(preedit, pos, anchor, mode);
|
2018-11-13 17:28:15 +00:00
|
|
|
else if (this._preeditVisible)
|
2022-07-18 13:11:49 +00:00
|
|
|
this.set_preedit_text(null, pos, anchor, mode);
|
2018-11-13 17:28:15 +00:00
|
|
|
|
|
|
|
this._preeditStr = preedit;
|
|
|
|
this._preeditPos = pos;
|
2022-07-18 13:11:49 +00:00
|
|
|
this._preeditAnchor = anchor;
|
2018-11-13 17:28:15 +00:00
|
|
|
this._preeditVisible = visible;
|
2021-07-27 14:52:32 +00:00
|
|
|
this._preeditCommitMode = mode;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2018-08-21 11:21:53 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_onShowPreeditText() {
|
2018-11-13 17:28:15 +00:00
|
|
|
this._preeditVisible = true;
|
2022-07-18 13:11:49 +00:00
|
|
|
this.set_preedit_text(
|
|
|
|
this._preeditStr, this._preeditPos, this._preeditAnchor,
|
|
|
|
this._preeditCommitMode);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-02-04 11:30:53 +00:00
|
|
|
_onHidePreeditText() {
|
2022-07-18 13:11:49 +00:00
|
|
|
this.set_preedit_text(
|
|
|
|
null, this._preeditPos, this._preeditAnchor,
|
|
|
|
this._preeditCommitMode);
|
2018-11-13 17:28:15 +00:00
|
|
|
this._preeditVisible = false;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2019-01-31 14:08:10 +00:00
|
|
|
_onForwardKeyEvent(_context, keyval, keycode, state) {
|
2018-06-29 15:35:39 +00:00
|
|
|
let press = (state & IBus.ModifierType.RELEASE_MASK) == 0;
|
2019-08-19 19:38:51 +00:00
|
|
|
state &= ~IBus.ModifierType.RELEASE_MASK;
|
2018-06-29 15:35:39 +00:00
|
|
|
|
2018-09-27 19:09:02 +00:00
|
|
|
let curEvent = Clutter.get_current_event();
|
|
|
|
let time;
|
|
|
|
if (curEvent)
|
|
|
|
time = curEvent.get_time();
|
|
|
|
else
|
|
|
|
time = global.display.get_current_time_roundtrip();
|
2018-06-29 15:35:39 +00:00
|
|
|
|
2018-09-27 19:09:02 +00:00
|
|
|
this.forward_key(keyval, keycode + 8, state & Clutter.ModifierType.MODIFIER_MASK, time, press);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2018-06-29 15:35:39 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_focus_in(focus) {
|
2017-12-05 19:05:00 +00:00
|
|
|
this._currentFocus = focus;
|
|
|
|
if (this._context) {
|
|
|
|
this._context.focus_in();
|
|
|
|
this._emitRequestSurrounding();
|
|
|
|
}
|
2019-02-08 22:00:18 +00:00
|
|
|
|
|
|
|
if (this._hidePanelId) {
|
|
|
|
GLib.source_remove(this._hidePanelId);
|
|
|
|
this._hidePanelId = 0;
|
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_focus_out() {
|
2017-12-05 19:05:00 +00:00
|
|
|
this._currentFocus = null;
|
2019-10-01 10:53:20 +00:00
|
|
|
if (this._context)
|
2017-12-05 19:05:00 +00:00
|
|
|
this._context.focus_out();
|
|
|
|
|
2021-10-29 14:46:18 +00:00
|
|
|
if (this._preeditStr && this._preeditVisible) {
|
2018-11-13 17:26:13 +00:00
|
|
|
// Unset any preedit text
|
2022-07-18 13:11:49 +00:00
|
|
|
this.set_preedit_text(null, 0, 0, this._preeditCommitMode);
|
2018-11-13 17:26:13 +00:00
|
|
|
this._preeditStr = null;
|
|
|
|
}
|
2019-02-08 22:00:18 +00:00
|
|
|
|
|
|
|
this._hidePanelId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, HIDE_PANEL_TIME, () => {
|
|
|
|
this.set_input_panel_state(Clutter.InputPanelState.OFF);
|
|
|
|
this._hidePanelId = 0;
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_reset() {
|
2021-09-29 19:46:45 +00:00
|
|
|
if (this._context) {
|
|
|
|
this._context.reset();
|
|
|
|
this._emitRequestSurrounding();
|
|
|
|
}
|
|
|
|
|
2022-04-20 21:16:38 +00:00
|
|
|
this._surroundingText = null;
|
|
|
|
this._surroundingTextCursor = null;
|
2021-10-29 14:43:15 +00:00
|
|
|
this._preeditStr = null;
|
2022-04-22 19:16:52 +00:00
|
|
|
this._setTerminalMode(false);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_set_cursor_location(rect) {
|
2017-12-05 19:05:00 +00:00
|
|
|
if (this._context) {
|
2022-10-17 11:30:40 +00:00
|
|
|
this._cursorRect = {
|
|
|
|
x: rect.get_x(), y: rect.get_y(),
|
|
|
|
width: rect.get_width(), height: rect.get_height(),
|
|
|
|
};
|
|
|
|
this._context.set_cursor_location(
|
|
|
|
this._cursorRect.x, this._cursorRect.y,
|
|
|
|
this._cursorRect.width, this._cursorRect.height);
|
2017-12-05 19:05:00 +00:00
|
|
|
this._emitRequestSurrounding();
|
|
|
|
}
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_set_surrounding(text, cursor, anchor) {
|
2022-04-20 21:16:38 +00:00
|
|
|
this._surroundingText = text;
|
|
|
|
this._surroundingTextCursor = cursor;
|
|
|
|
this.emit('surrounding-text-set');
|
|
|
|
|
2018-09-11 13:36:35 +00:00
|
|
|
if (!this._context || !text)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let ibusText = IBus.Text.new_from_string(text);
|
|
|
|
this._context.set_surrounding_text(ibusText, cursor, anchor);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_update_content_hints(hints) {
|
2017-12-05 19:05:00 +00:00
|
|
|
let ibusHints = 0;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.COMPLETION)
|
|
|
|
ibusHints |= IBus.InputHints.WORD_COMPLETION;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.SPELLCHECK)
|
|
|
|
ibusHints |= IBus.InputHints.SPELLCHECK;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.AUTO_CAPITALIZATION)
|
|
|
|
ibusHints |= IBus.InputHints.UPPERCASE_SENTENCES;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.LOWERCASE)
|
|
|
|
ibusHints |= IBus.InputHints.LOWERCASE;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.UPPERCASE)
|
|
|
|
ibusHints |= IBus.InputHints.UPPERCASE_CHARS;
|
|
|
|
if (hints & Clutter.InputContentHintFlags.TITLECASE)
|
|
|
|
ibusHints |= IBus.InputHints.UPPERCASE_WORDS;
|
|
|
|
|
|
|
|
this._hints = ibusHints;
|
|
|
|
if (this._context)
|
|
|
|
this._context.set_content_type(this._purpose, this._hints);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_update_content_purpose(purpose) {
|
2017-12-05 19:05:00 +00:00
|
|
|
let ibusPurpose = 0;
|
|
|
|
if (purpose == Clutter.InputContentPurpose.NORMAL)
|
|
|
|
ibusPurpose = IBus.InputPurpose.FREE_FORM;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.ALPHA)
|
|
|
|
ibusPurpose = IBus.InputPurpose.ALPHA;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.DIGITS)
|
|
|
|
ibusPurpose = IBus.InputPurpose.DIGITS;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.NUMBER)
|
|
|
|
ibusPurpose = IBus.InputPurpose.NUMBER;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.PHONE)
|
|
|
|
ibusPurpose = IBus.InputPurpose.PHONE;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.URL)
|
|
|
|
ibusPurpose = IBus.InputPurpose.URL;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.EMAIL)
|
|
|
|
ibusPurpose = IBus.InputPurpose.EMAIL;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.NAME)
|
|
|
|
ibusPurpose = IBus.InputPurpose.NAME;
|
|
|
|
else if (purpose == Clutter.InputContentPurpose.PASSWORD)
|
|
|
|
ibusPurpose = IBus.InputPurpose.PASSWORD;
|
2022-10-14 19:41:00 +00:00
|
|
|
else if (purpose === Clutter.InputContentPurpose.TERMINAL &&
|
|
|
|
IBus.InputPurpose.TERMINAL)
|
|
|
|
ibusPurpose = IBus.InputPurpose.TERMINAL;
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2022-04-22 19:16:52 +00:00
|
|
|
this._setTerminalMode(
|
|
|
|
purpose === Clutter.InputContentPurpose.TERMINAL);
|
|
|
|
|
2017-12-05 19:05:00 +00:00
|
|
|
this._purpose = ibusPurpose;
|
|
|
|
if (this._context)
|
|
|
|
this._context.set_content_type(this._purpose, this._hints);
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
|
2022-04-22 19:16:52 +00:00
|
|
|
_setTerminalMode(terminalMode) {
|
|
|
|
if (this.terminalMode !== terminalMode) {
|
|
|
|
this.terminalMode = terminalMode;
|
|
|
|
this.emit('terminal-mode-changed');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
vfunc_filter_key_event(event) {
|
2018-12-11 07:18:59 +00:00
|
|
|
if (!this._context)
|
2017-12-05 19:05:00 +00:00
|
|
|
return false;
|
2018-03-15 13:01:51 +00:00
|
|
|
if (!this._currentSource)
|
2017-12-05 19:05:00 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
let state = event.get_state();
|
|
|
|
if (state & IBus.ModifierType.IGNORED_MASK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (event.type() == Clutter.EventType.KEY_RELEASE)
|
|
|
|
state |= IBus.ModifierType.RELEASE_MASK;
|
2018-06-29 15:35:39 +00:00
|
|
|
|
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
2019-09-25 18:56:46 +00:00
|
|
|
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) => {
|
2019-11-07 18:06:15 +00:00
|
|
|
if (context != this._context)
|
|
|
|
return;
|
|
|
|
|
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
2019-09-25 18:56:46 +00:00
|
|
|
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}`);
|
|
|
|
}
|
|
|
|
});
|
2017-12-05 19:05:00 +00:00
|
|
|
return true;
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2022-04-20 21:16:38 +00:00
|
|
|
|
|
|
|
getSurroundingText() {
|
|
|
|
return [this._surroundingText, this._surroundingTextCursor];
|
|
|
|
}
|
2022-04-20 21:18:27 +00:00
|
|
|
|
|
|
|
hasPreedit() {
|
|
|
|
return this._preeditVisible && this._preeditStr !== '' && this._preeditStr !== null;
|
|
|
|
}
|
2022-04-22 11:28:02 +00:00
|
|
|
|
2022-10-11 16:24:15 +00:00
|
|
|
async handleVirtualKey(keyval) {
|
|
|
|
try {
|
|
|
|
if (!await this._context.process_key_event_async(
|
|
|
|
keyval, 0, 0, -1, null))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
await this._context.process_key_event_async(
|
|
|
|
keyval, 0, IBus.ModifierType.RELEASE_MASK, -1, null);
|
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-22 11:28:02 +00:00
|
|
|
}
|
2022-10-17 11:31:45 +00:00
|
|
|
|
|
|
|
update() {
|
|
|
|
if (!this._context)
|
|
|
|
return;
|
|
|
|
this._updateCapabilities();
|
|
|
|
this._context.set_content_type(this._purpose, this._hints);
|
|
|
|
this._context.set_cursor_location(
|
|
|
|
this._cursorRect.x, this._cursorRect.y,
|
|
|
|
this._cursorRect.width, this._cursorRect.height);
|
|
|
|
this._emitRequestSurrounding();
|
|
|
|
}
|
2017-12-05 19:05:00 +00:00
|
|
|
});
|