<div dir="ltr"><div><div>Hi,<br><br>I just noticed spice_gtk_session_sync_keyboard_modifiers() is not actually exported, and not documented etc.<br><br></div>Imho, it's not really helping to put in public API, I would rather move declaration to spice-gtk-session-priv.h.<br>
<br></div><div>What do you think?<br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Apr 3, 2014 at 12:38 AM, Marc-André Lureau <span dir="ltr"><<a href="mailto:mlureau@redhat.com" target="_blank">mlureau@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">looks good, ack<br>
<div class="HOEnZb"><div class="h5"><br>
----- Original Message -----<br>
> 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 moves the responsibility for synchronizing client and guest modifiers<br>
> into<br>
> SpiceGtkSession. It can't be handled easily within the SpiceDisplay widget<br>
> since<br>
> there can be multiple display widgets for each inputs channel.<br>
><br>
> A new function (spice_gtk_session_sync_keyboard_modifiers()) was added so<br>
> that<br>
> synchronization can be triggered manually if desired. But it also registers a<br>
> signal handler for the InputsChannel::inputs-modifiers signal to detect when<br>
> the<br>
> guest has changed its modifiers. The signal handler simply overrides the<br>
> guests<br>
> modifiers and sets them back to the value from the client.<br>
> ---<br>
>  gtk/spice-gtk-session.c | 97<br>
>  +++++++++++++++++++++++++++++++++++++++++++++++++<br>
>  gtk/spice-gtk-session.h |  1 +<br>
>  gtk/spice-widget.c      | 91 +---------------------------------------------<br>
>  3 files changed, 100 insertions(+), 89 deletions(-)<br>
><br>
> diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c<br>
> index a9ce025..f0f7edf 100644<br>
> --- a/gtk/spice-gtk-session.c<br>
> +++ b/gtk/spice-gtk-session.c<br>
> @@ -17,6 +17,22 @@<br>
>  */<br>
>  #include "config.h"<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 <gtk/gtk.h><br>
>  #include <spice/vd_agent.h><br>
>  #include "desktop-integration.h"<br>
> @@ -97,6 +113,70 @@ enum {<br>
>      PROP_AUTO_USBREDIR,<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<br>
> spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSession *self,<br>
> +<br>
> SpiceInputsChannel*<br>
> 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>
> +static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer<br>
> data)<br>
> +{<br>
> +    SpiceGtkSession *self = data;<br>
> +    spice_gtk_session_sync_keyboard_modifiers_for_channel(self, inputs);<br>
> +}<br>
> +<br>
>  static void spice_gtk_session_init(SpiceGtkSession *self)<br>
>  {<br>
>      SpiceGtkSessionPrivate *s;<br>
> @@ -872,6 +952,11 @@ static void channel_new(SpiceSession *session,<br>
> SpiceChannel *channel,<br>
>          g_signal_connect(channel, "main-clipboard-selection-release",<br>
>                           G_CALLBACK(clipboard_release), self);<br>
>      }<br>
> +    if (SPICE_IS_INPUTS_CHANNEL(channel)) {<br>
> +        spice_g_signal_connect_object(channel, "inputs-modifiers",<br>
> +                                      G_CALLBACK(guest_modifiers_changed),<br>
> self, 0);<br>
> +        spice_gtk_session_sync_keyboard_modifiers_for_channel(self,<br>
> SPICE_INPUTS_CHANNEL(channel));<br>
> +    }<br>
>  }<br>
><br>
>  static void channel_destroy(SpiceSession *session, SpiceChannel *channel,<br>
> @@ -1029,3 +1114,15 @@ void<br>
> spice_gtk_session_paste_from_guest(SpiceGtkSession *self)<br>
>      s->clipboard_by_guest[selection] = TRUE;<br>
>      s->clip_hasdata[selection] = FALSE;<br>
>  }<br>
> +<br>
> +void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self)<br>
> +{<br>
> +    GList *l = NULL, *channels =<br>
> spice_session_get_channels(self->priv->session);<br>
> +<br>
> +    for (l = channels; l != NULL; l = l->next) {<br>
> +        if (SPICE_IS_INPUTS_CHANNEL(l->data)) {<br>
> +            SpiceInputsChannel *inputs = SPICE_INPUTS_CHANNEL(l->data);<br>
> +            spice_gtk_session_sync_keyboard_modifiers_for_channel(self,<br>
> inputs);<br>
> +        }<br>
> +    }<br>
> +}<br>
> diff --git a/gtk/spice-gtk-session.h b/gtk/spice-gtk-session.h<br>
> index 3b4eac6..fbcc353 100644<br>
> --- a/gtk/spice-gtk-session.h<br>
> +++ b/gtk/spice-gtk-session.h<br>
> @@ -59,6 +59,7 @@ GType spice_gtk_session_get_type(void);<br>
>  SpiceGtkSession *spice_gtk_session_get(SpiceSession *session);<br>
>  void spice_gtk_session_copy_to_guest(SpiceGtkSession *self);<br>
>  void spice_gtk_session_paste_from_guest(SpiceGtkSession *self);<br>
> +void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self);<br>
><br>
>  G_END_DECLS<br>
><br>
> diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c<br>
> index 0e4a0de..2044513 100644<br>
> --- a/gtk/spice-widget.c<br>
> +++ b/gtk/spice-widget.c<br>
> @@ -131,7 +131,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<br>
>  data);<br>
>  static void channel_destroy(SpiceSession *s, SpiceChannel *channel, gpointer<br>
>  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,<br>
>  gint height);<br>
>  static void release_keys(SpiceDisplay *display);<br>
> @@ -1457,7 +1456,8 @@ static gboolean focus_in_event(GtkWidget *widget,<br>
> 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_gtk_session_sync_keyboard_modifiers(d->gtk_session);<br>
>      update_keyboard_focus(display, true);<br>
>      try_keyboard_grab(display);<br>
>      update_display(display);<br>
> @@ -2411,7 +2411,6 @@ static void channel_new(SpiceSession *s, SpiceChannel<br>
> *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>
>          return;<br>
>      }<br>
><br>
> @@ -2600,89 +2599,3 @@ GdkPixbuf *spice_display_get_pixbuf(SpiceDisplay<br>
> *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>
> --<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>
><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>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>Marc-André Lureau
</div>