[Spice-devel] [PATCH spice-gtk 2/2] Send keyboard description

Pavel Grunt pgrunt at redhat.com
Wed Nov 5 02:47:21 PST 2014


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) {
+        xkb = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+        if (xkb != NULL) {
+            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) {
+        channels = spice_session_get_channels(self->priv->session);
+        for (l = channels; l != NULL; l = l->next) {
+            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



More information about the Spice-devel mailing list