[gnome-flashback] input-sources: add GfKeyboardManager



commit 660e60e645f241a329d397f50a450513c906290e
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Mon Sep 21 22:38:18 2015 +0300

    input-sources: add GfKeyboardManager

 configure.ac                                       |   12 +
 gnome-flashback/libinput-sources/Makefile.am       |    3 +
 .../libinput-sources/gf-input-source-manager.c     |   31 +
 .../libinput-sources/gf-input-source-manager.h     |    4 +-
 .../libinput-sources/gf-keyboard-manager.c         |  682 ++++++++++++++++++++
 .../libinput-sources/gf-keyboard-manager.h         |   53 ++
 6 files changed, 784 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6455c72..9b17f68 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,8 +141,12 @@ PKG_CHECK_MODULES([IDLE_MONITOR], [
 ])
 
 PKG_CHECK_MODULES([INPUT_SOURCES], [
+  gnome-desktop-3.0 >= $LIBGNOME_DESKTOP_REQUIRED
   gtk+-3.0 >= $GTK_REQUIRED
   ibus-1.0 >= $IBUS_REQUIRED
+  xkbcommon-x11
+  xkbfile
+  xkeyboard-config
 ])
 
 PKG_CHECK_MODULES([POLKIT], [
@@ -192,6 +196,14 @@ PKG_CHECK_MODULES([WORKAROUNDS], [
 ])
 
 dnl **************************************************************************
+dnl Define XKB base directory
+dnl **************************************************************************
+
+AC_DEFINE_UNQUOTED([XKB_BASE],
+                   ["`$PKG_CONFIG --variable xkb_base xkeyboard-config`"],
+                   [Define XKB base directory])
+
+dnl **************************************************************************
 dnl Tell gvc submodule to not build introspection
 dnl **************************************************************************
 
diff --git a/gnome-flashback/libinput-sources/Makefile.am b/gnome-flashback/libinput-sources/Makefile.am
index 2231201..0e62ca2 100644
--- a/gnome-flashback/libinput-sources/Makefile.am
+++ b/gnome-flashback/libinput-sources/Makefile.am
@@ -11,6 +11,7 @@ libinput_sources_la_CFLAGS = \
        -I$(srcdir)/../../gnome-flashback \
        -I$(top_builddir)/gnome-flashback \
        -I$(top_builddir)/gnome-flashback/libinput-sources \
+       -DGNOME_DESKTOP_USE_UNSTABLE_API \
        $(NULL)
 
 libinput_sources_la_SOURCES = \
@@ -24,6 +25,8 @@ libinput_sources_la_SOURCES = \
        gf-input-source-manager.h \
        gf-input-source-settings.c \
        gf-input-source-settings.h \
+       gf-keyboard-manager.c \
+       gf-keyboard-manager.h \
        $(NULL)
 
 libinput_sources_la_LDFLAGS = \
diff --git a/gnome-flashback/libinput-sources/gf-input-source-manager.c 
b/gnome-flashback/libinput-sources/gf-input-source-manager.c
index 0df2e32..5c956a9 100644
--- a/gnome-flashback/libinput-sources/gf-input-source-manager.c
+++ b/gnome-flashback/libinput-sources/gf-input-source-manager.c
@@ -23,6 +23,7 @@
 #include "gf-input-source-manager.h"
 #include "gf-input-source-settings.h"
 #include "gf-ibus-manager.h"
+#include "gf-keyboard-manager.h"
 
 #define DESKTOP_WM_KEYBINDINGS_SCHEMA "org.gnome.desktop.wm.keybindings"
 
@@ -40,6 +41,8 @@ struct _GfInputSourceManager
 
   GfInputSourceSettings *settings;
 
+  GfKeyboardManager     *keyboard_manager;
+
   GfIBusManager         *ibus_manager;
 };
 
@@ -167,6 +170,17 @@ static void
 xkb_options_changed_cb (GfInputSourceSettings *settings,
                         gpointer               user_data)
 {
+  GfInputSourceManager *manager;
+  gchar **options;
+
+  manager = GF_INPUT_SOURCE_MANAGER (user_data);
+
+  options = gf_input_source_settings_get_xkb_options (manager->settings);
+
+  gf_keyboard_manager_set_xkb_options (manager->keyboard_manager, options);
+  g_strfreev (options);
+
+  gf_keyboard_manager_reapply (manager->keyboard_manager);
 }
 
 static void
@@ -200,6 +214,8 @@ gf_input_source_manager_dispose (GObject *object)
 
   g_clear_object (&manager->settings);
 
+  g_clear_object (&manager->keyboard_manager);
+
   G_OBJECT_CLASS (gf_input_source_manager_parent_class)->dispose (object);
 }
 
@@ -271,6 +287,8 @@ gf_input_source_manager_class_init (GfInputSourceManagerClass *manager_class)
 static void
 gf_input_source_manager_init (GfInputSourceManager *manager)
 {
+  manager->keyboard_manager = gf_keyboard_manager_new ();
+
   keybindings_init (manager);
   input_source_settings_init (manager);
 }
@@ -282,3 +300,16 @@ gf_input_source_manager_new (GfIBusManager *ibus_manager)
                        "ibus-manager", ibus_manager,
                        NULL);
 }
+
+void
+gf_input_source_manager_reload (GfInputSourceManager *manager)
+{
+  gchar **options;
+
+  options = gf_input_source_settings_get_xkb_options (manager->settings);
+
+  gf_keyboard_manager_set_xkb_options (manager->keyboard_manager, options);
+  g_strfreev (options);
+
+  sources_changed_cb (manager->settings, manager);
+}
diff --git a/gnome-flashback/libinput-sources/gf-input-source-manager.h 
b/gnome-flashback/libinput-sources/gf-input-source-manager.h
index c8bcfe9..73dddde 100644
--- a/gnome-flashback/libinput-sources/gf-input-source-manager.h
+++ b/gnome-flashback/libinput-sources/gf-input-source-manager.h
@@ -25,6 +25,8 @@
 G_DECLARE_FINAL_TYPE (GfInputSourceManager, gf_input_source_manager,
                       GF, INPUT_SOURCE_MANAGER, GObject)
 
-GfInputSourceManager *gf_input_source_manager_new (GfIBusManager *manager);
+GfInputSourceManager *gf_input_source_manager_new    (GfIBusManager        *manager);
+
+void                  gf_input_source_manager_reload (GfInputSourceManager *manager);
 
 #endif
diff --git a/gnome-flashback/libinput-sources/gf-keyboard-manager.c 
b/gnome-flashback/libinput-sources/gf-keyboard-manager.c
new file mode 100644
index 0000000..66faf49
--- /dev/null
+++ b/gnome-flashback/libinput-sources/gf-keyboard-manager.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <gdk/gdkx.h>
+#include <libgnome-desktop/gnome-languages.h>
+#include <xkbcommon/xkbcommon-x11.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBrules.h>
+
+#include "gf-keyboard-manager.h"
+
+#define DEFAULT_XKB_RULES_FILE "evdev"
+#define DEFAULT_XKB_MODEL "pc105+inet"
+
+#define DEFAULT_LOCALE "en_US"
+#define DEFAULT_LAYOUT "us"
+#define DEFAULT_VARIANT ""
+
+/* The XKB protocol doesn't allow for more than 4 layouts in a keymap. */
+#define MAX_LAYOUTS_PER_GROUP 4
+
+typedef struct _LayoutInfo LayoutInfo;
+struct _LayoutInfo
+{
+  gchar       *id;
+  gchar       *layout;
+  gchar       *variant;
+
+  LayoutInfo **group;
+  guint        index;
+};
+
+struct _GfKeyboardManager
+{
+  GObject       parent;
+
+  Display      *xdisplay;
+
+  gboolean      have_xkb;
+  gint          xkb_event_base;
+  gint          xkb_error_base;
+
+  GnomeXkbInfo *xkb_info;
+
+  LayoutInfo   *locale;
+
+  GHashTable   *layout_infos;
+  LayoutInfo   *current;
+
+  gchar        *layouts;
+  gchar        *variants;
+  gchar        *options;
+
+  GdkDevice    *keyboard;
+};
+
+G_DEFINE_TYPE (GfKeyboardManager, gf_keyboard_manager, G_TYPE_OBJECT)
+
+static LayoutInfo *
+layout_info_new (const gchar *id,
+                 const gchar *layout,
+                 const gchar *variant)
+{
+  LayoutInfo *layout_info;
+
+  layout_info = g_new0 (LayoutInfo, 1);
+
+  layout_info->id = g_strdup (id);
+  layout_info->layout = g_strdup (layout);
+  layout_info->variant = g_strdup (variant);
+
+  layout_info->group = NULL;
+
+  return layout_info;
+}
+
+static void
+layout_info_free (gpointer data)
+{
+  LayoutInfo *layout_info;
+
+  layout_info = (LayoutInfo *) data;
+
+  g_free (layout_info->id);
+  g_free (layout_info->layout);
+  g_free (layout_info->variant);
+
+  if (layout_info->index == 0)
+    g_free (layout_info->group);
+
+  g_free (layout_info);
+}
+
+static void
+upload_xkb_description (Display              *xdisplay,
+                        const gchar          *rules_file_path,
+                        XkbComponentNamesRec *component_names,
+                        XkbRF_VarDefsRec     *var_defs)
+{
+  guint want_mask;
+  guint need_mask;
+  XkbDescRec *xkb_desc;
+  gchar *rules_file;
+
+  want_mask = XkbGBN_AllComponentsMask;
+  need_mask = XkbGBN_AllComponentsMask & (~XkbGBN_GeometryMask);
+  xkb_desc = XkbGetKeyboardByName (xdisplay, XkbUseCoreKbd, component_names,
+                                   want_mask, need_mask, True);
+
+  if (xkb_desc == NULL)
+    {
+      g_warning ("Couldn't upload new XKB keyboard description");
+      return;
+    }
+
+  XkbFreeKeyboard (xkb_desc, 0, True);
+
+  rules_file = g_path_get_basename (rules_file_path);
+
+  if (!XkbRF_SetNamesProp (xdisplay, rules_file, var_defs))
+    g_warning ("Couldn't update the XKB root window property");
+
+  g_free (rules_file);
+}
+
+static void
+get_xkbrf_var_defs (Display           *xdisplay,
+                    const char        *layouts,
+                    const char        *variants,
+                    const char        *options,
+                    gchar            **rules,
+                    XkbRF_VarDefsRec **var_defs)
+{
+  gchar *tmp;
+  XkbRF_VarDefsRec *defs;
+
+  defs = g_new0 (XkbRF_VarDefsRec, 1);
+
+  tmp = NULL;
+  if (!XkbRF_GetNamesProp (xdisplay, &tmp, defs) || !tmp)
+    {
+      tmp = g_strdup (DEFAULT_XKB_RULES_FILE);
+
+      defs->model = g_strdup (DEFAULT_XKB_MODEL);
+      defs->layout = NULL;
+      defs->variant = NULL;
+      defs->options = NULL;
+    }
+
+  g_free (defs->layout);
+  defs->layout = g_strdup (layouts);
+
+  g_free (defs->variant);
+  defs->variant = g_strdup (variants);
+
+  g_free (defs->options);
+  defs->options = g_strdup (options);
+
+  if (tmp[0] == '/')
+    *rules = g_strdup (tmp);
+  else
+    *rules = g_build_filename (XKB_BASE, "rules", tmp, NULL);
+  g_free (tmp);
+
+  *var_defs = defs;
+}
+
+static void
+xkbrf_var_defs_free (XkbRF_VarDefsRec *var_defs)
+{
+  g_free (var_defs->model);
+  g_free (var_defs->layout);
+  g_free (var_defs->variant);
+  g_free (var_defs->options);
+
+  g_free (var_defs);
+}
+
+static void
+xkb_component_names_free (XkbComponentNamesRec *xkb_comp_names)
+{
+  g_free (xkb_comp_names->keymap);
+  g_free (xkb_comp_names->keycodes);
+  g_free (xkb_comp_names->types);
+  g_free (xkb_comp_names->compat);
+  g_free (xkb_comp_names->symbols);
+  g_free (xkb_comp_names->geometry);
+
+  g_free (xkb_comp_names);
+}
+
+static void
+set_keymap (GfKeyboardManager *manager)
+{
+  gchar *rules_file_path;
+  XkbRF_VarDefsRec *xkb_var_defs;
+  XkbRF_RulesRec *xkb_rules;
+
+  if (manager->have_xkb == FALSE)
+    return;
+
+  if (!manager->layouts || !manager->variants || !manager->options)
+    return;
+
+  xkb_var_defs = NULL;
+  get_xkbrf_var_defs (manager->xdisplay,
+                      manager->layouts, manager->variants, manager->options,
+                      &rules_file_path, &xkb_var_defs);
+
+  xkb_rules = XkbRF_Load (rules_file_path, NULL, True, True);
+
+  if (xkb_rules != NULL)
+    {
+      XkbComponentNamesRec *xkb_comp_names;
+
+      xkb_comp_names = g_new0 (XkbComponentNamesRec, 1);
+      XkbRF_GetComponents (xkb_rules, xkb_var_defs, xkb_comp_names);
+
+      upload_xkb_description (manager->xdisplay, rules_file_path,
+                              xkb_comp_names, xkb_var_defs);
+
+      xkb_component_names_free (xkb_comp_names);
+      XkbRF_Free (xkb_rules, True);
+    }
+  else
+    g_warning ("Couldn't load XKB rules");
+
+  g_free (rules_file_path);
+  xkbrf_var_defs_free (xkb_var_defs);
+}
+
+static gchar *
+get_layouts_string (GfKeyboardManager  *manager,
+                    LayoutInfo        **group)
+{
+  gchar *layouts;
+  gint i;
+  gchar *tmp;
+
+  if (group[0] == NULL)
+    return g_strdup ("");
+
+  layouts = g_strdup (group[0]->layout);
+  for (i = 1; i < (MAX_LAYOUTS_PER_GROUP - 1); i++)
+    {
+      if (group[i] == NULL)
+        continue;
+
+      tmp = g_strdup_printf ("%s,%s", layouts, group[i]->layout);
+      g_free (layouts);
+
+      layouts = tmp;
+    }
+
+  if (manager->locale != NULL)
+    {
+      tmp = g_strdup_printf ("%s,%s", layouts, manager->locale->layout);
+      g_free (layouts);
+
+      layouts = tmp;
+    }
+
+  return layouts;
+}
+
+static gchar *
+get_variants_string (GfKeyboardManager  *manager,
+                     LayoutInfo        **group)
+{
+  gchar *variants;
+  gint i;
+  gchar *tmp;
+
+  if (group[0] == NULL)
+    return g_strdup ("");
+
+  variants = g_strdup (group[0]->variant);
+  for (i = 1; i < (MAX_LAYOUTS_PER_GROUP - 1); i++)
+    {
+      if (group[i] == NULL)
+        continue;
+
+      tmp = g_strdup_printf ("%s,%s", variants, group[i]->variant);
+      g_free (variants);
+
+      variants = tmp;
+    }
+
+  if (manager->locale != NULL)
+    {
+      tmp = g_strdup_printf ("%s,%s", variants, manager->locale->variant);
+      g_free (variants);
+
+      variants = tmp;
+    }
+
+  return variants;
+}
+
+static void
+apply_layout_group (GfKeyboardManager  *manager,
+                    LayoutInfo        **group)
+{
+  g_free (manager->layouts);
+  manager->layouts = get_layouts_string (manager, group);
+
+  g_free (manager->variants);
+  manager->variants = get_variants_string (manager, group);
+
+  set_keymap (manager);
+}
+
+static void
+apply_layout_index (GfKeyboardManager *manager,
+                    guint              index)
+{
+  if (manager->have_xkb == FALSE)
+    return;
+
+  XkbLockGroup (manager->xdisplay, XkbUseCoreKbd, index);
+}
+
+static void
+device_added_cb (GdkDeviceManager *device_manager,
+                 GdkDevice        *device,
+                 gpointer          user_data)
+{
+  GfKeyboardManager *manager;
+
+  manager = GF_KEYBOARD_MANAGER (user_data);
+
+  if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+    return;
+
+  set_keymap (manager);
+}
+
+static void
+get_locale_layout_info (GfKeyboardManager *manager)
+{
+  const gchar *locale;
+  const gchar *type;
+  const gchar *id;
+  const gchar *layout;
+  const gchar *variant;
+
+  locale = g_get_language_names ()[0];
+  if (g_strrstr (locale, "_") == NULL)
+    locale = DEFAULT_LOCALE;
+
+  if (!gnome_get_input_source_from_locale (locale, &type, &id))
+    gnome_get_input_source_from_locale (DEFAULT_LOCALE, &type, &id);
+
+  if (gnome_xkb_info_get_layout_info (manager->xkb_info, id, NULL, NULL,
+                                      &layout, &variant))
+    {
+      manager->locale = layout_info_new (id, layout, variant);
+    }
+  else
+    {
+      manager->locale = layout_info_new (id, DEFAULT_LAYOUT, DEFAULT_VARIANT);
+    }
+}
+
+static void
+gf_keyboard_manager_dispose (GObject *object)
+{
+  GfKeyboardManager *manager;
+
+  manager = GF_KEYBOARD_MANAGER (object);
+
+  g_clear_object (&manager->xkb_info);
+  g_clear_object (&manager->keyboard);
+
+  G_OBJECT_CLASS (gf_keyboard_manager_parent_class)->dispose (object);
+}
+
+static void
+gf_keyboard_manager_finalize (GObject *object)
+{
+  GfKeyboardManager *manager;
+
+  manager = GF_KEYBOARD_MANAGER (object);
+
+  if (manager->locale != 0)
+    {
+      layout_info_free (manager->locale);
+      manager->locale = NULL;
+    }
+
+  if (manager->layout_infos != NULL)
+    {
+      g_hash_table_destroy (manager->layout_infos);
+      manager->layout_infos = NULL;
+    }
+
+  g_free (manager->layouts);
+  g_free (manager->variants);
+  g_free (manager->options);
+
+  G_OBJECT_CLASS (gf_keyboard_manager_parent_class)->finalize (object);
+}
+
+static void
+gf_keyboard_manager_class_init (GfKeyboardManagerClass *manager_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (manager_class);
+
+  object_class->dispose = gf_keyboard_manager_dispose;
+  object_class->finalize = gf_keyboard_manager_finalize;
+}
+
+static void
+gf_keyboard_manager_init (GfKeyboardManager *manager)
+{
+  GdkDisplay *display;
+  GdkDeviceManager *device_manager;
+  gint xkb_opcode;
+  gint xkb_major;
+  gint xkb_minor;
+
+  display = gdk_display_get_default ();
+  device_manager = gdk_display_get_device_manager (display);
+
+  manager->xdisplay = gdk_x11_display_get_xdisplay (display);
+  manager->xkb_info = gnome_xkb_info_new ();
+  manager->options = g_strdup ("");
+
+  xkb_major = XKB_X11_MIN_MAJOR_XKB_VERSION;
+  xkb_minor = XKB_X11_MIN_MINOR_XKB_VERSION;
+
+  manager->have_xkb = TRUE;
+  if (!XkbQueryExtension (manager->xdisplay, &xkb_opcode,
+                          &manager->xkb_event_base, &manager->xkb_error_base,
+                          &xkb_major, &xkb_minor))
+    {
+      g_warning ("X server doesn't have the XKB extension, "
+                 "version %d.%d or newer", XKB_X11_MIN_MAJOR_XKB_VERSION,
+                 XKB_X11_MIN_MINOR_XKB_VERSION);
+      manager->have_xkb = FALSE;
+    }
+
+  g_signal_connect_object (device_manager, "device-added",
+                           G_CALLBACK (device_added_cb), manager,
+                           G_CONNECT_AFTER);
+
+  get_locale_layout_info (manager);
+}
+
+/**
+ * gf_keyboard_manager_new:
+ *
+ * Creates a new #GfKeyboardManager.
+ *
+ * Returns: (transfer full): a newly created #GfKeyboardManager.
+ */
+GfKeyboardManager *
+gf_keyboard_manager_new (void)
+{
+  return g_object_new (GF_TYPE_KEYBOARD_MANAGER, NULL);
+}
+
+/**
+ * gf_keyboard_manager_get_xkb_info:
+ * @manager: a #GfKeyboardManager
+ *
+ * Returns: (transfer full):
+ */
+GnomeXkbInfo *
+gf_keyboard_manager_get_xkb_info (GfKeyboardManager *manager)
+{
+  return g_object_ref (manager->xkb_info);
+}
+
+/**
+ * gf_keyboard_manager_set_xkb_options:
+ * @manager: a #GfKeyboardManager
+ * @options: a %NULL-terminated array of xkb options
+ */
+void
+gf_keyboard_manager_set_xkb_options (GfKeyboardManager  *manager,
+                                     gchar             **options)
+{
+  g_free (manager->options);
+  manager->options = g_strjoinv (",", options);
+}
+
+/**
+ * gf_keyboard_manager_set_user_layouts:
+ * @manager: a #GfKeyboardManager
+ * @ids: a %NULL-terminated array of input source ids
+ */
+void
+gf_keyboard_manager_set_user_layouts (GfKeyboardManager  *manager,
+                                      gchar             **ids)
+{
+  gint i;
+  const gchar *layout;
+  const gchar *variant;
+  GHashTableIter iter;
+  gpointer value;
+  LayoutInfo **group;
+
+  manager->current = NULL;
+
+  if (manager->layout_infos != NULL)
+    g_hash_table_destroy (manager->layout_infos);
+
+  manager->layout_infos = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                 g_free, layout_info_free);
+
+  for (i = 0; ids[i] != NULL; i++)
+    {
+      if (gnome_xkb_info_get_layout_info (manager->xkb_info, ids[i],
+                                          NULL, NULL, &layout, &variant))
+        {
+          LayoutInfo *info;
+
+          info = layout_info_new (ids[i], layout, variant);
+
+          g_hash_table_insert (manager->layout_infos, g_strdup (ids[i]), info);
+        }
+    }
+
+  i = 0;
+  g_hash_table_iter_init (&iter, manager->layout_infos);
+
+  while (g_hash_table_iter_next (&iter, NULL, &value))
+    {
+      LayoutInfo *info;
+      guint index;
+
+      info = (LayoutInfo *) value;
+
+      /*
+       * We need to leave one slot on each group free so that we can add a
+       * layout containing the symbols for the language used in UI strings to
+       * ensure that toolkits can handle mnemonics like Alt+Ф even if the user
+       * is actually typing in a different layout.
+       */
+      index = i % (MAX_LAYOUTS_PER_GROUP - 1);
+
+      if (index == 0)
+        group = g_new0 (LayoutInfo *, (MAX_LAYOUTS_PER_GROUP - 1));
+
+      group[index] = info;
+
+      info->group = group;
+      info->index = index;
+
+      i++;
+    }
+}
+
+/**
+ * gf_keyboard_manager_apply:
+ * @manager: a #GfKeyboardManager
+ * @id: the xkb_layout + xkb_variant or xkb_layout if a XKB variant isn't
+ *     needed
+ */
+void
+gf_keyboard_manager_apply (GfKeyboardManager *manager,
+                           const gchar       *id)
+{
+  LayoutInfo *info;
+
+  info = (LayoutInfo *) g_hash_table_lookup (manager->layout_infos, id);
+
+  if (info == NULL)
+    return;
+
+  if (manager->current != NULL && manager->current->group == info->group)
+    {
+      if (manager->current->index != info->index)
+        apply_layout_index (manager, info->index);
+    }
+  else
+    {
+      apply_layout_group (manager, info->group);
+      apply_layout_index (manager, info->index);
+    }
+
+  manager->current = info;
+}
+
+/**
+ * gf_keyboard_manager_reapply:
+ * @manager: a #GfKeyboardManager
+ */
+void
+gf_keyboard_manager_reapply (GfKeyboardManager *manager)
+{
+  if (manager->current == NULL)
+    return;
+
+  apply_layout_group (manager, manager->current->group);
+  apply_layout_index (manager, manager->current->index);
+}
+
+/**
+ * gf_keyboard_manager_grab:
+ * @manager: a #GfKeyboardManager
+ * @timestamp: the timestamp of the user interaction (typically a button or
+ *     key press event) which triggered this call
+ */
+void
+gf_keyboard_manager_grab (GfKeyboardManager *manager,
+                          guint32            timestamp)
+{
+  GdkDisplay *display;
+  GdkScreen *screen;
+  GdkDeviceManager *device_manager;
+  GdkWindow *root;
+  GList *devices;
+  GList *l;
+
+  display = gdk_display_get_default ();
+  screen = gdk_display_get_default_screen (display);
+
+  device_manager = gdk_display_get_device_manager (display);
+  root = gdk_screen_get_root_window (screen);
+
+  devices = gdk_device_manager_list_devices (device_manager,
+                                             GDK_DEVICE_TYPE_MASTER);
+
+  for (l = devices; l != NULL; l = g_list_next (l))
+    {
+      GdkDevice *device;
+      GdkGrabStatus status;
+
+      device = GDK_DEVICE (l->data);
+
+      if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+        continue;
+
+      status = gdk_device_grab (device, root, GDK_OWNERSHIP_NONE, TRUE, 0,
+                                NULL, timestamp);
+
+      if (status == GDK_GRAB_SUCCESS)
+        {
+          manager->keyboard = device;
+          break;
+        }
+    }
+
+  g_list_free (devices);
+}
+
+/**
+ * gf_keyboard_manager_ungrab:
+ * @manager: a #GfKeyboardManager
+ * @timestamp: the timestamp of the user interaction (typically a button or
+ *     key press event) which triggered this call
+ */
+void
+gf_keyboard_manager_ungrab (GfKeyboardManager *manager,
+                            guint32            timestamp)
+{
+  if (manager->keyboard == NULL)
+    return;
+
+  gdk_device_ungrab (manager->keyboard, timestamp);
+}
diff --git a/gnome-flashback/libinput-sources/gf-keyboard-manager.h 
b/gnome-flashback/libinput-sources/gf-keyboard-manager.h
new file mode 100644
index 0000000..31fc96c
--- /dev/null
+++ b/gnome-flashback/libinput-sources/gf-keyboard-manager.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GF_KEYBOARD_MANAGER_H
+#define GF_KEYBOARD_MANAGER_H
+
+#include <glib-object.h>
+#include <libgnome-desktop/gnome-xkb-info.h>
+
+G_BEGIN_DECLS
+
+#define GF_TYPE_KEYBOARD_MANAGER gf_keyboard_manager_get_type ()
+G_DECLARE_FINAL_TYPE (GfKeyboardManager, gf_keyboard_manager,
+                      GF, KEYBOARD_MANAGER, GObject)
+
+GfKeyboardManager *gf_keyboard_manager_new              (void);
+
+GnomeXkbInfo      *gf_keyboard_manager_get_xkb_info     (GfKeyboardManager  *manager);
+
+void               gf_keyboard_manager_set_xkb_options  (GfKeyboardManager  *manager,
+                                                         gchar             **options);
+
+void               gf_keyboard_manager_set_user_layouts (GfKeyboardManager  *manager,
+                                                         gchar             **ids);
+
+void               gf_keyboard_manager_apply            (GfKeyboardManager  *manager,
+                                                         const gchar        *id);
+
+void               gf_keyboard_manager_reapply          (GfKeyboardManager  *manager);
+
+void               gf_keyboard_manager_grab             (GfKeyboardManager  *manager,
+                                                         guint32             timestamp);
+
+void               gf_keyboard_manager_ungrab           (GfKeyboardManager  *manager,
+                                                         guint32             timestamp);
+
+G_END_DECLS
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]