summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2016-09-02 22:40:19 +0100
committerFrediano Ziglio <fziglio@redhat.com>2017-02-01 15:15:34 +0000
commit6c51abc5ec640b1f9fedb43d9b21936272fab49c (patch)
tree96f43e4daa1bd1fab26b9e9e86aa90df8055436d
parent72f87c665643de6807b97e11b80833e4ac8c380b (diff)
Sync only on focus changeclient_sync
Limit the virtual keystrokes sent to the remote machine. The modifiers are synced only when the application receive or lose the focus. This reduce a lot the possible virtual keystrokes sent to the guest to synchronize the modifiers. This affect the situations where modifiers are configured differently in client and guest. When the application receive the focus the synchronization is attempted from client to guest while when the application lose focus is attempted guest to client (basically is moved following user moving). This patch is actually not complete but more an RFC: - only X11 and Windows are currently supported; - what happen with multimonitors? I don't think this patch it's causing regressions anyway; - there are some possible changes in behavior for keymap_modifiers_changed; - one possible regression is that if you are using virt-viewer and the guest is booted it's possible the boot process will switch modifiers status. Honestly I consider this more of an improvement than a regression. Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r--src/spice-gtk-session-priv.h2
-rw-r--r--src/spice-gtk-session.c76
-rw-r--r--src/spice-widget.c5
3 files changed, 78 insertions, 5 deletions
diff --git a/src/spice-gtk-session-priv.h b/src/spice-gtk-session-priv.h
index d7fe313..abf90d6 100644
--- a/src/spice-gtk-session-priv.h
+++ b/src/spice-gtk-session-priv.h
@@ -38,13 +38,13 @@ struct _SpiceGtkSessionClass
void spice_gtk_session_request_auto_usbredir(SpiceGtkSession *self,
gboolean state);
gboolean spice_gtk_session_get_read_only(SpiceGtkSession *self);
-void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self);
void spice_gtk_session_set_pointer_grabbed(SpiceGtkSession *self, gboolean grabbed);
gboolean spice_gtk_session_get_pointer_grabbed(SpiceGtkSession *self);
void spice_gtk_session_set_keyboard_has_focus(SpiceGtkSession *self, gboolean keyboard_has_focus);
void spice_gtk_session_set_mouse_has_pointer(SpiceGtkSession *self, gboolean mouse_has_pointer);
gboolean spice_gtk_session_get_keyboard_has_focus(SpiceGtkSession *self);
gboolean spice_gtk_session_get_mouse_has_pointer(SpiceGtkSession *self);
+void spice_gtk_session_set_focus(SpiceGtkSession *self, gboolean focus);
G_END_DECLS
diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
index ad93bd1..3c662ab 100644
--- a/src/spice-gtk-session.c
+++ b/src/spice-gtk-session.c
@@ -67,6 +67,8 @@ struct _SpiceGtkSessionPrivate {
gboolean keyboard_has_focus;
gboolean mouse_has_pointer;
gboolean sync_modifiers;
+ gboolean has_focus;
+ guint32 guest_modifiers;
};
/**
@@ -104,6 +106,7 @@ static void channel_new(SpiceSession *session, SpiceChannel *channel,
static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
gpointer user_data);
static gboolean read_only(SpiceGtkSession *self);
+static void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self);
/* ------------------------------------------------------------------ */
/* gobject glue */
@@ -127,7 +130,7 @@ static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio
SpiceInputsChannel* inputs,
gboolean force)
{
- guint32 guest_modifiers = 0, client_modifiers = 0;
+ guint32 guest_modifiers, client_modifiers;
g_return_if_fail(SPICE_IS_INPUTS_CHANNEL(inputs));
@@ -136,7 +139,20 @@ static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio
return;
}
+ // get and cache client modifiers
+ guest_modifiers = G_MAXUINT32;
g_object_get(inputs, "key-modifiers", &guest_modifiers, NULL);
+ if (guest_modifiers == G_MAXUINT32) {
+ return;
+ }
+ self->priv->guest_modifiers = guest_modifiers;
+
+ // if client synchronization is enabled the
+ // synchronization is done in spice_gtk_session_set_focus
+ if (!force && can_set_keyboard_lock_modifiers()) {
+ return;
+ }
+
client_modifiers = get_keyboard_lock_modifiers();
if (force || client_modifiers != guest_modifiers) {
@@ -146,10 +162,39 @@ static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio
}
}
+static void spice_gtk_session_set_client_keyboard_modifiers(SpiceGtkSession *self)
+{
+ guint32 guest_modifiers = 0, client_modifiers = 0;
+
+ if (SPICE_IS_GTK_SESSION(self) && !self->priv->sync_modifiers) {
+ SPICE_DEBUG("Syncing modifiers is disabled");
+ return;
+ }
+
+ if (!can_set_keyboard_lock_modifiers()) {
+ return;
+ }
+
+ guest_modifiers = self->priv->guest_modifiers;
+ client_modifiers = get_keyboard_lock_modifiers();
+ if (client_modifiers == guest_modifiers) {
+ return;
+ }
+
+ set_keyboard_lock_modifiers(guest_modifiers);
+}
+
+/* Keyboard state changed in the client, try to sync
+ */
static void keymap_modifiers_changed(GdkKeymap *keymap, gpointer data)
{
SpiceGtkSession *self = data;
+ /* client sync, sync done only when focus change */
+ if (can_set_keyboard_lock_modifiers()) {
+ return;
+ }
+
spice_gtk_session_sync_keyboard_modifiers(self);
}
@@ -1216,8 +1261,7 @@ void spice_gtk_session_paste_from_guest(SpiceGtkSession *self)
s->clip_hasdata[selection] = FALSE;
}
-G_GNUC_INTERNAL
-void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self)
+static void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self)
{
GList *l = NULL, *channels = spice_session_get_channels(self->priv->session);
@@ -1240,6 +1284,32 @@ void spice_gtk_session_set_pointer_grabbed(SpiceGtkSession *self, gboolean grabb
}
G_GNUC_INTERNAL
+void spice_gtk_session_set_focus(SpiceGtkSession *self, gboolean focus)
+{
+ g_return_if_fail(SPICE_IS_GTK_SESSION(self));
+
+ /* TODO detect switch between monitors */
+
+ /* not changed ? */
+ if (self->priv->has_focus == focus)
+ return;
+
+ if (focus) {
+ /* User switched to the viewer, try to syncronize the keyboard
+ * modifiers.
+ * This should be called before setting has_focus
+ */
+ spice_gtk_session_sync_keyboard_modifiers(self);
+ } else {
+ /* User swicthed to another application, syncronize the client
+ * keyboard */
+ spice_gtk_session_set_client_keyboard_modifiers(self);
+ }
+
+ self->priv->has_focus = focus;
+}
+
+G_GNUC_INTERNAL
gboolean spice_gtk_session_get_pointer_grabbed(SpiceGtkSession *self)
{
g_return_val_if_fail(SPICE_IS_GTK_SESSION(self), FALSE);
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 72fbbc8..187b144 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -1783,7 +1783,7 @@ static gboolean focus_in_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_UN
}
#endif
if (!d->disable_inputs)
- spice_gtk_session_sync_keyboard_modifiers(d->gtk_session);
+ spice_gtk_session_set_focus(d->gtk_session, TRUE);
if (d->keyboard_grab_released)
memset(d->activeseq, 0, sizeof(gboolean) * d->grabseq->nkeysyms);
update_keyboard_focus(display, true);
@@ -1810,6 +1810,9 @@ static gboolean focus_out_event(GtkWidget *widget, GdkEventFocus *focus G_GNUC_U
if (d->keyboard_grab_active)
return true;
+ if (!d->disable_inputs)
+ spice_gtk_session_set_focus(d->gtk_session, FALSE);
+
release_keys(display);
update_keyboard_focus(display, false);