----- Original Message ----- > The keyboard description of the client will be sent to the guest > when the connection is established. > > RFE: https://bugs.freedesktop.org/show_bug.cgi?id=85332 > --- > gtk/spice-gtk-session-priv.h | 1 + > gtk/spice-gtk-session.c | 72 > ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 73 insertions(+) > > diff --git a/gtk/spice-gtk-session-priv.h b/gtk/spice-gtk-session-priv.h > index 91304b2..571f91f 100644 > --- a/gtk/spice-gtk-session-priv.h > +++ b/gtk/spice-gtk-session-priv.h > @@ -28,6 +28,7 @@ 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_sync_keyboard_layout(SpiceGtkSession *self); > > G_END_DECLS > > diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c > index 52ad597..180f2ed 100644 > --- a/gtk/spice-gtk-session.c > +++ b/gtk/spice-gtk-session.c > @@ -178,6 +178,13 @@ static void > spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSessio > } > } > > +static void keymap_layout_changed(GdkKeymap *keymap, gpointer data) > +{ > + SpiceGtkSession *self = data; > + > + spice_gtk_session_sync_keyboard_layout(self); > +} > + > static void keymap_modifiers_changed(GdkKeymap *keymap, gpointer data) > { > SpiceGtkSession *self = data; > @@ -207,6 +214,8 @@ static void spice_gtk_session_init(SpiceGtkSession *self) > G_CALLBACK(clipboard_owner_change), self); > spice_g_signal_connect_object(keymap, "state-changed", > G_CALLBACK(keymap_modifiers_changed), > self, 0); > + spice_g_signal_connect_object(keymap, "keys-changed", > + G_CALLBACK(keymap_layout_changed), self, > 0); > } > > static GObject * > @@ -1001,6 +1010,15 @@ static void channel_new(SpiceSession *session, > SpiceChannel *channel, > G_CALLBACK(clipboard_request), self); > g_signal_connect(channel, "main-clipboard-selection-release", > G_CALLBACK(clipboard_release), self); > + gboolean agent_connected; > + g_object_get(channel, "agent-connected", &agent_connected, NULL); > + if (agent_connected) { > + spice_gtk_session_sync_keyboard_layout(self); > + } else { > + g_signal_connect_swapped(channel, "notify::agent-connected", > + > G_CALLBACK(spice_gtk_session_sync_keyboard_layout), > + self); > + } > } > if (SPICE_IS_INPUTS_CHANNEL(channel)) { > spice_g_signal_connect_object(channel, "inputs-modifiers", > @@ -1195,3 +1213,57 @@ gboolean > spice_gtk_session_get_pointer_grabbed(SpiceGtkSession *self) > > return self->priv->pointer_grabbed; > } > + > +static gchar *get_keyboard_description(void) > +{ > + gchar *keyboard_description = NULL; > +#ifdef HAVE_X11_XKBLIB_H > + Display *dpy; > + XkbDescPtr xkb; > + int major = XkbMajorVersion, minor = XkbMinorVersion; > + > + dpy = XkbOpenDisplay(NULL, NULL, NULL, &major, &minor, NULL); > + if (dpy != NULL) { Please use g_return_val_if_fail() here, as this should not happen. > + xkb = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd); > + if (xkb != NULL) { Same here > + keyboard_description = g_strdelimit( > + g_strdup_printf("%s", XGetAtomName(dpy, > xkb->names->symbols)), "_",'+'); > + XkbFreeKeyboard(xkb, XkbAllComponentsMask, True); > + } > + XCloseDisplay(dpy); > + } > +#elif defined(G_OS_WIN32) > + gchar *locale, *region; > + locale = g_win32_getlocale(); > + region = g_ascii_strdown(g_strrstr(locale, "_")+1, -1); > + g_free(locale); > + keyboard_description = g_strdup_printf("pc+%s", region); > + g_free(region); > +#endif > + return keyboard_description; > +} > + > +G_GNUC_INTERNAL > +void spice_gtk_session_sync_keyboard_layout(SpiceGtkSession *self) > +{ > + GList *l, *channels; > + gchar *keyboard_description = get_keyboard_description(); > + > + if (keyboard_description != NULL) { To avoid deep blocks, it's easy to return early, this time with simple return (NULL is ok) > + channels = spice_session_get_channels(self->priv->session); > + for (l = channels; l != NULL; l = l->next) { No need to look up all channels, there is a single main channel, and you can take it from priv->main > + if (SPICE_IS_MAIN_CHANNEL(l->data)) { > + SpiceMainChannel *main_channel = > SPICE_MAIN_CHANNEL(l->data); > + gboolean agent_connected; > + g_object_get(main_channel, "agent-connected", > &agent_connected, NULL); > + if (!agent_connected) > + continue; > + spice_main_keyboard_description(main_channel, > + keyboard_description, > + > strlen(keyboard_description)+1); > + } > + } > + g_list_free(channels); > + g_free(keyboard_description); > + } > +} > -- > 1.9.3 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel > _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel