From 944c28f3b34192ec2faacf245249d03f20c6eead Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Wed, 27 Mar 2013 01:01:33 +0100 Subject: [PATCH] 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 --- js/ui/status/keyboard.js | 40 ++++++++++++++++++++++++++++++++++++---- src/shell-global.c | 7 +++++++ src/shell-global.h | 2 ++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index 4880fd2bb..0dbcc4ac4 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -33,6 +33,33 @@ const KEY_INPUT_SOURCES = 'sources'; const INPUT_SOURCE_TYPE_XKB = 'xkb'; 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 = + + + + +; + +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({ Name: 'IBusManager', @@ -364,6 +391,13 @@ const InputSourceIndicator = new Lang.Class({ this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated)); 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._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); is.connect('activate', Lang.bind(this, function() { - if (this._currentSource && this._currentSource.index == is.index) - return; - this._settings.set_value(KEY_CURRENT_INPUT_SOURCE, - GLib.Variant.new_uint32(is.index)); + holdKeyboard(); + this._keyboardManager.SetInputSourceRemote(is.index, releaseKeyboard); })); if (!(is.shortName in inputSourcesByShortName)) diff --git a/src/shell-global.c b/src/shell-global.c index da7732bf9..4a82b9533 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -1007,6 +1007,13 @@ shell_global_end_modal (ShellGlobal *global, 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. * * Authors: Padraig O'Briain, Matthias Clasen, Lennart Poettering diff --git a/src/shell-global.h b/src/shell-global.h index 38532b5ee..c93cb1bdf 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -44,6 +44,8 @@ gboolean shell_global_begin_modal (ShellGlobal *global, MetaModalOptions options); void shell_global_end_modal (ShellGlobal *global, guint32 timestamp); +void shell_global_freeze_keyboard (ShellGlobal *global, + guint32 timestamp); typedef enum { SHELL_STAGE_INPUT_MODE_NORMAL,