[Spice-commits] 2 commits - gtk/spice-gtk-session.c gtk/spice-gtk-session.h gtk/spice-widget.c

Jonathon Jongsma jjongsma at kemper.freedesktop.org
Thu Apr 3 14:09:08 PDT 2014


 gtk/spice-gtk-session.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/spice-gtk-session.h |    1 
 gtk/spice-widget.c      |   91 -----------------------------------------
 3 files changed, 109 insertions(+), 89 deletions(-)

New commits:
commit d06b256710cf91aec1275785d8cd65283581f544
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Mon Mar 31 11:07:53 2014 -0500

    Use GdkKeymap to listen for keyboard modifier changes
    
    Connect to the GdkKeymap::state-changed signal to detect when the client
    keyboard modifiers have changed. This keeps the client and the guest in sync
    even when the SpiceDisplay widget isn't focused. New values are only sent down
    to the guest if the new value is different than the current value.

diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
index f0f7edf..fe77f47 100644
--- a/gtk/spice-gtk-session.c
+++ b/gtk/spice-gtk-session.c
@@ -171,6 +171,12 @@ static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio
         spice_inputs_set_key_locks(inputs, client_modifiers);
 }
 
+static void keymap_modifiers_changed(GdkKeymap *keymap, gpointer data)
+{
+    SpiceGtkSession *self = data;
+    spice_gtk_session_sync_keyboard_modifiers(self);
+}
+
 static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer data)
 {
     SpiceGtkSession *self = data;
@@ -180,6 +186,7 @@ static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer data)
 static void spice_gtk_session_init(SpiceGtkSession *self)
 {
     SpiceGtkSessionPrivate *s;
+    GdkKeymap *keymap = gdk_keymap_get_default();
 
     s = self->priv = SPICE_GTK_SESSION_GET_PRIVATE(self);
 
@@ -189,6 +196,8 @@ static void spice_gtk_session_init(SpiceGtkSession *self)
     s->clipboard_primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
     g_signal_connect(G_OBJECT(s->clipboard_primary), "owner-change",
                      G_CALLBACK(clipboard_owner_change), self);
+    spice_g_signal_connect_object(keymap, "state-changed",
+                                  G_CALLBACK(keymap_modifiers_changed), self, 0);
 }
 
 static GObject *
commit 9c75c7ee33d8567fef88594ae7844b9121c6291f
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Mon Mar 31 10:52:49 2014 -0500

    Ensure keyboard modifiers are synchronized properly
    
    In certain circumstances, the keyboard modifiers get out-of-sync between the
    guest and the client. This is easy to reproduce with the following steps:
     - launch virt-viewer with a guest that is not running
     - start the guest
     - while guest is booting, enable CAPS LOCK on the client
     - after guest finishes booting, it will set its modifiers to a default value
       (e.g. numlock on, capslock off)
     - now capslock is OFF in the guest, but ON in the client
     - toggle caps lock
     - now capslock is ON in the guest, but OFF in the client
    
    This moves the responsibility for synchronizing client and guest modifiers into
    SpiceGtkSession. It can't be handled easily within the SpiceDisplay widget since
    there can be multiple display widgets for each inputs channel.
    
    A new function (spice_gtk_session_sync_keyboard_modifiers()) was added so that
    synchronization can be triggered manually if desired. But it also registers a
    signal handler for the InputsChannel::inputs-modifiers signal to detect when the
    guest has changed its modifiers. The signal handler simply overrides the guests
    modifiers and sets them back to the value from the client.

diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
index a9ce025..f0f7edf 100644
--- a/gtk/spice-gtk-session.c
+++ b/gtk/spice-gtk-session.c
@@ -17,6 +17,22 @@
 */
 #include "config.h"
 
+#if HAVE_X11_XKBLIB_H
+#include <X11/XKBlib.h>
+#include <gdk/gdkx.h>
+#endif
+#ifdef GDK_WINDOWING_X11
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+#endif
+#ifdef WIN32
+#include <windows.h>
+#include <gdk/gdkwin32.h>
+#ifndef MAPVK_VK_TO_VSC /* may be undefined in older mingw-headers */
+#define MAPVK_VK_TO_VSC 0
+#endif
+#endif
+
 #include <gtk/gtk.h>
 #include <spice/vd_agent.h>
 #include "desktop-integration.h"
@@ -97,6 +113,70 @@ enum {
     PROP_AUTO_USBREDIR,
 };
 
+static guint32 get_keyboard_lock_modifiers(void)
+{
+    guint32 modifiers = 0;
+#if HAVE_X11_XKBLIB_H
+    Display *x_display = NULL;
+    XKeyboardState keyboard_state;
+
+    GdkScreen *screen = gdk_screen_get_default();
+    if (!GDK_IS_X11_DISPLAY(gdk_screen_get_display(screen))) {
+        SPICE_DEBUG("FIXME: gtk backend is not X11");
+        return 0;
+    }
+
+    x_display = GDK_SCREEN_XDISPLAY(screen);
+    XGetKeyboardControl(x_display, &keyboard_state);
+
+    if (keyboard_state.led_mask & 0x01) {
+        modifiers |= SPICE_INPUTS_CAPS_LOCK;
+    }
+    if (keyboard_state.led_mask & 0x02) {
+        modifiers |= SPICE_INPUTS_NUM_LOCK;
+    }
+    if (keyboard_state.led_mask & 0x04) {
+        modifiers |= SPICE_INPUTS_SCROLL_LOCK;
+    }
+#elif defined(win32)
+    if (GetKeyState(VK_CAPITAL) & 1) {
+        modifiers |= SPICE_INPUTS_CAPS_LOCK;
+    }
+    if (GetKeyState(VK_NUMLOCK) & 1) {
+        modifiers |= SPICE_INPUTS_NUM_LOCK;
+    }
+    if (GetKeyState(VK_SCROLL) & 1) {
+        modifiers |= SPICE_INPUTS_SCROLL_LOCK;
+    }
+#else
+    g_warning("get_keyboard_lock_modifiers not implemented");
+#endif // HAVE_X11_XKBLIB_H
+    return modifiers;
+}
+
+static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSession *self,
+                                                                  SpiceInputsChannel* inputs)
+{
+    gint guest_modifiers = 0, client_modifiers = 0;
+
+    g_return_if_fail(SPICE_IS_INPUTS_CHANNEL(inputs));
+
+    g_object_get(inputs, "key-modifiers", &guest_modifiers, NULL);
+
+    client_modifiers = get_keyboard_lock_modifiers();
+    g_debug("%s: input:%p client_modifiers:0x%x, guest_modifiers:0x%x",
+            G_STRFUNC, inputs, client_modifiers, guest_modifiers);
+
+    if (client_modifiers != guest_modifiers)
+        spice_inputs_set_key_locks(inputs, client_modifiers);
+}
+
+static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer data)
+{
+    SpiceGtkSession *self = data;
+    spice_gtk_session_sync_keyboard_modifiers_for_channel(self, inputs);
+}
+
 static void spice_gtk_session_init(SpiceGtkSession *self)
 {
     SpiceGtkSessionPrivate *s;
@@ -872,6 +952,11 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,
         g_signal_connect(channel, "main-clipboard-selection-release",
                          G_CALLBACK(clipboard_release), self);
     }
+    if (SPICE_IS_INPUTS_CHANNEL(channel)) {
+        spice_g_signal_connect_object(channel, "inputs-modifiers",
+                                      G_CALLBACK(guest_modifiers_changed), self, 0);
+        spice_gtk_session_sync_keyboard_modifiers_for_channel(self, SPICE_INPUTS_CHANNEL(channel));
+    }
 }
 
 static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
@@ -1029,3 +1114,15 @@ void spice_gtk_session_paste_from_guest(SpiceGtkSession *self)
     s->clipboard_by_guest[selection] = TRUE;
     s->clip_hasdata[selection] = FALSE;
 }
+
+void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self)
+{
+    GList *l = NULL, *channels = spice_session_get_channels(self->priv->session);
+
+    for (l = channels; l != NULL; l = l->next) {
+        if (SPICE_IS_INPUTS_CHANNEL(l->data)) {
+            SpiceInputsChannel *inputs = SPICE_INPUTS_CHANNEL(l->data);
+            spice_gtk_session_sync_keyboard_modifiers_for_channel(self, inputs);
+        }
+    }
+}
diff --git a/gtk/spice-gtk-session.h b/gtk/spice-gtk-session.h
index 3b4eac6..fbcc353 100644
--- a/gtk/spice-gtk-session.h
+++ b/gtk/spice-gtk-session.h
@@ -59,6 +59,7 @@ GType spice_gtk_session_get_type(void);
 SpiceGtkSession *spice_gtk_session_get(SpiceSession *session);
 void spice_gtk_session_copy_to_guest(SpiceGtkSession *self);
 void spice_gtk_session_paste_from_guest(SpiceGtkSession *self);
+void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self);
 
 G_END_DECLS
 
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index 0e4a0de..2044513 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -131,7 +131,6 @@ static void try_mouse_ungrab(SpiceDisplay *display);
 static void recalc_geometry(GtkWidget *widget);
 static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data);
 static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer data);
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display);
 static void cursor_invalidate(SpiceDisplay *display);
 static void update_area(SpiceDisplay *display, gint x, gint y, gint width, gint height);
 static void release_keys(SpiceDisplay *display);
@@ -1457,7 +1456,8 @@ static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UN
         return true;
 
     release_keys(display);
-    sync_keyboard_lock_modifiers(display);
+    if (!d->disable_inputs)
+        spice_gtk_session_sync_keyboard_modifiers(d->gtk_session);
     update_keyboard_focus(display, true);
     try_keyboard_grab(display);
     update_display(display);
@@ -2411,7 +2411,6 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
     if (SPICE_IS_INPUTS_CHANNEL(channel)) {
         d->inputs = SPICE_INPUTS_CHANNEL(channel);
         spice_channel_connect(channel);
-        sync_keyboard_lock_modifiers(display);
         return;
     }
 
@@ -2600,89 +2599,3 @@ GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay *display)
     return pixbuf;
 }
 
-#if HAVE_X11_XKBLIB_H
-static guint32 get_keyboard_lock_modifiers(Display *x_display)
-{
-    XKeyboardState keyboard_state;
-    guint32 modifiers = 0;
-
-    XGetKeyboardControl(x_display, &keyboard_state);
-
-    if (keyboard_state.led_mask & 0x01) {
-        modifiers |= SPICE_INPUTS_CAPS_LOCK;
-    }
-    if (keyboard_state.led_mask & 0x02) {
-        modifiers |= SPICE_INPUTS_NUM_LOCK;
-    }
-    if (keyboard_state.led_mask & 0x04) {
-        modifiers |= SPICE_INPUTS_SCROLL_LOCK;
-    }
-    return modifiers;
-}
-
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)
-{
-    Display *x_display;
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
-    guint32 modifiers;
-    GdkWindow *w;
-
-    if (d->disable_inputs)
-        return;
-
-    w = gtk_widget_get_parent_window(GTK_WIDGET(display));
-    if (w == NULL) /* it can happen if the display is not yet shown */
-        return;
-
-    if (!GDK_IS_X11_DISPLAY(gdk_window_get_display(w))) {
-        SPICE_DEBUG("FIXME: gtk backend is not X11");
-        return;
-    }
-
-    x_display = GDK_WINDOW_XDISPLAY(w);
-    modifiers = get_keyboard_lock_modifiers(x_display);
-    if (d->inputs)
-        spice_inputs_set_key_locks(d->inputs, modifiers);
-}
-
-#elif defined (WIN32)
-static guint32 get_keyboard_lock_modifiers(void)
-{
-    guint32 modifiers = 0;
-
-    if (GetKeyState(VK_CAPITAL) & 1) {
-        modifiers |= SPICE_INPUTS_CAPS_LOCK;
-    }
-    if (GetKeyState(VK_NUMLOCK) & 1) {
-        modifiers |= SPICE_INPUTS_NUM_LOCK;
-    }
-    if (GetKeyState(VK_SCROLL) & 1) {
-        modifiers |= SPICE_INPUTS_SCROLL_LOCK;
-    }
-
-    return modifiers;
-}
-
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)
-{
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
-    guint32 modifiers;
-    GdkWindow *w;
-
-    if (d->disable_inputs)
-        return;
-
-    w = gtk_widget_get_parent_window(GTK_WIDGET(display));
-    if (w == NULL) /* it can happen if the display is not yet shown */
-        return;
-
-    modifiers = get_keyboard_lock_modifiers();
-    if (d->inputs)
-        spice_inputs_set_key_locks(d->inputs, modifiers);
-}
-#else
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)
-{
-    g_warning("sync_keyboard_lock_modifiers not implemented");
-}
-#endif // HAVE_X11_XKBLIB_H


More information about the Spice-commits mailing list