have you decided ? i do not get your code from git.
where is the code you judge whether need to sync or not?
according to your code, i think there are at least two times to sync lock status, first , your code of state-changed,
the another is key_press_and_release.
i think we just ensure that at the beginning of connection we can make the lock status identical , and just only once.
thanks
At 2014-04-04 05:09:08,"Jonathon Jongsma" <jjongsma@xxxxxxxxxxxxxxxxxxxxxx> wrote: > 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@xxxxxxxxxx> >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@xxxxxxxxxx> >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 >_______________________________________________ >Spice-commits mailing list >Spice-commits@xxxxxxxxxxxxxxxxxxxxx >http://lists.freedesktop.org/mailman/listinfo/spice-commits
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel