diff --git a/js/misc/ibusManager.js b/js/misc/ibusManager.js index 06d808d3f..529352ab2 100644 --- a/js/misc/ibusManager.js +++ b/js/misc/ibusManager.js @@ -8,7 +8,7 @@ const Signals = imports.signals; try { var IBus = imports.gi.IBus; - _checkIBusVersion(); + _checkIBusVersion(1, 5, 2); const IBusCandidatePopup = imports.ui.ibusCandidatePopup; } catch (e) { var IBus = null; @@ -17,11 +17,7 @@ try { let _ibusManager = null; -function _checkIBusVersion() { - var requiredMajor = 1; - var requiredMinor = 5; - var requiredMicro = 2; - +function _checkIBusVersion(requiredMajor, requiredMinor, requiredMicro) { if ((IBus.MAJOR_VERSION > requiredMajor) || (IBus.MAJOR_VERSION == requiredMajor && IBus.MINOR_VERSION > requiredMinor) || (IBus.MAJOR_VERSION == requiredMajor && IBus.MINOR_VERSION == requiredMinor && @@ -125,6 +121,16 @@ const IBusManager = new Lang.Class({ object_path: IBus.PATH_PANEL }); this._candidatePopup.setPanelService(this._panelService); this._panelService.connect('update-property', Lang.bind(this, this._updateProperty)); + try { + // IBus versions older than 1.5.10 have a bug which + // causes spurious set-content-type emissions when + // switching input focus that temporarily lose purpose + // and hints defeating its intended semantics and + // confusing users. We thus don't use it in that case. + _checkIBusVersion(1, 5, 10); + this._panelService.connect('set-content-type', Lang.bind(this, this._setContentType)); + } catch (e) { + } // If an engine is already active we need to get its properties this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) { let engine; @@ -174,6 +180,10 @@ const IBusManager = new Lang.Class({ this.emit('property-updated', this._currentEngineName, prop); }, + _setContentType: function(panel, purpose, hints) { + this.emit('set-content-type', purpose, hints); + }, + activateProperty: function(key, state) { this._panelService.property_activate(key, state); }, @@ -186,7 +196,10 @@ const IBusManager = new Lang.Class({ }, setEngine: function(id, callback) { - if (!IBus || !this._ready || id == this._currentEngineName) { + // Send id even if id == this._currentEngineName + // because 'properties-registered' signal can be emitted + // while this._ibusSources == null on a lock screen. + if (!IBus || !this._ready) { if (callback) callback(); return; diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index 897497a54..3595a39d0 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -155,6 +155,7 @@ const InputSourceManager = new Lang.Class({ this._ibusSources = {}; this._currentSource = null; + this._backupSource = null; // All valid input sources currently in the gsettings // KEY_INPUT_SOURCES list ordered by most recently used @@ -183,6 +184,7 @@ const InputSourceManager = new Lang.Class({ this._ibusManager.connect('ready', Lang.bind(this, this._ibusReadyCallback)); this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered)); this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated)); + this._ibusManager.connect('set-content-type', Lang.bind(this, this._ibusSetContentType)); global.display.connect('modifiers-accelerator-activated', Lang.bind(this, this._modifiersSwitcher)); @@ -192,6 +194,7 @@ const InputSourceManager = new Lang.Class({ this._overviewHiddenId = 0; this._settings.connect('changed::per-window', Lang.bind(this, this._sourcesPerWindowChanged)); this._sourcesPerWindowChanged(); + this._disableIBus = false; }, reload: function() { @@ -309,6 +312,8 @@ const InputSourceManager = new Lang.Class({ [exists, displayName, shortName, , ] = this._xkbInfo.get_layout_info(id); } else if (type == INPUT_SOURCE_TYPE_IBUS) { + if (this._disableIBus) + continue; let engineDesc = this._ibusManager.getEngineDesc(id); if (engineDesc) { let language = IBus.get_language_name(engineDesc.get_language()); @@ -379,8 +384,20 @@ const InputSourceManager = new Lang.Class({ } this._mruSources = mruSources.concat(sourcesList); - if (this._mruSources.length > 0) + if (this._mruSources.length > 0) { + if (!this._disableIBus && this._backupSource) { + for (let i = 0; i < this._mruSources.length; i++) { + if (this._mruSources[i].type == this._backupSource.type && + this._mruSources[i].id == this._backupSource.id) { + let currentSource = this._mruSources.splice(i, 1); + this._mruSources = currentSource.concat(this._mruSources); + break; + } + } + this._backupSource = null; + } this._mruSources[0].activate(); + } // All ibus engines are preloaded here to reduce the launching time // when users switch the input sources. @@ -437,6 +454,27 @@ const InputSourceManager = new Lang.Class({ return false; }, + _ibusSetContentType: function(im, purpose, hints) { + if (purpose == IBus.InputPurpose.PASSWORD) { + if (Object.keys(this._inputSources).length == Object.keys(this._ibusSources).length) + return; + + if (this._disableIBus) + return; + this._disableIBus = true; + this._backupSource = this._currentSource; + } else { + if (!this._disableIBus) + return; + this._disableIBus = false; + } + // If this._mruSources is not cleared before this.reload() is called, + // the order is different from the original one as IM sources will + // be appended to XKB sources. + this._mruSources = []; + this.reload(); + }, + _getNewInputSource: function(current) { for (let i in this._inputSources) { let is = this._inputSources[i];