static void
parse_rules (GnomeXkbInfo *self)
{
  GnomeXkbInfoPrivate *priv = self->priv;
  GSettings *settings;
  gboolean show_all_sources;
  gchar *file_path;
  GError *error = NULL;

  /* Make sure the translated strings we get from XKEYBOARD_CONFIG() are
   * in UTF-8 and not in the current locale */
  bind_textdomain_codeset ("xkeyboard-config", "UTF-8");

  /* Maps option group ids to XkbOptionGroup structs. Owns the
     XkbOptionGroup structs. */
  priv->option_groups_table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                     NULL, free_option_group);
  /* Maps country strings to a GHashTable which is a set of Layout
     struct pointers into the Layout structs stored in
     layouts_table. */
  priv->layouts_by_country = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                    g_free, (GDestroyNotify) g_hash_table_destroy);
  /* Maps language strings to a GHashTable which is a set of Layout
     struct pointers into the Layout structs stored in
     layouts_table. */
  priv->layouts_by_language = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                     g_free, (GDestroyNotify) g_hash_table_destroy);
  /* Maps layout ids to Layout structs. Owns the Layout structs. */
  priv->layouts_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_layout);

  file_path = get_xml_rules_file_path (".xml");
  parse_rules_file (self, file_path, &error);
  if (error)
    goto cleanup;
  g_free (file_path);

  settings = g_settings_new ("org.gnome.desktop.input-sources");
  show_all_sources = g_settings_get_boolean (settings, "show-all-sources");
  g_object_unref (settings);

  if (!show_all_sources)
    return;

  file_path = get_xml_rules_file_path (".extras.xml");
  parse_rules_file (self, file_path, &error);
  if (error)
    goto cleanup;
  g_free (file_path);

  return;

 cleanup:
  g_warning ("Failed to load XKB rules file %s: %s", file_path, error->message);
  g_clear_pointer (&error, g_error_free);
  g_clear_pointer (&file_path, g_free);
  g_clear_pointer (&priv->option_groups_table, g_hash_table_destroy);
  g_clear_pointer (&priv->layouts_by_country, g_hash_table_destroy);
  g_clear_pointer (&priv->layouts_by_language, g_hash_table_destroy);
  g_clear_pointer (&priv->layouts_table, g_hash_table_destroy);
}
static void
parse_rules (GnomeXkbInfo *self)
{
  GnomeXkbInfoPrivate *priv = self->priv;
  GSettings *settings;
  gboolean show_all_sources;
  gchar *file_path;
  GError *error = NULL;

  /* Maps option group ids to XkbOptionGroup structs. Owns the
     XkbOptionGroup structs. */
  priv->option_groups_table = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                     NULL, free_option_group);
  priv->layouts_by_short_desc = g_hash_table_new (g_str_hash, g_str_equal);
  priv->layouts_by_iso639 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
  /* Maps layout ids to Layout structs. Owns the Layout structs. */
  priv->layouts_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_layout);

  file_path = get_xml_rules_file_path (".xml");
  parse_rules_file (self, file_path, &error);
  if (error)
    goto cleanup;
  g_free (file_path);

  settings = g_settings_new ("org.gnome.desktop.input-sources");
  show_all_sources = g_settings_get_boolean (settings, "show-all-sources");
  g_object_unref (settings);

  if (!show_all_sources)
    return;

  file_path = get_xml_rules_file_path (".extras.xml");
  parse_rules_file (self, file_path, &error);
  if (error)
    goto cleanup;
  g_free (file_path);

  return;

 cleanup:
  g_warning ("Failed to load XKB rules file %s: %s", file_path, error->message);

  if (error != NULL) {
    g_error_free (error);
    error = NULL;
  }

  if (file_path != NULL) {
    g_free (file_path);
    file_path = NULL;
  }

  if (priv->option_groups_table != NULL) {
    g_hash_table_destroy (priv->option_groups_table);
    priv->option_groups_table = NULL;
  }

  if (priv->layouts_by_short_desc != NULL) {
    g_hash_table_destroy (priv->layouts_by_short_desc);
    priv->layouts_by_short_desc = NULL;
  }

  if (priv->layouts_by_iso639 != NULL) {
    g_hash_table_destroy (priv->layouts_by_iso639);
    priv->layouts_by_iso639 = NULL;
  }

  if (priv->layouts_table != NULL) {
    g_hash_table_destroy (priv->layouts_table);
    priv->layouts_table = NULL;
  }
}