diff options
-rw-r--r-- | src/spice-gtk-session-priv.h | 2 | ||||
-rw-r--r-- | src/spice-gtk-session.c | 76 | ||||
-rw-r--r-- | src/spice-widget.c | 5 |
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); |