[gnome-shell/gnome-3-8] status/keyboard: Synchronize input source switching with key events



commit cd7197e60570cb2f5c8a669fd097ed5d44d78b58
Author: Rui Matos <tiagomatos gmail com>
Date:   Wed Mar 27 01:01:33 2013 +0100

    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 2e85561..fbf56c0 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 =
+<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({
     Name: 'IBusManager',
 
@@ -356,6 +383,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));
 
@@ -479,10 +513,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 889e146..74af6cd 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -1009,6 +1009,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 a8df0f5..046d0ed 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_NONREACTIVE,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]