status/keyboard: Synchronize input source switching with key events

Currently we simply set the gsettings key when activating an input
source. This obviously introduces a time window, between the event that
activates the switch and when the switch is complete, under which key
events are being delivered to applications and interpreted according
to the previous input source.

The patches in bug 696996 introduce a DBus API in g-s-d that allows us
to know when an input source if effectively active. Using that and
freezing keyboard events in the X server until we hear back from g-s-d
we can ensure that events won't be misinterpreted after an input
source switch.

https://bugzilla.gnome.org/show_bug.cgi?id=697007
This commit is contained in:
Rui Matos 2013-03-27 01:01:33 +01:00
parent c13a597fe0
commit 944c28f3b3
3 changed files with 45 additions and 4 deletions

View File

@ -33,6 +33,33 @@ const KEY_INPUT_SOURCES = 'sources';
const INPUT_SOURCE_TYPE_XKB = 'xkb'; const INPUT_SOURCE_TYPE_XKB = 'xkb';
const INPUT_SOURCE_TYPE_IBUS = 'ibus'; const INPUT_SOURCE_TYPE_IBUS = 'ibus';
// This is the longest we'll keep the keyboard frozen until an input
// source is active.
const MAX_INPUT_SOURCE_ACTIVATION_TIME = 4000; // ms
const BUS_NAME = 'org.gnome.SettingsDaemon.Keyboard';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Keyboard';
const KeyboardManagerInterface =
<interface name="org.gnome.SettingsDaemon.Keyboard">
<method name="SetInputSource">
<arg type="u" direction="in" />
</method>
</interface>;
const KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
function releaseKeyboard() {
if (Main.modalCount > 0)
global.display.unfreeze_keyboard(global.get_current_time());
else
global.display.ungrab_keyboard(global.get_current_time());
}
function holdKeyboard() {
global.freeze_keyboard(global.get_current_time());
}
const IBusManager = new Lang.Class({ const IBusManager = new Lang.Class({
Name: 'IBusManager', Name: 'IBusManager',
@ -364,6 +391,13 @@ const InputSourceIndicator = new Lang.Class({
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated)); this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
this._inputSourcesChanged(); this._inputSourcesChanged();
this._keyboardManager = new KeyboardManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
function(proxy, error) {
if (error)
log(error.message);
});
this._keyboardManager.g_default_timeout = MAX_INPUT_SOURCE_ACTIVATION_TIME;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout)); this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
@ -488,10 +522,8 @@ const InputSourceIndicator = new Lang.Class({
let is = new InputSource(type, id, displayName, shortName, i); let is = new InputSource(type, id, displayName, shortName, i);
is.connect('activate', Lang.bind(this, function() { is.connect('activate', Lang.bind(this, function() {
if (this._currentSource && this._currentSource.index == is.index) holdKeyboard();
return; this._keyboardManager.SetInputSourceRemote(is.index, releaseKeyboard);
this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
GLib.Variant.new_uint32(is.index));
})); }));
if (!(is.shortName in inputSourcesByShortName)) if (!(is.shortName in inputSourcesByShortName))

View File

@ -1007,6 +1007,13 @@ shell_global_end_modal (ShellGlobal *global,
meta_plugin_end_modal (global->plugin, timestamp); meta_plugin_end_modal (global->plugin, timestamp);
} }
void
shell_global_freeze_keyboard (ShellGlobal *global,
guint32 timestamp)
{
meta_display_freeze_keyboard (global->meta_display, global->stage_xwindow, timestamp);
}
/* Code to close all file descriptors before we exec; copied from gspawn.c in GLib. /* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
* *
* Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering

View File

@ -44,6 +44,8 @@ gboolean shell_global_begin_modal (ShellGlobal *global,
MetaModalOptions options); MetaModalOptions options);
void shell_global_end_modal (ShellGlobal *global, void shell_global_end_modal (ShellGlobal *global,
guint32 timestamp); guint32 timestamp);
void shell_global_freeze_keyboard (ShellGlobal *global,
guint32 timestamp);
typedef enum { typedef enum {
SHELL_STAGE_INPUT_MODE_NORMAL, SHELL_STAGE_INPUT_MODE_NORMAL,