<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Apr 2, 2014 at 5:58 PM, Jonathon Jongsma <span dir="ltr"><<a href="mailto:jjongsma@redhat.com" target="_blank">jjongsma@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In certain circumstances, the keyboard modifiers get out-of-sync between the<br>
guest and the client. This is easy to reproduce with the following steps:<br>
 - launch virt-viewer with a guest that is not running<br>
 - start the guest<br>
 - while guest is booting, enable CAPS LOCK on the client<br>
 - after guest finishes booting, it will set its modifiers to a default value<br>
   (e.g. numlock on, capslock off)<br>
 - now capslock is OFF in the guest, but ON in the client<br>
 - toggle caps lock<br>
 - now capslock is ON in the guest, but OFF in the client<br>
<br>
This fix consists of two parts. The first is that we register a signal handler<br>
for the InputsChannel::inputs-modifiers signal to detect when the guest has<br>
changed its modifiers. The signal handler simply overrides the guests modifiers<br>
and sets them back to the value from the client.<br>
<br>
In order to avoid sending this message down to the guest multiple times, I've<br>
introduce a singleton SpiceKeyboardStateMonitor object that is responsible for<br>
synchronizing keyboard modifier state. Unfortunately it can't be done directly<br>
within the InputsChannel object since it depends on Gdk.<br></blockquote><div><br></div><div>I think you should have done it in gtk-session, which is a singleton for the session and is gtk-aware.<br></div><div>Why having a gobject with a property if the object is all private?<br>
 <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
---<br>
 gtk/Makefile.am                    |   2 +<br>
 gtk/spice-keyboard-state-monitor.c | 223 +++++++++++++++++++++++++++++++++++++<br>
 gtk/spice-keyboard-state-monitor.h |  56 ++++++++++<br>
 gtk/spice-widget.c                 |  95 +---------------<br>
 4 files changed, 287 insertions(+), 89 deletions(-)<br>
 create mode 100644 gtk/spice-keyboard-state-monitor.c<br>
 create mode 100644 gtk/spice-keyboard-state-monitor.h<br>
<br>
diff --git a/gtk/Makefile.am b/gtk/Makefile.am<br>
index 2e38cce..b8f42a9 100644<br>
--- a/gtk/Makefile.am<br>
+++ b/gtk/Makefile.am<br>
@@ -126,6 +126,8 @@ SPICE_GTK_SOURCES_COMMON =          \<br>
        spice-util-priv.h               \<br>
        spice-gtk-session.c             \<br>
        spice-gtk-session-priv.h        \<br>
+       spice-keyboard-state-monitor.c  \<br>
+       spice-keyboard-state-monitor.h  \<br>
        spice-widget.c                  \<br>
        spice-widget-priv.h             \<br>
        vncdisplaykeymap.c              \<br>
diff --git a/gtk/spice-keyboard-state-monitor.c b/gtk/spice-keyboard-state-monitor.c<br>
new file mode 100644<br>
index 0000000..161dc43<br>
--- /dev/null<br>
+++ b/gtk/spice-keyboard-state-monitor.c<br>
@@ -0,0 +1,223 @@<br>
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */<br>
+/*<br>
+   Copyright (C) 2014 Red Hat, Inc.<br>
+<br>
+   This library is free software; you can redistribute it and/or<br>
+   modify it under the terms of the GNU Lesser General Public<br>
+   License as published by the Free Software Foundation; either<br>
+   version 2.1 of the License, or (at your option) any later version.<br>
+<br>
+   This library is distributed in the hope that it will be useful,<br>
+   but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+   Lesser General Public License for more details.<br>
+<br>
+   You should have received a copy of the GNU Lesser General Public<br>
+   License along with this library; if not, see <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
+   */<br>
+<br>
+#ifdef HAVE_CONFIG_H<br>
+#include "config.h"<br>
+#endif<br>
+<br>
+#if HAVE_X11_XKBLIB_H<br>
+#include <X11/XKBlib.h><br>
+#include <gdk/gdkx.h><br>
+#endif<br>
+#ifdef GDK_WINDOWING_X11<br>
+#include <X11/Xlib.h><br>
+#include <gdk/gdkx.h><br>
+#endif<br>
+#ifdef WIN32<br>
+#include <windows.h><br>
+#include <gdk/gdkwin32.h><br>
+#ifndef MAPVK_VK_TO_VSC /* may be undefined in older mingw-headers */<br>
+#define MAPVK_VK_TO_VSC 0<br>
+#endif<br>
+#endif<br>
+<br>
+#include "channel-inputs.h"<br>
+#include "spice-keyboard-state-monitor.h"<br>
+<br>
+#include <gdk/gdk.h><br>
+<br>
+G_DEFINE_TYPE(SpiceKeyboardStateMonitor, spice_keyboard_state_monitor, G_TYPE_OBJECT)<br>
+<br>
+#define KEYBOARD_STATE_MONITOR_PRIVATE(o) \<br>
+        (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_KEYBOARD_STATE_MONITOR, SpiceKeyboardStateMonitorPrivate))<br>
+<br>
+    struct _SpiceKeyboardStateMonitorPrivate<br>
+{<br>
+    GList *inputs_channels;<br>
+    gboolean override_guest_modifiers;<br>
+};<br>
+<br>
+enum {<br>
+    PROP_0,<br>
+    PROP_OVERRIDE_GUEST_MODIFIERS<br>
+};<br>
+<br>
+static void spice_keyboard_state_monitor_finalize(GObject *object)<br>
+{<br>
+    SpiceKeyboardStateMonitor *self = SPICE_KEYBOARD_STATE_MONITOR(object);<br>
+    g_list_free(self->priv->inputs_channels);<br>
+    G_OBJECT_CLASS(spice_keyboard_state_monitor_parent_class)->finalize(object);<br>
+}<br>
+<br>
+static void spice_keyboard_state_monitor_get_property(GObject *object,<br>
+                                                      guint prop_id,<br>
+                                                      GValue *value,<br>
+                                                      GParamSpec *pspec)<br>
+{<br>
+    SpiceKeyboardStateMonitor *self = SPICE_KEYBOARD_STATE_MONITOR(object);<br>
+    switch (prop_id) {<br>
+        case PROP_OVERRIDE_GUEST_MODIFIERS:<br>
+            g_value_set_boolean(value, self->priv->override_guest_modifiers);<br>
+            break;<br>
+        default:<br>
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);<br>
+            break;<br>
+    }<br>
+}<br>
+<br>
+static void spice_keyboard_state_monitor_set_property(GObject *object,<br>
+                                                      guint prop_id,<br>
+                                                      const GValue *value,<br>
+                                                      GParamSpec *pspec)<br>
+{<br>
+    SpiceKeyboardStateMonitor *self = SPICE_KEYBOARD_STATE_MONITOR(object);<br>
+    switch (prop_id) {<br>
+        case PROP_OVERRIDE_GUEST_MODIFIERS:<br>
+            self->priv->override_guest_modifiers = g_value_get_boolean(value);<br>
+            break;<br>
+        default:<br>
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);<br>
+            break;<br>
+    }<br>
+}<br>
+<br>
+static void spice_keyboard_state_monitor_class_init(SpiceKeyboardStateMonitorClass *klass)<br>
+{<br>
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);<br>
+<br>
+    g_type_class_add_private(klass, sizeof (SpiceKeyboardStateMonitorPrivate));<br>
+<br>
+    object_class->get_property = spice_keyboard_state_monitor_get_property;<br>
+    object_class->set_property = spice_keyboard_state_monitor_set_property;<br>
+    object_class->finalize = spice_keyboard_state_monitor_finalize;<br>
+<br>
+    g_object_class_install_property(object_class, PROP_OVERRIDE_GUEST_MODIFIERS,<br>
+                                    g_param_spec_boolean("override-guest-modifiers",<br>
+                                                         "Override guest modifiers",<br>
+                                                         "Whether guest modifiers should be overriidden by client modifiers",<br>
+                                                         TRUE,<br>
+                                                         G_PARAM_READWRITE |<br>
+                                                         G_PARAM_CONSTRUCT |<br>
+                                                         G_PARAM_STATIC_STRINGS));<br>
+}<br>
+<br>
+static guint32 get_keyboard_lock_modifiers(void)<br>
+{<br>
+    guint32 modifiers = 0;<br>
+#if HAVE_X11_XKBLIB_H<br>
+    Display *x_display = NULL;<br>
+    XKeyboardState keyboard_state;<br>
+<br>
+    GdkScreen *screen = gdk_screen_get_default();<br>
+    if (!GDK_IS_X11_DISPLAY(gdk_screen_get_display(screen))) {<br>
+        SPICE_DEBUG("FIXME: gtk backend is not X11");<br>
+        return 0;<br>
+    }<br>
+<br>
+    x_display = GDK_SCREEN_XDISPLAY(screen);<br>
+    XGetKeyboardControl(x_display, &keyboard_state);<br>
+<br>
+    if (keyboard_state.led_mask & 0x01) {<br>
+        modifiers |= SPICE_INPUTS_CAPS_LOCK;<br>
+    }<br>
+    if (keyboard_state.led_mask & 0x02) {<br>
+        modifiers |= SPICE_INPUTS_NUM_LOCK;<br>
+    }<br>
+    if (keyboard_state.led_mask & 0x04) {<br>
+        modifiers |= SPICE_INPUTS_SCROLL_LOCK;<br>
+    }<br>
+#elif defined(win32)<br>
+    if (GetKeyState(VK_CAPITAL) & 1) {<br>
+        modifiers |= SPICE_INPUTS_CAPS_LOCK;<br>
+    }<br>
+    if (GetKeyState(VK_NUMLOCK) & 1) {<br>
+        modifiers |= SPICE_INPUTS_NUM_LOCK;<br>
+    }<br>
+    if (GetKeyState(VK_SCROLL) & 1) {<br>
+        modifiers |= SPICE_INPUTS_SCROLL_LOCK;<br>
+    }<br>
+#else<br>
+    g_warning("get_keyboard_lock_modifiers not implemented");<br>
+#endif // HAVE_X11_XKBLIB_H<br>
+    return modifiers;<br>
+}<br>
+<br>
+static void spice_keyboard_state_monitor_init(SpiceKeyboardStateMonitor *self)<br>
+{<br>
+    self->priv = KEYBOARD_STATE_MONITOR_PRIVATE(self);<br>
+}<br>
+<br>
+static gpointer spice_keyboard_state_monitor_new(gpointer data)<br>
+{<br>
+    return g_object_new(SPICE_TYPE_KEYBOARD_STATE_MONITOR, NULL);<br>
+}<br>
+<br>
+SpiceKeyboardStateMonitor* spice_keyboard_state_monitor_get_default(void)<br>
+{<br>
+    static GOnce once = G_ONCE_INIT;<br>
+    g_once(&once, spice_keyboard_state_monitor_new, NULL);<br>
+    return once.retval;<br>
+}<br>
+<br>
+static void spice_keyboard_state_monitor_sync_one(SpiceKeyboardStateMonitor *self,<br>
+                                                  SpiceInputsChannel* inputs)<br>
+{<br>
+    gint guest_modifiers = 0, client_modifiers = 0;<br>
+<br>
+    g_return_if_fail(SPICE_IS_INPUTS_CHANNEL(inputs));<br>
+<br>
+    g_object_get(inputs, "key-modifiers", &guest_modifiers, NULL);<br>
+<br>
+    client_modifiers = get_keyboard_lock_modifiers();<br>
+    g_debug("%s: input:%p client_modifiers:0x%x, guest_modifiers:0x%x",<br>
+            G_STRFUNC, inputs, client_modifiers, guest_modifiers);<br>
+<br>
+    if (client_modifiers != guest_modifiers)<br>
+        spice_inputs_set_key_locks(inputs, client_modifiers);<br>
+}<br>
+<br>
+void spice_keyboard_state_monitor_sync_modifiers(SpiceKeyboardStateMonitor *self)<br>
+{<br>
+    g_debug("%s: modifiers", G_STRFUNC);<br>
+    GList *l = self->priv->inputs_channels;<br>
+    for (; l; l = l->next) {<br>
+        SpiceInputsChannel *inputs = SPICE_INPUTS_CHANNEL(l->data);<br>
+        spice_keyboard_state_monitor_sync_one(self, inputs);<br>
+    }<br>
+}<br>
+<br>
+static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer data)<br>
+{<br>
+    SpiceKeyboardStateMonitor *self = data;<br>
+    if (self->priv->override_guest_modifiers)<br>
+        spice_keyboard_state_monitor_sync_one(self, inputs);<br>
+}<br>
+<br>
+void spice_keyboard_state_monitor_register_inputs_channel(SpiceKeyboardStateMonitor *self,<br>
+                                                              SpiceInputsChannel *inputs)<br>
+{<br>
+    /* avoid registering the same channel multiple times */<br>
+    if (g_list_find(self->priv->inputs_channels, inputs) != NULL)<br>
+        return;<br>
+<br>
+    spice_g_signal_connect_object(inputs, "inputs-modifiers",<br>
+                                  G_CALLBACK(guest_modifiers_changed), self, 0);<br>
+    self->priv->inputs_channels = g_list_append(self->priv->inputs_channels,<br>
+                                                inputs);<br>
+}<br>
+<br>
diff --git a/gtk/spice-keyboard-state-monitor.h b/gtk/spice-keyboard-state-monitor.h<br>
new file mode 100644<br>
index 0000000..2c2033a<br>
--- /dev/null<br>
+++ b/gtk/spice-keyboard-state-monitor.h<br>
@@ -0,0 +1,56 @@<br>
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */<br>
+/*<br>
+   Copyright (C) 2014 Red Hat, Inc.<br>
+<br>
+   This library is free software; you can redistribute it and/or<br>
+   modify it under the terms of the GNU Lesser General Public<br>
+   License as published by the Free Software Foundation; either<br>
+   version 2.1 of the License, or (at your option) any later version.<br>
+<br>
+   This library is distributed in the hope that it will be useful,<br>
+   but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
+   Lesser General Public License for more details.<br>
+<br>
+   You should have received a copy of the GNU Lesser General Public<br>
+   License along with this library; if not, see <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
+*/<br>
+#ifndef __SPICE_KEYBOARD_STATE_MONITOR_H__<br>
+#define __SPICE_KEYBOARD_STATE_MONITOR_H__<br>
+<br>
+#include <glib-object.h><br>
+#include "channel-inputs.h"<br>
+<br>
+G_BEGIN_DECLS<br>
+<br>
+#define SPICE_TYPE_KEYBOARD_STATE_MONITOR               spice_keyboard_state_monitor_get_type()<br>
+#define SPICE_KEYBOARD_STATE_MONITOR(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_KEYBOARD_STATE_MONITOR, SpiceKeyboardStateMonitor))<br>
+#define SPICE_KEYBOARD_STATE_MONITOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_KEYBOARD_STATE_MONITOR, SpiceKeyboardStateMonitorClass))<br>
+#define SPICE_IS_KEYBOARD_STATE_MONITOR(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), SPICE_TYPE_KEYBOARD_STATE_MONITOR))<br>
+#define SPICE_IS_KEYBOARD_STATE_MONITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_KEYBOARD_STATE_MONITOR))<br>
+#define SPICE_KEYBOARD_STATE_MONITOR_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_KEYBOARD_STATE_MONITOR, SpiceKeyboardStateMonitorClass))<br>
+<br>
+typedef struct _SpiceKeyboardStateMonitor SpiceKeyboardStateMonitor;<br>
+typedef struct _SpiceKeyboardStateMonitorClass SpiceKeyboardStateMonitorClass;<br>
+typedef struct _SpiceKeyboardStateMonitorPrivate SpiceKeyboardStateMonitorPrivate;<br>
+<br>
+struct _SpiceKeyboardStateMonitor<br>
+{<br>
+    GObject parent;<br>
+    SpiceKeyboardStateMonitorPrivate *priv;<br>
+};<br>
+<br>
+struct _SpiceKeyboardStateMonitorClass<br>
+{<br>
+    GObjectClass parent_class;<br>
+};<br>
+<br>
+GType spice_keyboard_state_monitor_get_type(void) G_GNUC_CONST;<br>
+<br>
+SpiceKeyboardStateMonitor *spice_keyboard_state_monitor_get_default(void);<br>
+void spice_keyboard_state_monitor_register_inputs_channel(SpiceKeyboardStateMonitor *self, SpiceInputsChannel *inputs);<br>
+void spice_keyboard_state_monitor_sync_modifiers(SpiceKeyboardStateMonitor *self);<br>
+<br>
+G_END_DECLS<br>
+<br>
+#endif /* __SPICE_KEYBOARD_STATE_MONITOR_H__ */<br>
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c<br>
index 0e4a0de..dc9198c 100644<br>
--- a/gtk/spice-widget.c<br>
+++ b/gtk/spice-widget.c<br>
@@ -38,6 +38,7 @@<br>
 #include "spice-widget.h"<br>
 #include "spice-widget-priv.h"<br>
 #include "spice-gtk-session-priv.h"<br>
+#include "spice-keyboard-state-monitor.h"<br>
 #include "vncdisplaykeymap.h"<br>
<br>
 #include "glib-compat.h"<br>
@@ -131,7 +132,6 @@ static void try_mouse_ungrab(SpiceDisplay *display);<br>
 static void recalc_geometry(GtkWidget *widget);<br>
 static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data);<br>
 static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer data);<br>
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display);<br>
 static void cursor_invalidate(SpiceDisplay *display);<br>
 static void update_area(SpiceDisplay *display, gint x, gint y, gint width, gint height);<br>
 static void release_keys(SpiceDisplay *display);<br>
@@ -1457,7 +1457,8 @@ static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UN<br>
         return true;<br>
<br>
     release_keys(display);<br>
-    sync_keyboard_lock_modifiers(display);<br>
+    if (!d->disable_inputs)<br>
+        spice_keyboard_state_monitor_sync_modifiers(spice_keyboard_state_monitor_get_default());<br>
     update_keyboard_focus(display, true);<br>
     try_keyboard_grab(display);<br>
     update_display(display);<br>
@@ -2411,7 +2412,9 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)<br>
     if (SPICE_IS_INPUTS_CHANNEL(channel)) {<br>
         d->inputs = SPICE_INPUTS_CHANNEL(channel);<br>
         spice_channel_connect(channel);<br>
-        sync_keyboard_lock_modifiers(display);<br>
+        spice_keyboard_state_monitor_register_inputs_channel(spice_keyboard_state_monitor_get_default(), d->inputs);<br>
+        if (!d->disable_inputs)<br>
+            spice_keyboard_state_monitor_sync_modifiers(spice_keyboard_state_monitor_get_default());<br>
         return;<br>
     }<br>
<br>
@@ -2600,89 +2603,3 @@ GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay *display)<br>
     return pixbuf;<br>
 }<br>
<br>
-#if HAVE_X11_XKBLIB_H<br>
-static guint32 get_keyboard_lock_modifiers(Display *x_display)<br>
-{<br>
-    XKeyboardState keyboard_state;<br>
-    guint32 modifiers = 0;<br>
-<br>
-    XGetKeyboardControl(x_display, &keyboard_state);<br>
-<br>
-    if (keyboard_state.led_mask & 0x01) {<br>
-        modifiers |= SPICE_INPUTS_CAPS_LOCK;<br>
-    }<br>
-    if (keyboard_state.led_mask & 0x02) {<br>
-        modifiers |= SPICE_INPUTS_NUM_LOCK;<br>
-    }<br>
-    if (keyboard_state.led_mask & 0x04) {<br>
-        modifiers |= SPICE_INPUTS_SCROLL_LOCK;<br>
-    }<br>
-    return modifiers;<br>
-}<br>
-<br>
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)<br>
-{<br>
-    Display *x_display;<br>
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);<br>
-    guint32 modifiers;<br>
-    GdkWindow *w;<br>
-<br>
-    if (d->disable_inputs)<br>
-        return;<br>
-<br>
-    w = gtk_widget_get_parent_window(GTK_WIDGET(display));<br>
-    if (w == NULL) /* it can happen if the display is not yet shown */<br>
-        return;<br>
-<br>
-    if (!GDK_IS_X11_DISPLAY(gdk_window_get_display(w))) {<br>
-        SPICE_DEBUG("FIXME: gtk backend is not X11");<br>
-        return;<br>
-    }<br>
-<br>
-    x_display = GDK_WINDOW_XDISPLAY(w);<br>
-    modifiers = get_keyboard_lock_modifiers(x_display);<br>
-    if (d->inputs)<br>
-        spice_inputs_set_key_locks(d->inputs, modifiers);<br>
-}<br>
-<br>
-#elif defined (WIN32)<br>
-static guint32 get_keyboard_lock_modifiers(void)<br>
-{<br>
-    guint32 modifiers = 0;<br>
-<br>
-    if (GetKeyState(VK_CAPITAL) & 1) {<br>
-        modifiers |= SPICE_INPUTS_CAPS_LOCK;<br>
-    }<br>
-    if (GetKeyState(VK_NUMLOCK) & 1) {<br>
-        modifiers |= SPICE_INPUTS_NUM_LOCK;<br>
-    }<br>
-    if (GetKeyState(VK_SCROLL) & 1) {<br>
-        modifiers |= SPICE_INPUTS_SCROLL_LOCK;<br>
-    }<br>
-<br>
-    return modifiers;<br>
-}<br>
-<br>
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)<br>
-{<br>
-    SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);<br>
-    guint32 modifiers;<br>
-    GdkWindow *w;<br>
-<br>
-    if (d->disable_inputs)<br>
-        return;<br>
-<br>
-    w = gtk_widget_get_parent_window(GTK_WIDGET(display));<br>
-    if (w == NULL) /* it can happen if the display is not yet shown */<br>
-        return;<br>
-<br>
-    modifiers = get_keyboard_lock_modifiers();<br>
-    if (d->inputs)<br>
-        spice_inputs_set_key_locks(d->inputs, modifiers);<br>
-}<br>
-#else<br>
-static void sync_keyboard_lock_modifiers(SpiceDisplay *display)<br>
-{<br>
-    g_warning("sync_keyboard_lock_modifiers not implemented");<br>
-}<br>
-#endif // HAVE_X11_XKBLIB_H<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.0<br>
<br>
_______________________________________________<br>
Spice-devel mailing list<br>
<a href="mailto:Spice-devel@lists.freedesktop.org">Spice-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/spice-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/spice-devel</a><br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>Marc-André Lureau
</div></div>